From: Tom Lane <tgl@sss.pgh.pa.us>
To: Andres Freund <andres@anarazel.de>
Cc: Hans Buschmann <buschmann@nidsa.net>
Cc: pgsql-hackers@postgresql.org <pgsql-hackers@postgresql.org>
Subject: Re: Assorted improvements in pg_dump
Date: Tue, 26 Oct 2021 18:31:05 -0400
Message-ID: <177444.1635287465@sss.pgh.pa.us> (raw)
In-Reply-To: <20211025213550.2gd35lum5duw7urk@alap3.anarazel.de>
References: <7d7eb6128f40401d81b3b7a898b6b4de@W2012-02.nidsa.loc>
<3780613.1635109855@sss.pgh.pa.us>
<20211025193024.ssesntsq25muk7py@alap3.anarazel.de>
<4167039.1635192154@sss.pgh.pa.us>
<20211025213550.2gd35lum5duw7urk@alap3.anarazel.de>
Andres Freund <andres@anarazel.de> writes:
> I guess we could move the prepared-statement handling into a query execution
> helper. That could then use a hashtable or something similar to check if a
> certain prepared statement already exists. That'd then centrally be extensible
> to deal with multiple connects etc.
That seems like more mechanism than is warranted. I tried it with a
simple array of booleans, and that seems like not too much of a mess;
see revised 0006 attached.
(0001-0005 are the same as before; including them just to satisfy
the cfbot.)
regards, tom lane
Attachments:
[text/x-diff] 0001-fix-component-masking-2.patch (47.1K, ../177444.1635287465@sss.pgh.pa.us/2-0001-fix-component-masking-2.patch)
download | inline diff:diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.cindex e38ff3c030..310f94605c 100644--- a/src/bin/pg_dump/common.c+++ b/src/bin/pg_dump/common.c@@ -581,6 +581,8 @@ AssignDumpId(DumpableObject *dobj)
dobj->namespace = NULL; /* may be set later */
dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
dobj->dump_contains = DUMP_COMPONENT_ALL; /* default assumption */
+ /* All objects have definitions; we may set more components bits later */+ dobj->components = DUMP_COMPONENT_DEFINITION;
dobj->ext_member = false; /* default assumption */
dobj->depends_on_ext = false; /* default assumption */
dobj->dependencies = NULL;
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.cindex e9f68e8986..e5ea2c082d 100644--- a/src/bin/pg_dump/pg_dump.c+++ b/src/bin/pg_dump/pg_dump.c@@ -134,6 +134,14 @@ static const CatalogId nilCatalogId = {0, 0};
static bool have_extra_float_digits = false;
static int extra_float_digits;
+/* sorted table of comments */+static CommentItem *comments = NULL;+static int ncomments = 0;++/* sorted table of security labels */+static SecLabelItem *seclabels = NULL;+static int nseclabels = 0;+
/*
* The default number of rows per INSERT when
* --inserts is specified without --rows-per-insert
@@ -182,14 +190,14 @@ static inline void dumpComment(Archive *fout, const char *type,
int subid, DumpId dumpId);
static int findComments(Archive *fout, Oid classoid, Oid objoid,
CommentItem **items);
-static int collectComments(Archive *fout, CommentItem **items);+static void collectComments(Archive *fout);
static void dumpSecLabel(Archive *fout, const char *type, const char *name,
const char *namespace, const char *owner,
CatalogId catalogId, int subid, DumpId dumpId);
static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
SecLabelItem **items);
-static int collectSecLabels(Archive *fout, SecLabelItem **items);-static void dumpDumpableObject(Archive *fout, const DumpableObject *dobj);+static void collectSecLabels(Archive *fout);+static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo);
static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo);
static void dumpType(Archive *fout, const TypeInfo *tyinfo);
@@ -290,8 +298,9 @@ static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
Oid pg_type_oid,
bool force_array_type,
bool include_multirange_type);
-static void binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,- PQExpBuffer upgrade_buffer, Oid pg_rel_oid);+static void binary_upgrade_set_type_oids_by_rel(Archive *fout,+ PQExpBuffer upgrade_buffer,+ const TableInfo *tbinfo);
static void binary_upgrade_set_pg_class_oids(Archive *fout,
PQExpBuffer upgrade_buffer,
Oid pg_class_oid, bool is_index);
@@ -878,6 +887,14 @@ main(int argc, char **argv)
*/
getDependencies(fout);
+ /*+ * Collect comments and security labels, if wanted.+ */+ if (!dopt.no_comments)+ collectComments(fout);+ if (!dopt.no_security_labels)+ collectSecLabels(fout);+
/* Lastly, create dummy objects to represent the section boundaries */
boundaryObjs = createBoundaryObjects();
@@ -1631,6 +1648,13 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
++ /*+ * Also, make like it has a comment even if it doesn't; this is so+ * that we'll emit a command to drop the comment, if appropriate.+ * (Without this, we'd not call dumpCommentExtended for it.)+ */+ nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
}
else
nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
@@ -2471,7 +2495,7 @@ getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
* Make a dumpable object for the data of this specific table
*
* Note: we make a TableDataInfo if and only if we are going to dump the
- * table data; the "dump" flag in such objects isn't used.+ * table data; the "dump" field in such objects isn't very interesting.
*/
static void
makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
@@ -2531,6 +2555,9 @@ makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
tdinfo->filtercond = NULL; /* might get set later */
addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
+ /* A TableDataInfo contains data, of course */+ tdinfo->dobj.components |= DUMP_COMPONENT_DATA;+
tbinfo->dataObj = tdinfo;
/* Make sure that we'll collect per-column info for this table. */
@@ -3491,11 +3518,15 @@ getBlobs(Archive *fout)
binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
- if (PQgetisnull(res, i, i_lomacl) &&- PQgetisnull(res, i, i_rlomacl) &&- PQgetisnull(res, i, i_initlomacl) &&- PQgetisnull(res, i, i_initrlomacl))- binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;+ /* Blobs have data */+ binfo[i].dobj.components |= DUMP_COMPONENT_DATA;++ /* Mark whether blob has an ACL */+ if (!(PQgetisnull(res, i, i_lomacl) &&+ PQgetisnull(res, i, i_rlomacl) &&+ PQgetisnull(res, i, i_initlomacl) &&+ PQgetisnull(res, i, i_initrlomacl)))+ binfo[i].dobj.components |= DUMP_COMPONENT_ACL;
/*
* In binary-upgrade mode for blobs, we do *not* dump out the blob
@@ -3519,6 +3550,7 @@ getBlobs(Archive *fout)
bdata->catId = nilCatalogId;
AssignDumpId(bdata);
bdata->name = pg_strdup("BLOBS");
+ bdata->components |= DUMP_COMPONENT_DATA;
}
PQclear(res);
@@ -3566,7 +3598,7 @@ dumpBlob(Archive *fout, const BlobInfo *binfo)
binfo->dobj.catId, 0, binfo->dobj.dumpId);
/* Dump ACL if any */
- if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))+ if (binfo->dobj.dump & DUMP_COMPONENT_ACL)
dumpACL(fout, binfo->dobj.dumpId, InvalidDumpId, "LARGE OBJECT",
binfo->dobj.name, NULL,
NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
@@ -3697,6 +3729,8 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
if (tbinfo->rowsec)
{
+ tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;+
/*
* Note: use tableoid 0 so that this object won't be mistaken for
* something that pg_depend entries apply to.
@@ -3766,6 +3800,8 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
continue;
+ tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;+
polinfo[j].dobj.objType = DO_POLICY;
polinfo[j].dobj.catId.tableoid =
atooid(PQgetvalue(res, j, i_tableoid));
@@ -3818,6 +3854,7 @@ dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
const char *cmd;
char *tag;
+ /* Do nothing in data-only dump */
if (dopt->dataOnly)
return;
@@ -3838,7 +3875,7 @@ dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
* explicitly, because it will not match anything in pg_depend (unlike
* the case for other PolicyInfo objects).
*/
- if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)+ if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
ARCHIVE_OPTS(.tag = polinfo->dobj.name,
.namespace = polinfo->dobj.namespace->dobj.name,
@@ -3900,7 +3937,7 @@ dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
- if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)+ if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
ARCHIVE_OPTS(.tag = tag,
.namespace = polinfo->dobj.namespace->dobj.name,
@@ -4045,9 +4082,6 @@ dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
char *qpubname;
bool first = true;
- if (!(pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))- return;-
delq = createPQExpBuffer();
query = createPQExpBuffer();
@@ -4103,13 +4137,14 @@ dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
appendPQExpBufferStr(query, ");\n");
- ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,- ARCHIVE_OPTS(.tag = pubinfo->dobj.name,- .owner = pubinfo->rolname,- .description = "PUBLICATION",- .section = SECTION_POST_DATA,- .createStmt = query->data,- .dropStmt = delq->data));+ if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)+ ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,+ ARCHIVE_OPTS(.tag = pubinfo->dobj.name,+ .owner = pubinfo->rolname,+ .description = "PUBLICATION",+ .section = SECTION_POST_DATA,+ .createStmt = query->data,+ .dropStmt = delq->data));
if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
dumpComment(fout, "PUBLICATION", qpubname,
@@ -4225,9 +4260,6 @@ dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
PQExpBuffer query;
char *tag;
- if (!(pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))- return;-
tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
query = createPQExpBuffer();
@@ -4244,13 +4276,14 @@ dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
* owner field anyway to ensure that the command is run by the correct
* role at restore time.
*/
- ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,- ARCHIVE_OPTS(.tag = tag,- .namespace = tbinfo->dobj.namespace->dobj.name,- .owner = pubinfo->rolname,- .description = "PUBLICATION TABLE",- .section = SECTION_POST_DATA,- .createStmt = query->data));+ if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)+ ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,+ ARCHIVE_OPTS(.tag = tag,+ .namespace = tbinfo->dobj.namespace->dobj.name,+ .owner = pubinfo->rolname,+ .description = "PUBLICATION TABLE",+ .section = SECTION_POST_DATA,+ .createStmt = query->data));
free(tag);
destroyPQExpBuffer(query);
@@ -4420,9 +4453,6 @@ dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
int i;
char two_phase_disabled[] = {LOGICALREP_TWOPHASE_STATE_DISABLED, '\0'};
- if (!(subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))- return;-
delq = createPQExpBuffer();
query = createPQExpBuffer();
@@ -4468,13 +4498,14 @@ dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
appendPQExpBufferStr(query, ");\n");
- ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,- ARCHIVE_OPTS(.tag = subinfo->dobj.name,- .owner = subinfo->rolname,- .description = "SUBSCRIPTION",- .section = SECTION_POST_DATA,- .createStmt = query->data,- .dropStmt = delq->data));+ if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)+ ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,+ ARCHIVE_OPTS(.tag = subinfo->dobj.name,+ .owner = subinfo->rolname,+ .description = "SUBSCRIPTION",+ .section = SECTION_POST_DATA,+ .createStmt = query->data,+ .dropStmt = delq->data));
if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
dumpComment(fout, "SUBSCRIPTION", qsubname,
@@ -4662,30 +4693,15 @@ binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
}
static void
-binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,- PQExpBuffer upgrade_buffer,- Oid pg_rel_oid)+binary_upgrade_set_type_oids_by_rel(Archive *fout,+ PQExpBuffer upgrade_buffer,+ const TableInfo *tbinfo)
{
- PQExpBuffer upgrade_query = createPQExpBuffer();- PGresult *upgrade_res;- Oid pg_type_oid;-- appendPQExpBuffer(upgrade_query,- "SELECT c.reltype AS crel "- "FROM pg_catalog.pg_class c "- "WHERE c.oid = '%u'::pg_catalog.oid;",- pg_rel_oid);-- upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);-- pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));+ Oid pg_type_oid = tbinfo->reltype;
if (OidIsValid(pg_type_oid))
binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
pg_type_oid, false, false);
-- PQclear(upgrade_res);- destroyPQExpBuffer(upgrade_query);
}
static void
@@ -4940,18 +4956,12 @@ getNamespaces(Archive *fout, int *numNamespaces)
/* Decide whether to dump this namespace */
selectDumpableNamespace(&nsinfo[i], fout);
- /*- * Do not try to dump ACL if the ACL is empty or the default.- *- * This is useful because, for some schemas/objects, the only- * component we are going to try and dump is the ACL and if we can- * remove that then 'dump' goes to zero/false and we don't consider- * this object for dumping at all later on.- */- if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&- PQgetisnull(res, i, i_initnspacl) &&- PQgetisnull(res, i, i_initrnspacl))- nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;+ /* Mark whether namespace has an ACL */+ if (!(PQgetisnull(res, i, i_nspacl) &&+ PQgetisnull(res, i, i_rnspacl) &&+ PQgetisnull(res, i, i_initnspacl) &&+ PQgetisnull(res, i, i_initrnspacl)))+ nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
if (strlen(nsinfo[i].rolname) == 0)
pg_log_warning("owner of schema \"%s\" appears to be invalid",
@@ -5260,11 +5270,12 @@ getTypes(Archive *fout, int *numTypes)
/* Decide whether we want to dump it */
selectDumpableType(&tyinfo[i], fout);
- /* Do not try to dump ACL if no ACL exists. */- if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&- PQgetisnull(res, i, i_inittypacl) &&- PQgetisnull(res, i, i_initrtypacl))- tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;+ /* Mark whether type has an ACL */+ if (!(PQgetisnull(res, i, i_typacl) &&+ PQgetisnull(res, i, i_rtypacl) &&+ PQgetisnull(res, i, i_inittypacl) &&+ PQgetisnull(res, i, i_initrtypacl)))+ tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
/*
* If it's a domain, fetch info about its constraints, if any
@@ -5387,9 +5398,6 @@ getOperators(Archive *fout, int *numOprs)
/* Decide whether we want to dump it */
selectDumpableObject(&(oprinfo[i].dobj), fout);
- /* Operators do not currently have ACLs. */- oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;-
if (strlen(oprinfo[i].rolname) == 0)
pg_log_warning("owner of operator \"%s\" appears to be invalid",
oprinfo[i].dobj.name);
@@ -5469,9 +5477,6 @@ getCollations(Archive *fout, int *numCollations)
/* Decide whether we want to dump it */
selectDumpableObject(&(collinfo[i].dobj), fout);
-- /* Collations do not currently have ACLs. */- collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
}
PQclear(res);
@@ -5541,9 +5546,6 @@ getConversions(Archive *fout, int *numConversions)
/* Decide whether we want to dump it */
selectDumpableObject(&(convinfo[i].dobj), fout);
-- /* Conversions do not currently have ACLs. */- convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
}
PQclear(res);
@@ -5614,9 +5616,6 @@ getAccessMethods(Archive *fout, int *numAccessMethods)
/* Decide whether we want to dump it */
selectDumpableAccessMethod(&(aminfo[i]), fout);
-- /* Access methods do not currently have ACLs. */- aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
}
PQclear(res);
@@ -5686,9 +5685,6 @@ getOpclasses(Archive *fout, int *numOpclasses)
/* Decide whether we want to dump it */
selectDumpableObject(&(opcinfo[i].dobj), fout);
- /* Op Classes do not currently have ACLs. */- opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;-
if (strlen(opcinfo[i].rolname) == 0)
pg_log_warning("owner of operator class \"%s\" appears to be invalid",
opcinfo[i].dobj.name);
@@ -5769,9 +5765,6 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
/* Decide whether we want to dump it */
selectDumpableObject(&(opfinfo[i].dobj), fout);
- /* Extensions do not currently have ACLs. */- opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;-
if (strlen(opfinfo[i].rolname) == 0)
pg_log_warning("owner of operator family \"%s\" appears to be invalid",
opfinfo[i].dobj.name);
@@ -5963,11 +5956,12 @@ getAggregates(Archive *fout, int *numAggs)
/* Decide whether we want to dump it */
selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
- /* Do not try to dump ACL if no ACL exists. */- if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&- PQgetisnull(res, i, i_initaggacl) &&- PQgetisnull(res, i, i_initraggacl))- agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;+ /* Mark whether aggregate has an ACL */+ if (!(PQgetisnull(res, i, i_aggacl) &&+ PQgetisnull(res, i, i_raggacl) &&+ PQgetisnull(res, i, i_initaggacl) &&+ PQgetisnull(res, i, i_initraggacl)))+ agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
}
PQclear(res);
@@ -6193,11 +6187,12 @@ getFuncs(Archive *fout, int *numFuncs)
/* Decide whether we want to dump it */
selectDumpableObject(&(finfo[i].dobj), fout);
- /* Do not try to dump ACL if no ACL exists. */- if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl) &&- PQgetisnull(res, i, i_initproacl) &&- PQgetisnull(res, i, i_initrproacl))- finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;+ /* Mark whether function has an ACL */+ if (!(PQgetisnull(res, i, i_proacl) &&+ PQgetisnull(res, i, i_rproacl) &&+ PQgetisnull(res, i, i_initproacl) &&+ PQgetisnull(res, i, i_initrproacl)))+ finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
if (strlen(finfo[i].rolname) == 0)
pg_log_warning("owner of function \"%s\" appears to be invalid",
@@ -6232,6 +6227,7 @@ getTables(Archive *fout, int *numTables)
int i_relname;
int i_relnamespace;
int i_relkind;
+ int i_reltype;
int i_rolname;
int i_relchecks;
int i_relhasindex;
@@ -6282,7 +6278,7 @@ getTables(Archive *fout, int *numTables)
appendPQExpBuffer(query,
"SELECT c.tableoid, c.oid, c.relname, "
- "c.relnamespace, c.relkind, "+ "c.relnamespace, c.relkind, c.reltype, "
"(%s c.relowner) AS rolname, "
"c.relchecks, "
"c.relhasindex, c.relhasrules, c.relpages, "
@@ -6558,6 +6554,7 @@ getTables(Archive *fout, int *numTables)
i_relname = PQfnumber(res, "relname");
i_relnamespace = PQfnumber(res, "relnamespace");
i_relkind = PQfnumber(res, "relkind");
+ i_reltype = PQfnumber(res, "reltype");
i_rolname = PQfnumber(res, "rolname");
i_relchecks = PQfnumber(res, "relchecks");
i_relhasindex = PQfnumber(res, "relhasindex");
@@ -6619,6 +6616,7 @@ getTables(Archive *fout, int *numTables)
tblinfo[i].dobj.namespace =
findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
+ tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
@@ -6681,11 +6679,30 @@ getTables(Archive *fout, int *numTables)
else
selectDumpableTable(&tblinfo[i], fout);
- tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;+ /*+ * Now, consider the table "interesting" if we need to dump its+ * definition or its data. Later on, we'll skip a lot of data+ * collection for uninteresting tables.+ *+ * Note: the "interesting" flag will also be set by flagInhTables for+ * parents of interesting tables, so that we collect necessary+ * inheritance info even when the parents are not themselves being+ * dumped. This is the main reason why we need an "interesting" flag+ * that's separate from the components-to-dump bitmask.+ */+ tblinfo[i].interesting = (tblinfo[i].dobj.dump &+ (DUMP_COMPONENT_DEFINITION |+ DUMP_COMPONENT_DATA)) != 0;+
tblinfo[i].dummy_view = false; /* might get set during sort */
tblinfo[i].postponed_def = false; /* might get set during sort */
+ /* Tables have data */+ tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;+
/*
+ * Mark whether table has an ACL.+ *
* If the table-level and all column-level ACLs for this table are
* unchanged, then we don't need to worry about including the ACLs for
* this table. If any column-level ACLs have been changed, the
@@ -6694,11 +6711,12 @@ getTables(Archive *fout, int *numTables)
* This can result in a significant performance improvement in cases
* where we are only looking to dump out the ACL (eg: pg_catalog).
*/
- if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&- PQgetisnull(res, i, i_initrelacl) &&- PQgetisnull(res, i, i_initrrelacl) &&- strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)- tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;+ if (!(PQgetisnull(res, i, i_relacl) &&+ PQgetisnull(res, i, i_rrelacl) &&+ PQgetisnull(res, i, i_initrelacl) &&+ PQgetisnull(res, i, i_initrrelacl) &&+ strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0))+ tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
/*
* Read-lock target tables to make sure they aren't DROPPED or altered
@@ -6715,10 +6733,9 @@ getTables(Archive *fout, int *numTables)
* We only need to lock the table for certain components; see
* pg_dump.h
*/
- if (tblinfo[i].dobj.dump &&+ if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
(tblinfo[i].relkind == RELKIND_RELATION ||
- tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE) &&- (tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))+ tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
{
resetPQExpBuffer(query);
appendPQExpBuffer(query,
@@ -6900,13 +6917,9 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
continue;
/*
- * Ignore indexes of tables whose definitions are not to be dumped.- *- * We also need indexes on partitioned tables which have partitions to- * be dumped, in order to dump the indexes on the partitions.+ * We can ignore indexes of uninteresting tables.
*/
- if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION) &&- !tbinfo->interesting)+ if (!tbinfo->interesting)
continue;
pg_log_info("reading indexes for table \"%s.%s\"",
@@ -7276,9 +7289,6 @@ getExtendedStatistics(Archive *fout)
/* Decide whether we want to dump it */
selectDumpableObject(&(statsextinfo[i].dobj), fout);
-- /* Stats objects do not currently have ACLs. */- statsextinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
}
PQclear(res);
@@ -7968,9 +7978,6 @@ getEventTriggers(Archive *fout, int *numEventTriggers)
/* Decide whether we want to dump it */
selectDumpableObject(&(evtinfo[i].dobj), fout);
-- /* Event Triggers do not currently have ACLs. */- evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
}
PQclear(res);
@@ -8147,11 +8154,12 @@ getProcLangs(Archive *fout, int *numProcLangs)
/* Decide whether we want to dump it */
selectDumpableProcLang(&(planginfo[i]), fout);
- /* Do not try to dump ACL if no ACL exists. */- if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl) &&- PQgetisnull(res, i, i_initlanacl) &&- PQgetisnull(res, i, i_initrlanacl))- planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;+ /* Mark whether language has an ACL */+ if (!(PQgetisnull(res, i, i_lanacl) &&+ PQgetisnull(res, i, i_rlanacl) &&+ PQgetisnull(res, i, i_initlanacl) &&+ PQgetisnull(res, i, i_initrlanacl)))+ planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
}
PQclear(res);
@@ -8261,9 +8269,6 @@ getCasts(Archive *fout, int *numCasts)
/* Decide whether we want to dump it */
selectDumpableCast(&(castinfo[i]), fout);
-- /* Casts do not currently have ACLs. */- castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
}
PQclear(res);
@@ -8960,9 +8965,6 @@ getTSParsers(Archive *fout, int *numTSParsers)
/* Decide whether we want to dump it */
selectDumpableObject(&(prsinfo[i].dobj), fout);
-- /* Text Search Parsers do not currently have ACLs. */- prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
}
PQclear(res);
@@ -9043,9 +9045,6 @@ getTSDictionaries(Archive *fout, int *numTSDicts)
/* Decide whether we want to dump it */
selectDumpableObject(&(dictinfo[i].dobj), fout);
-- /* Text Search Dictionaries do not currently have ACLs. */- dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
}
PQclear(res);
@@ -9118,9 +9117,6 @@ getTSTemplates(Archive *fout, int *numTSTemplates)
/* Decide whether we want to dump it */
selectDumpableObject(&(tmplinfo[i].dobj), fout);
-- /* Text Search Templates do not currently have ACLs. */- tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
}
PQclear(res);
@@ -9194,9 +9190,6 @@ getTSConfigurations(Archive *fout, int *numTSConfigs)
/* Decide whether we want to dump it */
selectDumpableObject(&(cfginfo[i].dobj), fout);
-- /* Text Search Configurations do not currently have ACLs. */- cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
}
PQclear(res);
@@ -9358,11 +9351,12 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
/* Decide whether we want to dump it */
selectDumpableObject(&(fdwinfo[i].dobj), fout);
- /* Do not try to dump ACL if no ACL exists. */- if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl) &&- PQgetisnull(res, i, i_initfdwacl) &&- PQgetisnull(res, i, i_initrfdwacl))- fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;+ /* Mark whether FDW has an ACL */+ if (!(PQgetisnull(res, i, i_fdwacl) &&+ PQgetisnull(res, i, i_rfdwacl) &&+ PQgetisnull(res, i, i_initfdwacl) &&+ PQgetisnull(res, i, i_initrfdwacl)))+ fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
}
PQclear(res);
@@ -9508,11 +9502,15 @@ getForeignServers(Archive *fout, int *numForeignServers)
/* Decide whether we want to dump it */
selectDumpableObject(&(srvinfo[i].dobj), fout);
- /* Do not try to dump ACL if no ACL exists. */- if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl) &&- PQgetisnull(res, i, i_initsrvacl) &&- PQgetisnull(res, i, i_initrsrvacl))- srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;+ /* Servers have user mappings */+ srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;++ /* Mark whether server has an ACL */+ if (!(PQgetisnull(res, i, i_srvacl) &&+ PQgetisnull(res, i, i_rsrvacl) &&+ PQgetisnull(res, i, i_initsrvacl) &&+ PQgetisnull(res, i, i_initrsrvacl)))+ srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
}
PQclear(res);
@@ -9664,6 +9662,9 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)
daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));
daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));
+ /* Default ACLs are ACLs, of course */+ daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;+
/* Decide whether we want to dump it */
selectDumpableDefaultACL(&(daclinfo[i]), dopt);
}
@@ -9917,19 +9918,11 @@ static int
findComments(Archive *fout, Oid classoid, Oid objoid,
CommentItem **items)
{
- /* static storage for table of comments */- static CommentItem *comments = NULL;- static int ncomments = -1;-
CommentItem *middle = NULL;
CommentItem *low;
CommentItem *high;
int nmatch;
- /* Get comments if we didn't already */- if (ncomments < 0)- ncomments = collectComments(fout, &comments);-
/*
* Do binary search to find some item matching the object.
*/
@@ -9990,15 +9983,17 @@ findComments(Archive *fout, Oid classoid, Oid objoid,
/*
* collectComments --
*
- * Construct a table of all comments available for database objects.+ * Construct a table of all comments available for database objects;+ * also set the has-comment component flag for each relevant object.+ *
* We used to do per-object queries for the comments, but it's much faster
* to pull them all over at once, and on most databases the memory cost
* isn't high.
*
* The table is sorted by classoid/objid/objsubid for speed in lookup.
*/
-static int-collectComments(Archive *fout, CommentItem **items)+static void+collectComments(Archive *fout)
{
PGresult *res;
PQExpBuffer query;
@@ -10008,7 +10003,7 @@ collectComments(Archive *fout, CommentItem **items)
int i_objsubid;
int ntups;
int i;
- CommentItem *comments;+ DumpableObject *dobj;
query = createPQExpBuffer();
@@ -10028,20 +10023,52 @@ collectComments(Archive *fout, CommentItem **items)
ntups = PQntuples(res);
comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
+ ncomments = 0;+ dobj = NULL;
for (i = 0; i < ntups; i++)
{
- comments[i].descr = PQgetvalue(res, i, i_description);- comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));- comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));- comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));+ CatalogId objId;+ int subid;++ objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));+ objId.oid = atooid(PQgetvalue(res, i, i_objoid));+ subid = atoi(PQgetvalue(res, i, i_objsubid));++ /* We needn't remember comments that don't match any dumpable object */+ if (dobj == NULL ||+ dobj->catId.tableoid != objId.tableoid ||+ dobj->catId.oid != objId.oid)+ dobj = findObjectByCatalogId(objId);+ if (dobj == NULL)+ continue;++ /*+ * Comments on columns of composite types are linked to the type's+ * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag+ * in the type's own DumpableObject.+ */+ if (subid != 0 && dobj->objType == DO_TABLE &&+ ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)+ {+ TypeInfo *cTypeInfo;++ cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);+ if (cTypeInfo)+ cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;+ }+ else+ dobj->components |= DUMP_COMPONENT_COMMENT;++ comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));+ comments[ncomments].classoid = objId.tableoid;+ comments[ncomments].objoid = objId.oid;+ comments[ncomments].objsubid = subid;+ ncomments++;
}
- /* Do NOT free the PGresult since we are keeping pointers into it */+ PQclear(res);
destroyPQExpBuffer(query);
-- *items = comments;- return ntups;
}
/*
@@ -10051,8 +10078,19 @@ collectComments(Archive *fout, CommentItem **items)
* ArchiveEntries (TOC objects) for each object to be dumped.
*/
static void
-dumpDumpableObject(Archive *fout, const DumpableObject *dobj)+dumpDumpableObject(Archive *fout, DumpableObject *dobj)
{
+ /*+ * Clear any dump-request bits for components that don't exist for this+ * object. (This makes it safe to initially use DUMP_COMPONENT_ALL as the+ * request for every kind of object.)+ */+ dobj->dump &= dobj->components;++ /* Now, short-circuit if there's nothing to be done here. */+ if (dobj->dump == 0)+ return;+
switch (dobj->objType)
{
case DO_NAMESPACE:
@@ -10227,8 +10265,8 @@ dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
PQExpBuffer delq;
char *qnspname;
- /* Skip if not to be dumped */- if (!nspinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
q = createPQExpBuffer();
@@ -10307,8 +10345,8 @@ dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
PQExpBuffer delq;
char *qextname;
- /* Skip if not to be dumped */- if (!extinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
q = createPQExpBuffer();
@@ -10432,8 +10470,8 @@ dumpType(Archive *fout, const TypeInfo *tyinfo)
{
DumpOptions *dopt = fout->dopt;
- /* Skip if not to be dumped */- if (!tyinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
/* Dump out in proper style */
@@ -11571,8 +11609,8 @@ dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
DumpOptions *dopt = fout->dopt;
PQExpBuffer q;
- /* Skip if not to be dumped */- if (!stinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
q = createPQExpBuffer();
@@ -11623,8 +11661,8 @@ dumpProcLang(Archive *fout, const ProcLangInfo *plang)
FuncInfo *inlineInfo = NULL;
FuncInfo *validatorInfo = NULL;
- /* Skip if not to be dumped */- if (!plang->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
/*
@@ -11911,8 +11949,8 @@ dumpFunc(Archive *fout, const FuncInfo *finfo)
const char *keyword;
int i;
- /* Skip if not to be dumped */- if (!finfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
query = createPQExpBuffer();
@@ -12405,8 +12443,8 @@ dumpCast(Archive *fout, const CastInfo *cast)
const char *sourceType;
const char *targetType;
- /* Skip if not to be dumped */- if (!cast->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
/* Cannot dump if we don't have the cast function's info */
@@ -12511,8 +12549,8 @@ dumpTransform(Archive *fout, const TransformInfo *transform)
char *lanname;
const char *transformType;
- /* Skip if not to be dumped */- if (!transform->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
/* Cannot dump if we don't have the transform functions' info */
@@ -12660,8 +12698,8 @@ dumpOpr(Archive *fout, const OprInfo *oprinfo)
char *oprregproc;
char *oprref;
- /* Skip if not to be dumped */- if (!oprinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
/*
@@ -12953,8 +12991,8 @@ dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
PQExpBuffer delq;
char *qamname;
- /* Skip if not to be dumped */- if (!aminfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
q = createPQExpBuffer();
@@ -13058,8 +13096,8 @@ dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
bool needComma;
int i;
- /* Skip if not to be dumped */- if (!opcinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
query = createPQExpBuffer();
@@ -13420,8 +13458,8 @@ dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
bool needComma;
int i;
- /* Skip if not to be dumped */- if (!opfinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
query = createPQExpBuffer();
@@ -13665,8 +13703,8 @@ dumpCollation(Archive *fout, const CollInfo *collinfo)
const char *collcollate;
const char *collctype;
- /* Skip if not to be dumped */- if (!collinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
query = createPQExpBuffer();
@@ -13817,8 +13855,8 @@ dumpConversion(Archive *fout, const ConvInfo *convinfo)
const char *conproc;
bool condefault;
- /* Skip if not to be dumped */- if (!convinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
query = createPQExpBuffer();
@@ -13965,8 +14003,8 @@ dumpAgg(Archive *fout, const AggInfo *agginfo)
const char *proparallel;
char defaultfinalmodify;
- /* Skip if not to be dumped */- if (!agginfo->aggfn.dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
query = createPQExpBuffer();
@@ -14299,8 +14337,8 @@ dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
PQExpBuffer delq;
char *qprsname;
- /* Skip if not to be dumped */- if (!prsinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
q = createPQExpBuffer();
@@ -14367,8 +14405,8 @@ dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
char *nspname;
char *tmplname;
- /* Skip if not to be dumped */- if (!dictinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
q = createPQExpBuffer();
@@ -14443,8 +14481,8 @@ dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
PQExpBuffer delq;
char *qtmplname;
- /* Skip if not to be dumped */- if (!tmplinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
q = createPQExpBuffer();
@@ -14509,8 +14547,8 @@ dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
int i_tokenname;
int i_dictname;
- /* Skip if not to be dumped */- if (!cfginfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
q = createPQExpBuffer();
@@ -14621,8 +14659,8 @@ dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
PQExpBuffer delq;
char *qfdwname;
- /* Skip if not to be dumped */- if (!fdwinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
q = createPQExpBuffer();
@@ -14696,8 +14734,8 @@ dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
char *qsrvname;
char *fdwname;
- /* Skip if not to be dumped */- if (!srvinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
q = createPQExpBuffer();
@@ -14889,8 +14927,8 @@ dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
PQExpBuffer tag;
const char *type;
- /* Skip if not to be dumped */- if (!daclinfo->dobj.dump || dopt->dataOnly || dopt->aclsSkip)+ /* Do nothing in data-only dump, or if we're skipping ACLs */+ if (dopt->dataOnly || dopt->aclsSkip)
return;
q = createPQExpBuffer();
@@ -15245,20 +15283,12 @@ dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypenam
static int
findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
{
- /* static storage for table of security labels */- static SecLabelItem *labels = NULL;- static int nlabels = -1;-
SecLabelItem *middle = NULL;
SecLabelItem *low;
SecLabelItem *high;
int nmatch;
- /* Get security labels if we didn't already */- if (nlabels < 0)- nlabels = collectSecLabels(fout, &labels);-- if (nlabels <= 0) /* no labels, so no match is possible */+ if (nseclabels <= 0) /* no labels, so no match is possible */
{
*items = NULL;
return 0;
@@ -15267,8 +15297,8 @@ findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
/*
* Do binary search to find some item matching the object.
*/
- low = &labels[0];- high = &labels[nlabels - 1];+ low = &seclabels[0];+ high = &seclabels[nseclabels - 1];
while (low <= high)
{
middle = low + (high - low) / 2;
@@ -15324,13 +15354,13 @@ findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
/*
* collectSecLabels
*
- * Construct a table of all security labels available for database objects.- * It's much faster to pull them all at once.+ * Construct a table of all security labels available for database objects;+ * also set the has-seclabel component flag for each relevant object.
*
* The table is sorted by classoid/objid/objsubid for speed in lookup.
*/
-static int-collectSecLabels(Archive *fout, SecLabelItem **items)+static void+collectSecLabels(Archive *fout)
{
PGresult *res;
PQExpBuffer query;
@@ -15341,7 +15371,7 @@ collectSecLabels(Archive *fout, SecLabelItem **items)
int i_objsubid;
int ntups;
int i;
- SecLabelItem *labels;+ DumpableObject *dobj;
query = createPQExpBuffer();
@@ -15361,22 +15391,54 @@ collectSecLabels(Archive *fout, SecLabelItem **items)
ntups = PQntuples(res);
- labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));+ seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));+ nseclabels = 0;+ dobj = NULL;
for (i = 0; i < ntups; i++)
{
- labels[i].label = PQgetvalue(res, i, i_label);- labels[i].provider = PQgetvalue(res, i, i_provider);- labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));- labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));- labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));+ CatalogId objId;+ int subid;++ objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));+ objId.oid = atooid(PQgetvalue(res, i, i_objoid));+ subid = atoi(PQgetvalue(res, i, i_objsubid));++ /* We needn't remember labels that don't match any dumpable object */+ if (dobj == NULL ||+ dobj->catId.tableoid != objId.tableoid ||+ dobj->catId.oid != objId.oid)+ dobj = findObjectByCatalogId(objId);+ if (dobj == NULL)+ continue;++ /*+ * Labels on columns of composite types are linked to the type's+ * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag+ * in the type's own DumpableObject.+ */+ if (subid != 0 && dobj->objType == DO_TABLE &&+ ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)+ {+ TypeInfo *cTypeInfo;++ cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);+ if (cTypeInfo)+ cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;+ }+ else+ dobj->components |= DUMP_COMPONENT_SECLABEL;++ seclabels[nseclabels].label = pg_strdup(PQgetvalue(res, i, i_label));+ seclabels[nseclabels].provider = pg_strdup(PQgetvalue(res, i, i_provider));+ seclabels[nseclabels].classoid = objId.tableoid;+ seclabels[nseclabels].objoid = objId.oid;+ seclabels[nseclabels].objsubid = subid;+ nseclabels++;
}
- /* Do NOT free the PGresult since we are keeping pointers into it */+ PQclear(res);
destroyPQExpBuffer(query);
-- *items = labels;- return ntups;
}
/*
@@ -15390,17 +15452,17 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
DumpId tableAclDumpId = InvalidDumpId;
char *namecopy;
- /*- * noop if we are not dumping anything about this table, or if we are- * doing a data-only dump- */- if (!tbinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
- if (tbinfo->relkind == RELKIND_SEQUENCE)- dumpSequence(fout, tbinfo);- else- dumpTableSchema(fout, tbinfo);+ if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)+ {+ if (tbinfo->relkind == RELKIND_SEQUENCE)+ dumpSequence(fout, tbinfo);+ else+ dumpTableSchema(fout, tbinfo);+ }
/* Handle the ACL here */
namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
@@ -15420,7 +15482,8 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
/*
* Handle column ACLs, if any. Note: we pull these with a separate query
* rather than trying to fetch them during getTableAttrs, so that we won't
- * miss ACLs on system columns.+ * miss ACLs on system columns. Doing it this way also allows us to dump+ * ACLs for catalogs that we didn't mark "interesting" back in getTables.
*/
if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
{
@@ -15639,8 +15702,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
qrelname);
if (dopt->binary_upgrade)
- binary_upgrade_set_type_oids_by_rel_oid(fout, q,- tbinfo->dobj.catId.oid);+ binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
/* Is it a table or a view? */
if (tbinfo->relkind == RELKIND_VIEW)
@@ -16381,6 +16443,7 @@ dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
DumpOptions *dopt = fout->dopt;
PQExpBuffer q;
+ /* Do nothing in data-only dump */
if (dopt->dataOnly)
return;
@@ -16431,8 +16494,8 @@ dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
char *tag;
char *foreign;
- /* Skip if table definition not to be dumped */- if (!tbinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
/* Skip if not "separate"; it was dumped in the table's definition */
@@ -16520,6 +16583,7 @@ dumpIndex(Archive *fout, const IndxInfo *indxinfo)
char *qindxname;
char *qqindxname;
+ /* Do nothing in data-only dump */
if (dopt->dataOnly)
return;
@@ -16654,6 +16718,7 @@ dumpIndex(Archive *fout, const IndxInfo *indxinfo)
static void
dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
{
+ /* Do nothing in data-only dump */
if (fout->dopt->dataOnly)
return;
@@ -16700,8 +16765,8 @@ dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
PGresult *res;
char *stxdef;
- /* Skip if not to be dumped */- if (!statsextinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
q = createPQExpBuffer();
@@ -16777,8 +16842,8 @@ dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
char *tag = NULL;
char *foreign;
- /* Skip if not to be dumped */- if (!coninfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
q = createPQExpBuffer();
@@ -17430,10 +17495,7 @@ dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
int findx;
char *tag;
- /*- * we needn't check dobj.dump because TriggerInfo wouldn't have been- * created in the first place for non-dumpable triggers- */+ /* Do nothing in data-only dump */
if (dopt->dataOnly)
return;
@@ -17669,8 +17731,8 @@ dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
PQExpBuffer delqry;
char *qevtname;
- /* Skip if not to be dumped */- if (!evtinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
query = createPQExpBuffer();
@@ -17760,8 +17822,8 @@ dumpRule(Archive *fout, const RuleInfo *rinfo)
PGresult *res;
char *tag;
- /* Skip if not to be dumped */- if (!rinfo->dobj.dump || dopt->dataOnly)+ /* Do nothing in data-only dump */+ if (dopt->dataOnly)
return;
/*
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.hindex cc55e598ec..3db73f710c 100644--- a/src/bin/pg_dump/pg_dump.h+++ b/src/bin/pg_dump/pg_dump.h@@ -84,8 +84,13 @@ typedef enum
DO_SUBSCRIPTION
} DumpableObjectType;
-/* component types of an object which can be selected for dumping */-typedef uint32 DumpComponents; /* a bitmask of dump object components */+/*+ * DumpComponents is a bitmask of the potentially dumpable components of+ * a database object: its core definition, plus optional attributes such+ * as ACL, comments, etc. The NONE and ALL symbols are convenient+ * shorthands.+ */+typedef uint32 DumpComponents;
#define DUMP_COMPONENT_NONE (0)
#define DUMP_COMPONENT_DEFINITION (1 << 0)
#define DUMP_COMPONENT_DATA (1 << 1)
@@ -130,8 +135,9 @@ typedef struct _dumpableObject
DumpId dumpId; /* assigned by AssignDumpId() */
char *name; /* object name (should never be NULL) */
struct _namespaceInfo *namespace; /* containing namespace, or NULL */
- DumpComponents dump; /* bitmask of components to dump */+ DumpComponents dump; /* bitmask of components requested to dump */
DumpComponents dump_contains; /* as above, but for contained objects */
+ DumpComponents components; /* bitmask of components available to dump */
bool ext_member; /* true if object is member of extension */
bool depends_on_ext; /* true if object depends on an extension */
DumpId *dependencies; /* dumpIds of objects this one depends on */
@@ -288,6 +294,7 @@ typedef struct _tableInfo
uint32 toast_frozenxid; /* toast table's relfrozenxid, if any */
uint32 toast_minmxid; /* toast table's relminmxid */
int ncheck; /* # of CHECK expressions */
+ Oid reltype; /* OID of table's composite type, if any */
char *reloftype; /* underlying type for typed table */
Oid foreign_server; /* foreign server oid, if applicable */
/* these two are set only if table is a sequence owned by a column: */
[text/x-diff] 0002-rethink-ACL-handling-2.patch (121.1K, ../177444.1635287465@sss.pgh.pa.us/3-0002-rethink-ACL-handling-2.patch)
download | inline diff:diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.cindex ea67e52a3f..6e216313c6 100644--- a/src/bin/pg_dump/dumputils.c+++ b/src/bin/pg_dump/dumputils.c@@ -24,7 +24,7 @@ static bool parseAclItem(const char *item, const char *type,
const char *name, const char *subname, int remoteVersion,
PQExpBuffer grantee, PQExpBuffer grantor,
PQExpBuffer privs, PQExpBuffer privswgo);
-static char *copyAclUserName(PQExpBuffer output, char *input);+static char *dequoteAclUserName(PQExpBuffer output, char *input);
static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
const char *subname);
@@ -39,7 +39,8 @@ static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
* TABLE, SEQUENCE, FUNCTION, PROCEDURE, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
* FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT)
* acls: the ACL string fetched from the database
- * racls: the ACL string of any initial-but-now-revoked privileges+ * baseacls: the initial ACL string for this object; can be+ * NULL or empty string to indicate "not available from server"
* owner: username of object owner (will be passed through fmtId); can be
* NULL or empty string to indicate "no owner known"
* prefix: string to prefix to each generated command; typically empty
@@ -48,6 +49,12 @@ static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
* Returns true if okay, false if could not parse the acl string.
* The resulting commands (if any) are appended to the contents of 'sql'.
*
+ * baseacls is typically the result of acldefault() for the object's type+ * and owner. However, if there is a pg_init_privs entry for the object,+ * it should instead be the initprivs ACLs. When acls is itself a+ * pg_init_privs entry, baseacls is what to dump that relative to; then+ * it can be either an acldefault() value or an empty ACL "{}".+ *
* Note: when processing a default ACL, prefix is "ALTER DEFAULT PRIVILEGES "
* or something similar, and name is an empty string.
*
@@ -56,15 +63,19 @@ static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
*/
bool
buildACLCommands(const char *name, const char *subname, const char *nspname,
- const char *type, const char *acls, const char *racls,+ const char *type, const char *acls, const char *baseacls,
const char *owner, const char *prefix, int remoteVersion,
PQExpBuffer sql)
{
bool ok = true;
char **aclitems = NULL;
- char **raclitems = NULL;+ char **baseitems = NULL;+ char **grantitems = NULL;+ char **revokeitems = NULL;
int naclitems = 0;
- int nraclitems = 0;+ int nbaseitems = 0;+ int ngrantitems = 0;+ int nrevokeitems = 0;
int i;
PQExpBuffer grantee,
grantor,
@@ -72,37 +83,88 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,
privswgo;
PQExpBuffer firstsql,
secondsql;
- bool found_owner_privs = false;- if (strlen(acls) == 0 && strlen(racls) == 0)+ /*+ * If the acl was NULL (initial default state), we need do nothing. Note+ * that this is distinguishable from all-privileges-revoked, which will+ * look like an empty array ("{}").+ */+ if (acls == NULL || *acls == '\0')
return true; /* object has default permissions */
/* treat empty-string owner same as NULL */
if (owner && *owner == '\0')
owner = NULL;
- if (strlen(acls) != 0)+ /* Parse the acls array */+ if (!parsePGArray(acls, &aclitems, &naclitems))+ {+ if (aclitems)+ free(aclitems);+ return false;+ }++ /* Parse the baseacls, if provided */+ if (baseacls && *baseacls != '\0')
{
- if (!parsePGArray(acls, &aclitems, &naclitems))+ if (!parsePGArray(baseacls, &baseitems, &nbaseitems))
{
if (aclitems)
free(aclitems);
+ if (baseitems)+ free(baseitems);
return false;
}
}
- if (strlen(racls) != 0)+ /*+ * Compare the actual ACL with the base ACL, extracting the privileges+ * that need to be granted (i.e., are in the actual ACL but not the base+ * ACL) and the ones that need to be revoked (the reverse). We use plain+ * string comparisons to check for matches. In principle that could be+ * fooled by extraneous issues such as whitespace, but since all these+ * strings are the work of aclitemout(), it should be OK in practice.+ * Besides, a false mismatch will just cause the output to be a little+ * more verbose than it really needed to be.+ *+ * (If we weren't given a base ACL, this stanza winds up with all the+ * ACL's items in grantitems and nothing in revokeitems. It's not worth+ * special-casing that.)+ */+ grantitems = (char **) pg_malloc(naclitems * sizeof(char *));+ for (i = 0; i < naclitems; i++)
{
- if (!parsePGArray(racls, &raclitems, &nraclitems))+ bool found = false;++ for (int j = 0; j < nbaseitems; j++)
{
- if (aclitems)- free(aclitems);- if (raclitems)- free(raclitems);- return false;+ if (strcmp(aclitems[i], baseitems[j]) == 0)+ {+ found = true;+ break;+ }
}
+ if (!found)+ grantitems[ngrantitems++] = aclitems[i];
}
+ revokeitems = (char **) pg_malloc(nbaseitems * sizeof(char *));+ for (i = 0; i < nbaseitems; i++)+ {+ bool found = false;+ for (int j = 0; j < naclitems; j++)+ {+ if (strcmp(baseitems[i], aclitems[j]) == 0)+ {+ found = true;+ break;+ }+ }+ if (!found)+ revokeitems[nrevokeitems++] = baseitems[i];+ }++ /* Prepare working buffers */
grantee = createPQExpBuffer();
grantor = createPQExpBuffer();
privs = createPQExpBuffer();
@@ -110,50 +172,21 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,
/*
* At the end, these two will be pasted together to form the result.
- *- * For older systems we use these to ensure that the owner privileges go- * before the other ones, as a GRANT could create the default entry for- * the object, which generally includes all rights for the owner. In more- * recent versions we normally handle this because the owner rights come- * first in the ACLs, but older versions might have them after the PUBLIC- * privileges.- *- * For 9.6 and later systems, much of this changes. With 9.6, we check- * the default privileges for the objects at dump time and create two sets- * of ACLs- "racls" which are the ACLs to REVOKE from the object (as the- * object may have initial privileges on it, along with any default ACLs- * which are not part of the current set of privileges), and regular- * "acls", which are the ACLs to GRANT to the object. We handle the- * REVOKEs first, followed by the GRANTs.
*/
firstsql = createPQExpBuffer();
secondsql = createPQExpBuffer();
/*
- * For pre-9.6 systems, we always start with REVOKE ALL FROM PUBLIC, as we- * don't wish to make any assumptions about what the default ACLs are, and- * we do not collect them during the dump phase (and racls will always be- * the empty set, see above).- *- * For 9.6 and later, if any revoke ACLs have been provided, then include- * them in 'firstsql'.+ * If we weren't given baseacls information, we just revoke everything and+ * then grant what's listed in the ACL. This avoids having to embed+ * detailed knowledge about what the defaults are/were, and it's not very+ * expensive since servers lacking acldefault() are now rare.
*
- * Revoke ACLs happen when an object starts out life with a set of- * privileges (eg: GRANT SELECT ON pg_class TO PUBLIC;) and the user has- * decided to revoke those rights. Since those objects come into being- * with those default privileges, we have to revoke them to match what the- * current state of affairs is. Note that we only started explicitly- * tracking such initial rights in 9.6, and prior to that all initial- * rights are actually handled by the simple 'REVOKE ALL .. FROM PUBLIC'- * case, for initdb-created objects. Prior to 9.6, we didn't handle- * extensions correctly, but we do now by tracking their initial- * privileges, in the same way we track initdb initial privileges, see- * pg_init_privs.+ * Otherwise, we need only revoke what's listed in revokeitems.
*/
- if (remoteVersion < 90600)+ if (baseacls == NULL || *baseacls == '\0')
{
- Assert(nraclitems == 0);-+ /* We assume the old defaults only involved the owner and PUBLIC */
appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
if (subname)
appendPQExpBuffer(firstsql, "(%s)", subname);
@@ -161,13 +194,24 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,
if (nspname && *nspname)
appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));
appendPQExpBuffer(firstsql, "%s FROM PUBLIC;\n", name);
+ if (owner)+ {+ appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);+ if (subname)+ appendPQExpBuffer(firstsql, "(%s)", subname);+ appendPQExpBuffer(firstsql, " ON %s ", type);+ if (nspname && *nspname)+ appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));+ appendPQExpBuffer(firstsql, "%s FROM %s;\n", name, fmtId(owner));+ }
}
else
{
/* Scan individual REVOKE ACL items */
- for (i = 0; i < nraclitems; i++)+ for (i = 0; i < nrevokeitems; i++)
{
- if (!parseAclItem(raclitems[i], type, name, subname, remoteVersion,+ if (!parseAclItem(revokeitems[i],+ type, name, subname, remoteVersion,
grantee, grantor, privs, NULL))
{
ok = false;
@@ -195,6 +239,10 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,
}
/*
+ * At this point we have issued REVOKE statements for all initial and+ * default privileges that are no longer present on the object, so we are+ * almost ready to GRANT the privileges listed in grantitems[].+ *
* We still need some hacking though to cover the case where new default
* public privileges are added in new versions: the REVOKE ALL will revoke
* them, leading to behavior different from what the old version had,
@@ -208,146 +256,92 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,
prefix, type, name);
}
- /* Scan individual ACL items */- for (i = 0; i < naclitems; i++)+ /*+ * Scan individual ACL items to be granted.+ *+ * The order in which privileges appear in the ACL string (the order they+ * have been GRANT'd in, which the backend maintains) must be preserved to+ * ensure that GRANTs WITH GRANT OPTION and subsequent GRANTs based on+ * those are dumped in the correct order. However, some old server+ * versions will show grants to PUBLIC before the owner's own grants; for+ * consistency's sake, force the owner's grants to be output first.+ */+ for (i = 0; i < ngrantitems; i++)
{
- if (!parseAclItem(aclitems[i], type, name, subname, remoteVersion,- grantee, grantor, privs, privswgo))- {- ok = false;- break;- }-- if (grantor->len == 0 && owner)- printfPQExpBuffer(grantor, "%s", owner);-- if (privs->len > 0 || privswgo->len > 0)+ if (parseAclItem(grantitems[i], type, name, subname, remoteVersion,+ grantee, grantor, privs, privswgo))
{
/*
- * Prior to 9.6, we had to handle owner privileges in a special- * manner by first REVOKE'ing the rights and then GRANT'ing them- * after. With 9.6 and above, what we need to REVOKE and what we- * need to GRANT is figured out when we dump and stashed into- * "racls" and "acls", respectively. See above.+ * If the grantor isn't the owner, we'll need to use SET SESSION+ * AUTHORIZATION to become the grantor. Issue the SET/RESET only+ * if there's something useful to do.
*/
- if (remoteVersion < 90600 && owner- && strcmp(grantee->data, owner) == 0- && strcmp(grantor->data, owner) == 0)+ if (privs->len > 0 || privswgo->len > 0)
{
- found_owner_privs = true;+ PQExpBuffer thissql;++ /* Set owner as grantor if that's not explicit in the ACL */+ if (grantor->len == 0 && owner)+ printfPQExpBuffer(grantor, "%s", owner);++ /* Make sure owner's own grants are output before others */+ if (owner &&+ strcmp(grantee->data, owner) == 0 &&+ strcmp(grantor->data, owner) == 0)+ thissql = firstsql;+ else+ thissql = secondsql;- /*- * For the owner, the default privilege level is ALL WITH- * GRANT OPTION.- */- if (strcmp(privswgo->data, "ALL") != 0)- {- appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);- if (subname)- appendPQExpBuffer(firstsql, "(%s)", subname);- appendPQExpBuffer(firstsql, " ON %s ", type);- if (nspname && *nspname)- appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));- appendPQExpBuffer(firstsql, "%s FROM %s;\n",- name, fmtId(grantee->data));- if (privs->len > 0)- {- appendPQExpBuffer(firstsql,- "%sGRANT %s ON %s ",- prefix, privs->data, type);- if (nspname && *nspname)- appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));- appendPQExpBuffer(firstsql,- "%s TO %s;\n",- name, fmtId(grantee->data));- }- if (privswgo->len > 0)- {- appendPQExpBuffer(firstsql,- "%sGRANT %s ON %s ",- prefix, privswgo->data, type);- if (nspname && *nspname)- appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));- appendPQExpBuffer(firstsql,- "%s TO %s WITH GRANT OPTION;\n",- name, fmtId(grantee->data));- }- }- }- else- {- /*- * For systems prior to 9.6, we can assume we are starting- * from no privs at this point.- *- * For 9.6 and above, at this point we have issued REVOKE- * statements for all initial and default privileges which are- * no longer present on the object (as they were passed in as- * 'racls') and we can simply GRANT the rights which are in- * 'acls'.- */
if (grantor->len > 0
&& (!owner || strcmp(owner, grantor->data) != 0))
- appendPQExpBuffer(secondsql, "SET SESSION AUTHORIZATION %s;\n",+ appendPQExpBuffer(thissql, "SET SESSION AUTHORIZATION %s;\n",
fmtId(grantor->data));
if (privs->len > 0)
{
- appendPQExpBuffer(secondsql, "%sGRANT %s ON %s ",+ appendPQExpBuffer(thissql, "%sGRANT %s ON %s ",
prefix, privs->data, type);
if (nspname && *nspname)
- appendPQExpBuffer(secondsql, "%s.", fmtId(nspname));- appendPQExpBuffer(secondsql, "%s TO ", name);+ appendPQExpBuffer(thissql, "%s.", fmtId(nspname));+ appendPQExpBuffer(thissql, "%s TO ", name);
if (grantee->len == 0)
- appendPQExpBufferStr(secondsql, "PUBLIC;\n");+ appendPQExpBufferStr(thissql, "PUBLIC;\n");
else if (strncmp(grantee->data, "group ",
strlen("group ")) == 0)
- appendPQExpBuffer(secondsql, "GROUP %s;\n",+ appendPQExpBuffer(thissql, "GROUP %s;\n",
fmtId(grantee->data + strlen("group ")));
else
- appendPQExpBuffer(secondsql, "%s;\n", fmtId(grantee->data));+ appendPQExpBuffer(thissql, "%s;\n", fmtId(grantee->data));
}
if (privswgo->len > 0)
{
- appendPQExpBuffer(secondsql, "%sGRANT %s ON %s ",+ appendPQExpBuffer(thissql, "%sGRANT %s ON %s ",
prefix, privswgo->data, type);
if (nspname && *nspname)
- appendPQExpBuffer(secondsql, "%s.", fmtId(nspname));- appendPQExpBuffer(secondsql, "%s TO ", name);+ appendPQExpBuffer(thissql, "%s.", fmtId(nspname));+ appendPQExpBuffer(thissql, "%s TO ", name);
if (grantee->len == 0)
- appendPQExpBufferStr(secondsql, "PUBLIC");+ appendPQExpBufferStr(thissql, "PUBLIC");
else if (strncmp(grantee->data, "group ",
strlen("group ")) == 0)
- appendPQExpBuffer(secondsql, "GROUP %s",+ appendPQExpBuffer(thissql, "GROUP %s",
fmtId(grantee->data + strlen("group ")));
else
- appendPQExpBufferStr(secondsql, fmtId(grantee->data));- appendPQExpBufferStr(secondsql, " WITH GRANT OPTION;\n");+ appendPQExpBufferStr(thissql, fmtId(grantee->data));+ appendPQExpBufferStr(thissql, " WITH GRANT OPTION;\n");
}
if (grantor->len > 0
&& (!owner || strcmp(owner, grantor->data) != 0))
- appendPQExpBufferStr(secondsql, "RESET SESSION AUTHORIZATION;\n");+ appendPQExpBufferStr(thissql, "RESET SESSION AUTHORIZATION;\n");
}
}
- }-- /*- * For systems prior to 9.6, if we didn't find any owner privs, the owner- * must have revoked 'em all.- *- * For 9.6 and above, we handle this through the 'racls'. See above.- */- if (remoteVersion < 90600 && !found_owner_privs && owner)- {- appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);- if (subname)- appendPQExpBuffer(firstsql, "(%s)", subname);- appendPQExpBuffer(firstsql, " ON %s ", type);- if (nspname && *nspname)- appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));- appendPQExpBuffer(firstsql, "%s FROM %s;\n",- name, fmtId(owner));+ else+ {+ /* parseAclItem failed, give up */+ ok = false;+ break;+ }
}
destroyPQExpBuffer(grantee);
@@ -361,19 +355,23 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,
if (aclitems)
free(aclitems);
-- if (raclitems)- free(raclitems);+ if (baseitems)+ free(baseitems);+ if (grantitems)+ free(grantitems);+ if (revokeitems)+ free(revokeitems);
return ok;
}
/*
- * Build ALTER DEFAULT PRIVILEGES command(s) for single pg_default_acl entry.+ * Build ALTER DEFAULT PRIVILEGES command(s) for a single pg_default_acl entry.
*
* type: the object type (TABLES, FUNCTIONS, etc)
* nspname: schema name, or NULL for global default privileges
* acls: the ACL string fetched from the database
+ * acldefault: the appropriate default ACL for the object type and owner
* owner: username of privileges owner (will be passed through fmtId)
* remoteVersion: version of database
*
@@ -382,8 +380,7 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,
*/
bool
buildDefaultACLCommands(const char *type, const char *nspname,
- const char *acls, const char *racls,- const char *initacls, const char *initracls,+ const char *acls, const char *acldefault,
const char *owner,
int remoteVersion,
PQExpBuffer sql)
@@ -403,21 +400,12 @@ buildDefaultACLCommands(const char *type, const char *nspname,
if (nspname)
appendPQExpBuffer(prefix, "IN SCHEMA %s ", fmtId(nspname));
- if (strlen(initacls) != 0 || strlen(initracls) != 0)- {- appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");- if (!buildACLCommands("", NULL, NULL, type,- initacls, initracls, owner,- prefix->data, remoteVersion, sql))- {- destroyPQExpBuffer(prefix);- return false;- }- appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");- }-+ /*+ * There's no such thing as initprivs for a default ACL, so the base ACL+ * is always just the object-type-specific default.+ */
if (!buildACLCommands("", NULL, NULL, type,
- acls, racls, owner,+ acls, acldefault, owner,
prefix->data, remoteVersion, sql))
{
destroyPQExpBuffer(prefix);
@@ -467,7 +455,7 @@ parseAclItem(const char *item, const char *type,
buf = pg_strdup(item);
/* user or group name is string up to = */
- eqpos = copyAclUserName(grantee, buf);+ eqpos = dequoteAclUserName(grantee, buf);
if (*eqpos != '=')
{
pg_free(buf);
@@ -479,7 +467,7 @@ parseAclItem(const char *item, const char *type,
if (slpos)
{
*slpos++ = '\0';
- slpos = copyAclUserName(grantor, slpos);+ slpos = dequoteAclUserName(grantor, slpos);
if (*slpos != '\0')
{
pg_free(buf);
@@ -603,13 +591,46 @@ do { \
return true;
}
+/*+ * Transfer the role name at *input into the output buffer, adding+ * quoting according to the same rules as putid() in backend's acl.c.+ */+void+quoteAclUserName(PQExpBuffer output, const char *input)+{+ const char *src;+ bool safe = true;++ for (src = input; *src; src++)+ {+ /* This test had better match what putid() does */+ if (!isalnum((unsigned char) *src) && *src != '_')+ {+ safe = false;+ break;+ }+ }+ if (!safe)+ appendPQExpBufferChar(output, '"');+ for (src = input; *src; src++)+ {+ /* A double quote character in a username is encoded as "" */+ if (*src == '"')+ appendPQExpBufferChar(output, '"');+ appendPQExpBufferChar(output, *src);+ }+ if (!safe)+ appendPQExpBufferChar(output, '"');+}+
/*
* Transfer a user or group name starting at *input into the output buffer,
* dequoting if needed. Returns a pointer to just past the input name.
* The name is taken to end at an unquoted '=' or end of string.
+ * Note: unlike quoteAclUserName(), this first clears the output buffer.
*/
static char *
-copyAclUserName(PQExpBuffer output, char *input)+dequoteAclUserName(PQExpBuffer output, char *input)
{
resetPQExpBuffer(output);
@@ -708,137 +729,6 @@ emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer,
}
}
-/*- * buildACLQueries- *- * Build the subqueries to extract out the correct set of ACLs to be- * GRANT'd and REVOKE'd for the specific kind of object, accounting for any- * initial privileges (from pg_init_privs) and based on if we are in binary- * upgrade mode or not.- *- * Also builds subqueries to extract out the set of ACLs to go from the object- * default privileges to the privileges in pg_init_privs, if we are in binary- * upgrade mode, so that those privileges can be set up and recorded in the new- * cluster before the regular privileges are added on top of those.- */-void-buildACLQueries(PQExpBuffer acl_subquery, PQExpBuffer racl_subquery,- PQExpBuffer init_acl_subquery, PQExpBuffer init_racl_subquery,- const char *acl_column, const char *acl_owner,- const char *initprivs_expr,- const char *obj_kind, bool binary_upgrade)-{- /*- * To get the delta from what the permissions were at creation time- * (either initdb or CREATE EXTENSION) vs. what they are now, we have to- * look at two things:- *- * What privileges have been added, which we calculate by extracting all- * the current privileges (using the set of default privileges for the- * object type if current privileges are NULL) and then removing those- * which existed at creation time (again, using the set of default- * privileges for the object type if there were no creation time- * privileges).- *- * What privileges have been removed, which we calculate by extracting the- * privileges as they were at creation time (or the default privileges, as- * above), and then removing the current privileges (or the default- * privileges, if current privileges are NULL).- *- * As a good cross-check, both directions of these checks should result in- * the empty set if both the current ACL and the initial privs are NULL- * (meaning, in practice, that the default ACLs were there at init time- * and is what the current privileges are).- *- * We always perform this delta on all ACLs and expect that by the time- * these are run the initial privileges will be in place, even in a binary- * upgrade situation (see below).- *- * Finally, the order in which privileges are in the ACL string (the order- * they been GRANT'd in, which the backend maintains) must be preserved to- * ensure that GRANTs WITH GRANT OPTION and subsequent GRANTs based on- * those are dumped in the correct order.- */- printfPQExpBuffer(acl_subquery,- "(SELECT pg_catalog.array_agg(acl ORDER BY row_n) FROM "- "(SELECT acl, row_n FROM "- "pg_catalog.unnest(coalesce(%s,pg_catalog.acldefault(%s,%s))) "- "WITH ORDINALITY AS perm(acl,row_n) "- "WHERE NOT EXISTS ( "- "SELECT 1 FROM "- "pg_catalog.unnest(coalesce(%s,pg_catalog.acldefault(%s,%s))) "- "AS init(init_acl) WHERE acl = init_acl)) as foo)",- acl_column,- obj_kind,- acl_owner,- initprivs_expr,- obj_kind,- acl_owner);-- printfPQExpBuffer(racl_subquery,- "(SELECT pg_catalog.array_agg(acl ORDER BY row_n) FROM "- "(SELECT acl, row_n FROM "- "pg_catalog.unnest(coalesce(%s,pg_catalog.acldefault(%s,%s))) "- "WITH ORDINALITY AS initp(acl,row_n) "- "WHERE NOT EXISTS ( "- "SELECT 1 FROM "- "pg_catalog.unnest(coalesce(%s,pg_catalog.acldefault(%s,%s))) "- "AS permp(orig_acl) WHERE acl = orig_acl)) as foo)",- initprivs_expr,- obj_kind,- acl_owner,- acl_column,- obj_kind,- acl_owner);-- /*- * In binary upgrade mode we don't run the extension script but instead- * dump out the objects independently and then recreate them. To preserve- * the initial privileges which were set on extension objects, we need to- * grab the set of GRANT and REVOKE commands necessary to get from the- * default privileges of an object to the initial privileges as recorded- * in pg_init_privs.- *- * These will then be run ahead of the regular ACL commands, which were- * calculated using the queries above, inside of a block which sets a flag- * to indicate that the backend should record the results of these GRANT- * and REVOKE statements into pg_init_privs. This is how we preserve the- * contents of that catalog across binary upgrades.- */- if (binary_upgrade)- {- printfPQExpBuffer(init_acl_subquery,- "CASE WHEN privtype = 'e' THEN "- "(SELECT pg_catalog.array_agg(acl ORDER BY row_n) FROM "- "(SELECT acl, row_n FROM pg_catalog.unnest(%s) "- "WITH ORDINALITY AS initp(acl,row_n) "- "WHERE NOT EXISTS ( "- "SELECT 1 FROM "- "pg_catalog.unnest(pg_catalog.acldefault(%s,%s)) "- "AS privm(orig_acl) WHERE acl = orig_acl)) as foo) END",- initprivs_expr,- obj_kind,- acl_owner);-- printfPQExpBuffer(init_racl_subquery,- "CASE WHEN privtype = 'e' THEN "- "(SELECT pg_catalog.array_agg(acl) FROM "- "(SELECT acl, row_n FROM "- "pg_catalog.unnest(pg_catalog.acldefault(%s,%s)) "- "WITH ORDINALITY AS privp(acl,row_n) "- "WHERE NOT EXISTS ( "- "SELECT 1 FROM pg_catalog.unnest(%s) "- "AS initp(init_acl) WHERE acl = init_acl)) as foo) END",- obj_kind,- acl_owner,- initprivs_expr);- }- else- {- printfPQExpBuffer(init_acl_subquery, "NULL");- printfPQExpBuffer(init_racl_subquery, "NULL");- }-}
/*
* Detect whether the given GUC variable is of GUC_LIST_QUOTE type.
diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.hindex f5465f19ae..fac7a05c91 100644--- a/src/bin/pg_dump/dumputils.h+++ b/src/bin/pg_dump/dumputils.h@@ -37,26 +37,22 @@
extern bool buildACLCommands(const char *name, const char *subname, const char *nspname,
- const char *type, const char *acls, const char *racls,+ const char *type, const char *acls, const char *baseacls,
const char *owner, const char *prefix, int remoteVersion,
PQExpBuffer sql);
extern bool buildDefaultACLCommands(const char *type, const char *nspname,
- const char *acls, const char *racls,- const char *initacls, const char *initracls,+ const char *acls, const char *acldefault,
const char *owner,
int remoteVersion,
PQExpBuffer sql);
++extern void quoteAclUserName(PQExpBuffer output, const char *input);+
extern void buildShSecLabelQuery(const char *catalog_name,
Oid objectId, PQExpBuffer sql);
extern void emitShSecLabels(PGconn *conn, PGresult *res,
PQExpBuffer buffer, const char *objtype, const char *objname);
-extern void buildACLQueries(PQExpBuffer acl_subquery, PQExpBuffer racl_subquery,- PQExpBuffer init_acl_subquery, PQExpBuffer init_racl_subquery,- const char *acl_column, const char *acl_owner,- const char *initprivs_expr,- const char *obj_kind, bool binary_upgrade);-
extern bool variable_is_guc_list_quote(const char *name);
extern bool SplitGUCList(char *rawstring, char separator,
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.cindex e5ea2c082d..607abb97d3 100644--- a/src/bin/pg_dump/pg_dump.c+++ b/src/bin/pg_dump/pg_dump.c@@ -179,6 +179,7 @@ static NamespaceInfo *findNamespace(Oid nsoid);
static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo);
static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo);
static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
+static void getAdditionalACLs(Archive *fout);
static void dumpCommentExtended(Archive *fout, const char *type,
const char *name, const char *namespace,
const char *owner, CatalogId catalogId,
@@ -248,8 +249,7 @@ static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo);
static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
const char *type, const char *name, const char *subname,
const char *nspname, const char *owner,
- const char *acls, const char *racls,- const char *initacls, const char *initracls);+ const DumpableAcl *dacl);
static void getDependencies(Archive *fout);
static void BuildArchiveDependencies(Archive *fout);
@@ -888,8 +888,10 @@ main(int argc, char **argv)
getDependencies(fout);
/*
- * Collect comments and security labels, if wanted.+ * Collect ACLs, comments, and security labels, if wanted.
*/
+ if (!dopt.aclsSkip)+ getAdditionalACLs(fout);
if (!dopt.no_comments)
collectComments(fout);
if (!dopt.no_security_labels)
@@ -2822,19 +2824,18 @@ dumpDatabase(Archive *fout)
i_frozenxid,
i_minmxid,
i_datacl,
- i_rdatacl,+ i_acldefault,
i_datistemplate,
i_datconnlimit,
i_tablespace;
CatalogId dbCatId;
DumpId dbDumpId;
+ DumpableAcl dbdacl;
const char *datname,
*dba,
*encoding,
*collate,
*ctype,
- *datacl,- *rdatacl,
*datistemplate,
*datconnlimit,
*tablespace;
@@ -2846,40 +2847,14 @@ dumpDatabase(Archive *fout)
/*
* Fetch the database-level properties for this database.
- *- * The order in which privileges are in the ACL string (the order they- * have been GRANT'd in, which the backend maintains) must be preserved to- * ensure that GRANTs WITH GRANT OPTION and subsequent GRANTs based on- * those are dumped in the correct order. Note that initial privileges- * (pg_init_privs) are not supported on databases, so this logic cannot- * make use of buildACLQueries().
*/
- if (fout->remoteVersion >= 90600)+ if (fout->remoteVersion >= 90300)
{
appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
"(%s datdba) AS dba, "
"pg_encoding_to_char(encoding) AS encoding, "
"datcollate, datctype, datfrozenxid, datminmxid, "
- "(SELECT array_agg(acl ORDER BY row_n) FROM "- " (SELECT acl, row_n FROM "- " unnest(coalesce(datacl,acldefault('d',datdba))) "- " WITH ORDINALITY AS perm(acl,row_n) "- " WHERE NOT EXISTS ( "- " SELECT 1 "- " FROM unnest(acldefault('d',datdba)) "- " AS init(init_acl) "- " WHERE acl = init_acl)) AS datacls) "- " AS datacl, "- "(SELECT array_agg(acl ORDER BY row_n) FROM "- " (SELECT acl, row_n FROM "- " unnest(acldefault('d',datdba)) "- " WITH ORDINALITY AS initp(acl,row_n) "- " WHERE NOT EXISTS ( "- " SELECT 1 "- " FROM unnest(coalesce(datacl,acldefault('d',datdba))) "- " AS permp(orig_acl) "- " WHERE acl = orig_acl)) AS rdatacls) "- " AS rdatacl, "+ "datacl, acldefault('d', datdba) AS acldefault, "
"datistemplate, datconnlimit, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
"shobj_description(oid, 'pg_database') AS description "
@@ -2888,13 +2863,14 @@ dumpDatabase(Archive *fout)
"WHERE datname = current_database()",
username_subquery);
}
- else if (fout->remoteVersion >= 90300)+ else if (fout->remoteVersion >= 90200)
{
appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
"(%s datdba) AS dba, "
"pg_encoding_to_char(encoding) AS encoding, "
- "datcollate, datctype, datfrozenxid, datminmxid, "- "datacl, '' as rdatacl, datistemplate, datconnlimit, "+ "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "+ "datacl, acldefault('d', datdba) AS acldefault, "+ "datistemplate, datconnlimit, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
"shobj_description(oid, 'pg_database') AS description "
@@ -2908,7 +2884,8 @@ dumpDatabase(Archive *fout)
"(%s datdba) AS dba, "
"pg_encoding_to_char(encoding) AS encoding, "
"datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
- "datacl, '' as rdatacl, datistemplate, datconnlimit, "+ "datacl, NULL AS acldefault, "+ "datistemplate, datconnlimit, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
"shobj_description(oid, 'pg_database') AS description "
@@ -2922,7 +2899,8 @@ dumpDatabase(Archive *fout)
"(%s datdba) AS dba, "
"pg_encoding_to_char(encoding) AS encoding, "
"NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
- "datacl, '' as rdatacl, datistemplate, datconnlimit, "+ "datacl, NULL AS acldefault, "+ "datistemplate, datconnlimit, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
"shobj_description(oid, 'pg_database') AS description "
@@ -2936,8 +2914,8 @@ dumpDatabase(Archive *fout)
"(%s datdba) AS dba, "
"pg_encoding_to_char(encoding) AS encoding, "
"NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
- "datacl, '' as rdatacl, datistemplate, "- "-1 as datconnlimit, "+ "datacl, NULL AS acldefault, "+ "datistemplate, -1 AS datconnlimit, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
"FROM pg_database "
"WHERE datname = current_database()",
@@ -2956,7 +2934,7 @@ dumpDatabase(Archive *fout)
i_frozenxid = PQfnumber(res, "datfrozenxid");
i_minmxid = PQfnumber(res, "datminmxid");
i_datacl = PQfnumber(res, "datacl");
- i_rdatacl = PQfnumber(res, "rdatacl");+ i_acldefault = PQfnumber(res, "acldefault");
i_datistemplate = PQfnumber(res, "datistemplate");
i_datconnlimit = PQfnumber(res, "datconnlimit");
i_tablespace = PQfnumber(res, "tablespace");
@@ -2970,8 +2948,8 @@ dumpDatabase(Archive *fout)
ctype = PQgetvalue(res, 0, i_ctype);
frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
- datacl = PQgetvalue(res, 0, i_datacl);- rdatacl = PQgetvalue(res, 0, i_rdatacl);+ dbdacl.acl = PQgetvalue(res, 0, i_datacl);+ dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
datistemplate = PQgetvalue(res, 0, i_datistemplate);
datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
tablespace = PQgetvalue(res, 0, i_tablespace);
@@ -3109,9 +3087,12 @@ dumpDatabase(Archive *fout)
* Dump ACL if any. Note that we do not support initial privileges
* (pg_init_privs) on databases.
*/
+ dbdacl.privtype = 0;+ dbdacl.initprivs = NULL;+
dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
qdatname, NULL, NULL,
- dba, datacl, rdatacl, "", "");+ dba, &dbdacl);
/*
* Now construct a DATABASE PROPERTIES archive entry to restore any
@@ -3433,59 +3414,30 @@ getBlobs(Archive *fout)
int i_oid;
int i_lomowner;
int i_lomacl;
- int i_rlomacl;- int i_initlomacl;- int i_initrlomacl;+ int i_acldefault;
pg_log_info("reading large objects");
/* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
- if (fout->remoteVersion >= 90600)+ if (fout->remoteVersion >= 90200)
{
- PQExpBuffer acl_subquery = createPQExpBuffer();- PQExpBuffer racl_subquery = createPQExpBuffer();- PQExpBuffer init_acl_subquery = createPQExpBuffer();- PQExpBuffer init_racl_subquery = createPQExpBuffer();-- buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,- init_racl_subquery, "l.lomacl", "l.lomowner",- "pip.initprivs", "'L'", dopt->binary_upgrade);-
appendPQExpBuffer(blobQry,
- "SELECT l.oid, (%s l.lomowner) AS rolname, "- "%s AS lomacl, "- "%s AS rlomacl, "- "%s AS initlomacl, "- "%s AS initrlomacl "- "FROM pg_largeobject_metadata l "- "LEFT JOIN pg_init_privs pip ON "- "(l.oid = pip.objoid "- "AND pip.classoid = 'pg_largeobject'::regclass "- "AND pip.objsubid = 0) ",- username_subquery,- acl_subquery->data,- racl_subquery->data,- init_acl_subquery->data,- init_racl_subquery->data);-- destroyPQExpBuffer(acl_subquery);- destroyPQExpBuffer(racl_subquery);- destroyPQExpBuffer(init_acl_subquery);- destroyPQExpBuffer(init_racl_subquery);+ "SELECT oid, (%s lomowner) AS rolname, lomacl, "+ "acldefault('L', lomowner) AS acldefault "+ "FROM pg_largeobject_metadata",+ username_subquery);
}
else if (fout->remoteVersion >= 90000)
appendPQExpBuffer(blobQry,
"SELECT oid, (%s lomowner) AS rolname, lomacl, "
- "NULL AS rlomacl, NULL AS initlomacl, "- "NULL AS initrlomacl "- " FROM pg_largeobject_metadata",+ "NULL AS acldefault "+ "FROM pg_largeobject_metadata",
username_subquery);
else
appendPQExpBufferStr(blobQry,
"SELECT DISTINCT loid AS oid, "
"NULL::name AS rolname, NULL::oid AS lomacl, "
- "NULL::oid AS rlomacl, NULL::oid AS initlomacl, "- "NULL::oid AS initrlomacl "+ "NULL::oid AS acldefault "
" FROM pg_largeobject");
res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
@@ -3493,9 +3445,7 @@ getBlobs(Archive *fout)
i_oid = PQfnumber(res, "oid");
i_lomowner = PQfnumber(res, "rolname");
i_lomacl = PQfnumber(res, "lomacl");
- i_rlomacl = PQfnumber(res, "rlomacl");- i_initlomacl = PQfnumber(res, "initlomacl");- i_initrlomacl = PQfnumber(res, "initrlomacl");+ i_acldefault = PQfnumber(res, "acldefault");
ntups = PQntuples(res);
@@ -3512,20 +3462,17 @@ getBlobs(Archive *fout)
AssignDumpId(&binfo[i].dobj);
binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
+ binfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lomacl));+ binfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));+ binfo[i].dacl.privtype = 0;+ binfo[i].dacl.initprivs = NULL;
binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
- binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));- binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));- binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));- binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
/* Blobs have data */
binfo[i].dobj.components |= DUMP_COMPONENT_DATA;
/* Mark whether blob has an ACL */
- if (!(PQgetisnull(res, i, i_lomacl) &&- PQgetisnull(res, i, i_rlomacl) &&- PQgetisnull(res, i, i_initlomacl) &&- PQgetisnull(res, i, i_initrlomacl)))+ if (!PQgetisnull(res, i, i_lomacl))
binfo[i].dobj.components |= DUMP_COMPONENT_ACL;
/*
@@ -3601,8 +3548,7 @@ dumpBlob(Archive *fout, const BlobInfo *binfo)
if (binfo->dobj.dump & DUMP_COMPONENT_ACL)
dumpACL(fout, binfo->dobj.dumpId, InvalidDumpId, "LARGE OBJECT",
binfo->dobj.name, NULL,
- NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,- binfo->initblobacl, binfo->initrblobacl);+ NULL, binfo->rolname, &binfo->dacl);
destroyPQExpBuffer(cquery);
destroyPQExpBuffer(dquery);
@@ -4837,7 +4783,6 @@ binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
NamespaceInfo *
getNamespaces(Archive *fout, int *numNamespaces)
{
- DumpOptions *dopt = fout->dopt;
PGresult *res;
int ntups;
int i;
@@ -4849,9 +4794,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
int i_nspowner;
int i_rolname;
int i_nspacl;
- int i_rnspacl;- int i_initnspacl;- int i_initrnspacl;+ int i_acldefault;
query = createPQExpBuffer();
@@ -4859,67 +4802,18 @@ getNamespaces(Archive *fout, int *numNamespaces)
* we fetch all namespaces including system ones, so that every object we
* read in can be linked to a containing namespace.
*/
- if (fout->remoteVersion >= 90600)- {- PQExpBuffer acl_subquery = createPQExpBuffer();- PQExpBuffer racl_subquery = createPQExpBuffer();- PQExpBuffer init_acl_subquery = createPQExpBuffer();- PQExpBuffer init_racl_subquery = createPQExpBuffer();-- /*- * Bypass pg_init_privs.initprivs for the public schema, for several- * reasons. First, dropping and recreating the schema detaches it- * from its pg_init_privs row, but an empty destination database- * starts with this ACL nonetheless. Second, we support dump/reload- * of public schema ownership changes. ALTER SCHEMA OWNER filters- * nspacl through aclnewowner(), but initprivs continues to reflect- * the initial owner. Hence, synthesize the value that nspacl will- * have after the restore's ALTER SCHEMA OWNER. Third, this makes the- * destination database match the source's ACL, even if the latter was- * an initdb-default ACL, which changed in v15. An upgrade pulls in- * changes to most system object ACLs that the DBA had not customized.- * We've made the public schema depart from that, because changing its- * ACL so easily breaks applications.- */- buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,- init_racl_subquery, "n.nspacl", "n.nspowner",- "CASE WHEN n.nspname = 'public' THEN array["- " format('%s=UC/%s', "- " n.nspowner::regrole, n.nspowner::regrole),"- " format('=U/%s', n.nspowner::regrole)]::aclitem[] "- "ELSE pip.initprivs END",- "'n'", dopt->binary_upgrade);-+ if (fout->remoteVersion >= 90200)
appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
"n.nspowner, "
"(%s nspowner) AS rolname, "
- "%s as nspacl, "- "%s as rnspacl, "- "%s as initnspacl, "- "%s as initrnspacl "- "FROM pg_namespace n "- "LEFT JOIN pg_init_privs pip "- "ON (n.oid = pip.objoid "- "AND pip.classoid = 'pg_namespace'::regclass "- "AND pip.objsubid = 0",- username_subquery,- acl_subquery->data,- racl_subquery->data,- init_acl_subquery->data,- init_racl_subquery->data);-- appendPQExpBufferStr(query, ") ");-- destroyPQExpBuffer(acl_subquery);- destroyPQExpBuffer(racl_subquery);- destroyPQExpBuffer(init_acl_subquery);- destroyPQExpBuffer(init_racl_subquery);- }+ "n.nspacl, "+ "acldefault('n', n.nspowner) AS acldefault "+ "FROM pg_namespace n",+ username_subquery);
else
appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, nspowner, "
"(%s nspowner) AS rolname, "
- "nspacl, NULL as rnspacl, "- "NULL AS initnspacl, NULL as initrnspacl "+ "nspacl, NULL AS acldefault "
"FROM pg_namespace",
username_subquery);
@@ -4935,9 +4829,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
i_nspowner = PQfnumber(res, "nspowner");
i_rolname = PQfnumber(res, "rolname");
i_nspacl = PQfnumber(res, "nspacl");
- i_rnspacl = PQfnumber(res, "rnspacl");- i_initnspacl = PQfnumber(res, "initnspacl");- i_initrnspacl = PQfnumber(res, "initrnspacl");+ i_acldefault = PQfnumber(res, "acldefault");
for (i = 0; i < ntups; i++)
{
@@ -4946,23 +4838,61 @@ getNamespaces(Archive *fout, int *numNamespaces)
nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&nsinfo[i].dobj);
nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
+ nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));+ nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));+ nsinfo[i].dacl.privtype = 0;+ nsinfo[i].dacl.initprivs = NULL;
nsinfo[i].nspowner = atooid(PQgetvalue(res, i, i_nspowner));
nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
- nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));- nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));- nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));- nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
/* Decide whether to dump this namespace */
selectDumpableNamespace(&nsinfo[i], fout);
/* Mark whether namespace has an ACL */
- if (!(PQgetisnull(res, i, i_nspacl) &&- PQgetisnull(res, i, i_rnspacl) &&- PQgetisnull(res, i, i_initnspacl) &&- PQgetisnull(res, i, i_initrnspacl)))+ if (!PQgetisnull(res, i, i_nspacl))+ nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;++ /*+ * We ignore any pg_init_privs.initprivs entry for the public schema+ * and assume a predetermined default, for several reasons. First,+ * dropping and recreating the schema removes its pg_init_privs entry,+ * but an empty destination database starts with this ACL nonetheless.+ * Second, we support dump/reload of public schema ownership changes.+ * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but+ * initprivs continues to reflect the initial owner. Hence,+ * synthesize the value that nspacl will have after the restore's+ * ALTER SCHEMA OWNER. Third, this makes the destination database+ * match the source's ACL, even if the latter was an initdb-default+ * ACL, which changed in v15. An upgrade pulls in changes to most+ * system object ACLs that the DBA had not customized. We've made the+ * public schema depart from that, because changing its ACL so easily+ * breaks applications.+ */+ if (strcmp(nsinfo[i].dobj.name, "public") == 0)+ {+ PQExpBuffer aclarray = createPQExpBuffer();+ PQExpBuffer aclitem = createPQExpBuffer();++ /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */+ appendPQExpBufferChar(aclarray, '{');+ quoteAclUserName(aclitem, nsinfo[i].rolname);+ appendPQExpBufferStr(aclitem, "=UC/");+ quoteAclUserName(aclitem, nsinfo[i].rolname);+ appendPGArray(aclarray, aclitem->data);+ resetPQExpBuffer(aclitem);+ appendPQExpBufferStr(aclitem, "=U/");+ quoteAclUserName(aclitem, nsinfo[i].rolname);+ appendPGArray(aclarray, aclitem->data);+ appendPQExpBufferChar(aclarray, '}');++ nsinfo[i].dacl.privtype = 'i';+ nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
+ destroyPQExpBuffer(aclarray);+ destroyPQExpBuffer(aclitem);+ }+
if (strlen(nsinfo[i].rolname) == 0)
pg_log_warning("owner of schema \"%s\" appears to be invalid",
nsinfo[i].dobj.name);
@@ -5085,7 +5015,6 @@ getExtensions(Archive *fout, int *numExtensions)
TypeInfo *
getTypes(Archive *fout, int *numTypes)
{
- DumpOptions *dopt = fout->dopt;
PGresult *res;
int ntups;
int i;
@@ -5097,9 +5026,7 @@ getTypes(Archive *fout, int *numTypes)
int i_typname;
int i_typnamespace;
int i_typacl;
- int i_rtypacl;- int i_inittypacl;- int i_initrtypacl;+ int i_acldefault;
int i_rolname;
int i_typelem;
int i_typrelid;
@@ -5123,52 +5050,11 @@ getTypes(Archive *fout, int *numTypes)
* cost of the subselect probe for all standard types. This would have to
* be revisited if the backend ever allows renaming of array types.
*/
-- if (fout->remoteVersion >= 90600)- {- PQExpBuffer acl_subquery = createPQExpBuffer();- PQExpBuffer racl_subquery = createPQExpBuffer();- PQExpBuffer initacl_subquery = createPQExpBuffer();- PQExpBuffer initracl_subquery = createPQExpBuffer();-- buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,- initracl_subquery, "t.typacl", "t.typowner",- "pip.initprivs", "'T'", dopt->binary_upgrade);-- appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "- "t.typnamespace, "- "%s AS typacl, "- "%s AS rtypacl, "- "%s AS inittypacl, "- "%s AS initrtypacl, "- "(%s t.typowner) AS rolname, "- "t.typelem, t.typrelid, "- "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "- "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "- "t.typtype, t.typisdefined, "- "t.typname[0] = '_' AND t.typelem != 0 AND "- "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "- "FROM pg_type t "- "LEFT JOIN pg_init_privs pip ON "- "(t.oid = pip.objoid "- "AND pip.classoid = 'pg_type'::regclass "- "AND pip.objsubid = 0) ",- acl_subquery->data,- racl_subquery->data,- initacl_subquery->data,- initracl_subquery->data,- username_subquery);-- destroyPQExpBuffer(acl_subquery);- destroyPQExpBuffer(racl_subquery);- destroyPQExpBuffer(initacl_subquery);- destroyPQExpBuffer(initracl_subquery);- }- else if (fout->remoteVersion >= 90200)+ if (fout->remoteVersion >= 90200)
{
appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
- "typnamespace, typacl, NULL as rtypacl, "- "NULL AS inittypacl, NULL AS initrtypacl, "+ "typnamespace, typacl, "+ "acldefault('T', typowner) AS acldefault, "
"(%s typowner) AS rolname, "
"typelem, typrelid, "
"CASE WHEN typrelid = 0 THEN ' '::\"char\" "
@@ -5182,8 +5068,7 @@ getTypes(Archive *fout, int *numTypes)
else if (fout->remoteVersion >= 80300)
{
appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
- "typnamespace, NULL AS typacl, NULL as rtypacl, "- "NULL AS inittypacl, NULL AS initrtypacl, "+ "typnamespace, NULL AS typacl, NULL AS acldefault, "
"(%s typowner) AS rolname, "
"typelem, typrelid, "
"CASE WHEN typrelid = 0 THEN ' '::\"char\" "
@@ -5197,8 +5082,7 @@ getTypes(Archive *fout, int *numTypes)
else
{
appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
- "typnamespace, NULL AS typacl, NULL as rtypacl, "- "NULL AS inittypacl, NULL AS initrtypacl, "+ "typnamespace, NULL AS typacl, NULL AS acldefault, "
"(%s typowner) AS rolname, "
"typelem, typrelid, "
"CASE WHEN typrelid = 0 THEN ' '::\"char\" "
@@ -5220,9 +5104,7 @@ getTypes(Archive *fout, int *numTypes)
i_typname = PQfnumber(res, "typname");
i_typnamespace = PQfnumber(res, "typnamespace");
i_typacl = PQfnumber(res, "typacl");
- i_rtypacl = PQfnumber(res, "rtypacl");- i_inittypacl = PQfnumber(res, "inittypacl");- i_initrtypacl = PQfnumber(res, "initrtypacl");+ i_acldefault = PQfnumber(res, "acldefault");
i_rolname = PQfnumber(res, "rolname");
i_typelem = PQfnumber(res, "typelem");
i_typrelid = PQfnumber(res, "typrelid");
@@ -5240,12 +5122,12 @@ getTypes(Archive *fout, int *numTypes)
tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
tyinfo[i].dobj.namespace =
findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
+ tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));+ tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));+ tyinfo[i].dacl.privtype = 0;+ tyinfo[i].dacl.initprivs = NULL;
tyinfo[i].ftypname = NULL; /* may get filled later */
tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
- tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));- tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));- tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));- tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
@@ -5271,10 +5153,7 @@ getTypes(Archive *fout, int *numTypes)
selectDumpableType(&tyinfo[i], fout);
/* Mark whether type has an ACL */
- if (!(PQgetisnull(res, i, i_typacl) &&- PQgetisnull(res, i, i_rtypacl) &&- PQgetisnull(res, i, i_inittypacl) &&- PQgetisnull(res, i, i_initrtypacl)))+ if (!PQgetisnull(res, i, i_typacl))
tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
/*
@@ -5801,9 +5680,7 @@ getAggregates(Archive *fout, int *numAggs)
int i_proargtypes;
int i_rolname;
int i_aggacl;
- int i_raggacl;- int i_initaggacl;- int i_initraggacl;+ int i_acldefault;
/*
* Find all interesting aggregates. See comment in getFuncs() for the
@@ -5811,16 +5688,8 @@ getAggregates(Archive *fout, int *numAggs)
*/
if (fout->remoteVersion >= 90600)
{
- PQExpBuffer acl_subquery = createPQExpBuffer();- PQExpBuffer racl_subquery = createPQExpBuffer();- PQExpBuffer initacl_subquery = createPQExpBuffer();- PQExpBuffer initracl_subquery = createPQExpBuffer();
const char *agg_check;
- buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,- initracl_subquery, "p.proacl", "p.proowner",- "pip.initprivs", "'f'", dopt->binary_upgrade);-
agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
: "p.proisagg");
@@ -5829,10 +5698,8 @@ getAggregates(Archive *fout, int *numAggs)
"p.pronamespace AS aggnamespace, "
"p.pronargs, p.proargtypes, "
"(%s p.proowner) AS rolname, "
- "%s AS aggacl, "- "%s AS raggacl, "- "%s AS initaggacl, "- "%s AS initraggacl "+ "p.proacl AS aggacl, "+ "acldefault('f', p.proowner) AS acldefault "
"FROM pg_proc p "
"LEFT JOIN pg_init_privs pip ON "
"(p.oid = pip.objoid "
@@ -5844,10 +5711,6 @@ getAggregates(Archive *fout, int *numAggs)
"WHERE nspname = 'pg_catalog') OR "
"p.proacl IS DISTINCT FROM pip.initprivs",
username_subquery,
- acl_subquery->data,- racl_subquery->data,- initacl_subquery->data,- initracl_subquery->data,
agg_check);
if (dopt->binary_upgrade)
appendPQExpBufferStr(query,
@@ -5857,11 +5720,29 @@ getAggregates(Archive *fout, int *numAggs)
"refclassid = 'pg_extension'::regclass AND "
"deptype = 'e')");
appendPQExpBufferChar(query, ')');
-- destroyPQExpBuffer(acl_subquery);- destroyPQExpBuffer(racl_subquery);- destroyPQExpBuffer(initacl_subquery);- destroyPQExpBuffer(initracl_subquery);+ }+ else if (fout->remoteVersion >= 90200)+ {+ appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "+ "pronamespace AS aggnamespace, "+ "pronargs, proargtypes, "+ "(%s proowner) AS rolname, "+ "proacl AS aggacl, "+ "acldefault('f', proowner) AS acldefault "+ "FROM pg_proc p "+ "WHERE proisagg AND ("+ "pronamespace != "+ "(SELECT oid FROM pg_namespace "+ "WHERE nspname = 'pg_catalog')",+ username_subquery);+ if (dopt->binary_upgrade)+ appendPQExpBufferStr(query,+ " OR EXISTS(SELECT 1 FROM pg_depend WHERE "+ "classid = 'pg_proc'::regclass AND "+ "objid = p.oid AND "+ "refclassid = 'pg_extension'::regclass AND "+ "deptype = 'e')");+ appendPQExpBufferChar(query, ')');
}
else if (fout->remoteVersion >= 80200)
{
@@ -5870,8 +5751,7 @@ getAggregates(Archive *fout, int *numAggs)
"pronargs, proargtypes, "
"(%s proowner) AS rolname, "
"proacl AS aggacl, "
- "NULL AS raggacl, "- "NULL AS initaggacl, NULL AS initraggacl "+ "NULL AS acldefault "
"FROM pg_proc p "
"WHERE proisagg AND ("
"pronamespace != "
@@ -5895,8 +5775,7 @@ getAggregates(Archive *fout, int *numAggs)
"proargtypes, "
"(%s proowner) AS rolname, "
"proacl AS aggacl, "
- "NULL AS raggacl, "- "NULL AS initaggacl, NULL AS initraggacl "+ "NULL AS acldefault "
"FROM pg_proc "
"WHERE proisagg "
"AND pronamespace != "
@@ -5919,9 +5798,7 @@ getAggregates(Archive *fout, int *numAggs)
i_proargtypes = PQfnumber(res, "proargtypes");
i_rolname = PQfnumber(res, "rolname");
i_aggacl = PQfnumber(res, "aggacl");
- i_raggacl = PQfnumber(res, "raggacl");- i_initaggacl = PQfnumber(res, "initaggacl");- i_initraggacl = PQfnumber(res, "initraggacl");+ i_acldefault = PQfnumber(res, "acldefault");
for (i = 0; i < ntups; i++)
{
@@ -5932,16 +5809,16 @@ getAggregates(Archive *fout, int *numAggs)
agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
agginfo[i].aggfn.dobj.namespace =
findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
+ agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));+ agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));+ agginfo[i].aggfn.dacl.privtype = 0;+ agginfo[i].aggfn.dacl.initprivs = NULL;
agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
if (strlen(agginfo[i].aggfn.rolname) == 0)
pg_log_warning("owner of aggregate function \"%s\" appears to be invalid",
agginfo[i].aggfn.dobj.name);
agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
- agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));- agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));- agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));- agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
if (agginfo[i].aggfn.nargs == 0)
agginfo[i].aggfn.argtypes = NULL;
@@ -5957,10 +5834,7 @@ getAggregates(Archive *fout, int *numAggs)
selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
/* Mark whether aggregate has an ACL */
- if (!(PQgetisnull(res, i, i_aggacl) &&- PQgetisnull(res, i, i_raggacl) &&- PQgetisnull(res, i, i_initaggacl) &&- PQgetisnull(res, i, i_initraggacl)))+ if (!PQgetisnull(res, i, i_aggacl))
agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
}
@@ -5997,9 +5871,7 @@ getFuncs(Archive *fout, int *numFuncs)
int i_proargtypes;
int i_prorettype;
int i_proacl;
- int i_rproacl;- int i_initproacl;- int i_initrproacl;+ int i_acldefault;
/*
* Find all interesting functions. This is a bit complicated:
@@ -6021,30 +5893,20 @@ getFuncs(Archive *fout, int *numFuncs)
* to gather the information about them, though they won't be dumped if
* they are built-in. Also, in 9.6 and up, include functions in
* pg_catalog if they have an ACL different from what's shown in
- * pg_init_privs.+ * pg_init_privs (so we have to join to pg_init_privs; annoying).
*/
if (fout->remoteVersion >= 90600)
{
- PQExpBuffer acl_subquery = createPQExpBuffer();- PQExpBuffer racl_subquery = createPQExpBuffer();- PQExpBuffer initacl_subquery = createPQExpBuffer();- PQExpBuffer initracl_subquery = createPQExpBuffer();
const char *not_agg_check;
- buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,- initracl_subquery, "p.proacl", "p.proowner",- "pip.initprivs", "'f'", dopt->binary_upgrade);-
not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
: "NOT p.proisagg");
appendPQExpBuffer(query,
"SELECT p.tableoid, p.oid, p.proname, p.prolang, "
"p.pronargs, p.proargtypes, p.prorettype, "
- "%s AS proacl, "- "%s AS rproacl, "- "%s AS initproacl, "- "%s AS initrproacl, "+ "p.proacl, "+ "acldefault('f', p.proowner) AS acldefault, "
"p.pronamespace, "
"(%s p.proowner) AS rolname "
"FROM pg_proc p "
@@ -6067,10 +5929,6 @@ getFuncs(Archive *fout, int *numFuncs)
"\n WHERE pg_transform.oid > %u AND "
"\n (p.oid = pg_transform.trffromsql"
"\n OR p.oid = pg_transform.trftosql))",
- acl_subquery->data,- racl_subquery->data,- initacl_subquery->data,- initracl_subquery->data,
username_subquery,
not_agg_check,
g_last_builtin_oid,
@@ -6085,23 +5943,23 @@ getFuncs(Archive *fout, int *numFuncs)
appendPQExpBufferStr(query,
"\n OR p.proacl IS DISTINCT FROM pip.initprivs");
appendPQExpBufferChar(query, ')');
-- destroyPQExpBuffer(acl_subquery);- destroyPQExpBuffer(racl_subquery);- destroyPQExpBuffer(initacl_subquery);- destroyPQExpBuffer(initracl_subquery);
}
else
{
+ const char *acldefault_call;++ acldefault_call = (fout->remoteVersion >= 90200 ?+ "acldefault('f', proowner)" : "NULL");+
appendPQExpBuffer(query,
"SELECT tableoid, oid, proname, prolang, "
"pronargs, proargtypes, prorettype, proacl, "
- "NULL as rproacl, "- "NULL as initproacl, NULL AS initrproacl, "+ "%s AS acldefault, "
"pronamespace, "
"(%s proowner) AS rolname "
"FROM pg_proc p "
"WHERE NOT proisagg",
+ acldefault_call,
username_subquery);
if (fout->remoteVersion >= 90200)
appendPQExpBufferStr(query,
@@ -6154,9 +6012,7 @@ getFuncs(Archive *fout, int *numFuncs)
i_proargtypes = PQfnumber(res, "proargtypes");
i_prorettype = PQfnumber(res, "prorettype");
i_proacl = PQfnumber(res, "proacl");
- i_rproacl = PQfnumber(res, "rproacl");- i_initproacl = PQfnumber(res, "initproacl");- i_initrproacl = PQfnumber(res, "initrproacl");+ i_acldefault = PQfnumber(res, "acldefault");
for (i = 0; i < ntups; i++)
{
@@ -6167,13 +6023,13 @@ getFuncs(Archive *fout, int *numFuncs)
finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
finfo[i].dobj.namespace =
findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
+ finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));+ finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));+ finfo[i].dacl.privtype = 0;+ finfo[i].dacl.initprivs = NULL;
finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
- finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));- finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));- finfo[i].initproacl = pg_strdup(PQgetvalue(res, i, i_initproacl));- finfo[i].initrproacl = pg_strdup(PQgetvalue(res, i, i_initrproacl));
finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
if (finfo[i].nargs == 0)
finfo[i].argtypes = NULL;
@@ -6188,10 +6044,7 @@ getFuncs(Archive *fout, int *numFuncs)
selectDumpableObject(&(finfo[i].dobj), fout);
/* Mark whether function has an ACL */
- if (!(PQgetisnull(res, i, i_proacl) &&- PQgetisnull(res, i, i_rproacl) &&- PQgetisnull(res, i, i_initproacl) &&- PQgetisnull(res, i, i_initrproacl)))+ if (!PQgetisnull(res, i, i_proacl))
finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
if (strlen(finfo[i].rolname) == 0)
@@ -6256,10 +6109,7 @@ getTables(Archive *fout, int *numTables)
int i_amname;
int i_is_identity_sequence;
int i_relacl;
- int i_rrelacl;- int i_initrelacl;- int i_initrrelacl;- int i_changed_acl;+ int i_acldefault;
int i_partkeydef;
int i_ispartition;
int i_partbound;
@@ -6400,67 +6250,14 @@ getTables(Archive *fout, int *numTables)
appendPQExpBufferStr(query,
"false AS is_identity_sequence, ");
- if (fout->remoteVersion >= 90600)- {- PQExpBuffer acl_subquery = createPQExpBuffer();- PQExpBuffer racl_subquery = createPQExpBuffer();- PQExpBuffer initacl_subquery = createPQExpBuffer();- PQExpBuffer initracl_subquery = createPQExpBuffer();- PQExpBuffer attacl_subquery = createPQExpBuffer();- PQExpBuffer attracl_subquery = createPQExpBuffer();- PQExpBuffer attinitacl_subquery = createPQExpBuffer();- PQExpBuffer attinitracl_subquery = createPQExpBuffer();-- buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,- initracl_subquery, "c.relacl", "c.relowner",- "pip.initprivs",- "CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)- " THEN 's' ELSE 'r' END::\"char\"",- dopt->binary_upgrade);-- buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,- attinitracl_subquery, "at.attacl", "c.relowner",- "pip.initprivs", "'c'", dopt->binary_upgrade);-- appendPQExpBuffer(query,- "%s AS relacl, %s as rrelacl, "- "%s AS initrelacl, %s as initrrelacl, ",- acl_subquery->data,- racl_subquery->data,- initacl_subquery->data,- initracl_subquery->data);-- appendPQExpBuffer(query,- "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON "- "(c.oid = pip.objoid "- "AND pip.classoid = 'pg_class'::regclass "- "AND pip.objsubid = at.attnum)"- "WHERE at.attrelid = c.oid AND ("- "%s IS NOT NULL "- "OR %s IS NOT NULL "- "OR %s IS NOT NULL "- "OR %s IS NOT NULL"- "))"- "AS changed_acl, ",- attacl_subquery->data,- attracl_subquery->data,- attinitacl_subquery->data,- attinitracl_subquery->data);-- destroyPQExpBuffer(acl_subquery);- destroyPQExpBuffer(racl_subquery);- destroyPQExpBuffer(initacl_subquery);- destroyPQExpBuffer(initracl_subquery);- destroyPQExpBuffer(attacl_subquery);- destroyPQExpBuffer(attracl_subquery);- destroyPQExpBuffer(attinitacl_subquery);- destroyPQExpBuffer(attinitracl_subquery);- }+ if (fout->remoteVersion >= 90200)+ appendPQExpBufferStr(query,+ "c.relacl, "+ "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)+ " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, ");
else
appendPQExpBufferStr(query,
- "c.relacl, NULL as rrelacl, "- "NULL AS initrelacl, NULL AS initrrelacl, "- "false AS changed_acl, ");+ "c.relacl, NULL AS acldefault, ");
if (fout->remoteVersion >= 100000)
appendPQExpBufferStr(query,
@@ -6482,22 +6279,16 @@ getTables(Archive *fout, int *numTables)
"\nFROM pg_class c\n"
"LEFT JOIN pg_depend d ON "
"(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
- "d.classid = c.tableoid AND d.objid = c.oid AND "+ "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
"d.objsubid = 0 AND "
- "d.refclassid = c.tableoid AND d.deptype IN ('a', 'i'))\n"+ "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
"LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
/*
- * In 9.6 and up, left join to pg_init_privs to detect if any privileges- * are still as-set-at-init, in which case we won't dump out ACL commands- * for those. We also are interested in the amname as of 9.6.+ * In 9.6 and up, left join to pg_am to pick up the amname.
*/
if (fout->remoteVersion >= 90600)
appendPQExpBufferStr(query,
- "LEFT JOIN pg_init_privs pip ON "- "(c.oid = pip.objoid "- "AND pip.classoid = 'pg_class'::regclass "- "AND pip.objsubid = 0)\n"
"LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
/*
@@ -6509,7 +6300,9 @@ getTables(Archive *fout, int *numTables)
*/
if (fout->remoteVersion >= 80200)
appendPQExpBufferStr(query,
- "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");+ "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"+ " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)+ " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
/*
* Restrict to interesting relkinds (in particular, not indexes). Not all
@@ -6583,10 +6376,7 @@ getTables(Archive *fout, int *numTables)
i_amname = PQfnumber(res, "amname");
i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
i_relacl = PQfnumber(res, "relacl");
- i_rrelacl = PQfnumber(res, "rrelacl");- i_initrelacl = PQfnumber(res, "initrelacl");- i_initrrelacl = PQfnumber(res, "initrrelacl");- i_changed_acl = PQfnumber(res, "changed_acl");+ i_acldefault = PQfnumber(res, "acldefault");
i_partkeydef = PQfnumber(res, "partkeydef");
i_ispartition = PQfnumber(res, "ispartition");
i_partbound = PQfnumber(res, "partbound");
@@ -6615,6 +6405,10 @@ getTables(Archive *fout, int *numTables)
tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
tblinfo[i].dobj.namespace =
findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
+ tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));+ tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));+ tblinfo[i].dacl.privtype = 0;+ tblinfo[i].dacl.initprivs = NULL;
tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
@@ -6661,10 +6455,6 @@ getTables(Archive *fout, int *numTables)
else
tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
- tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));- tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));- tblinfo[i].initrelacl = pg_strdup(PQgetvalue(res, i, i_initrelacl));- tblinfo[i].initrrelacl = pg_strdup(PQgetvalue(res, i, i_initrrelacl));
tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
@@ -6700,23 +6490,10 @@ getTables(Archive *fout, int *numTables)
/* Tables have data */
tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
- /*- * Mark whether table has an ACL.- *- * If the table-level and all column-level ACLs for this table are- * unchanged, then we don't need to worry about including the ACLs for- * this table. If any column-level ACLs have been changed, the- * 'changed_acl' column from the query will indicate that.- *- * This can result in a significant performance improvement in cases- * where we are only looking to dump out the ACL (eg: pg_catalog).- */- if (!(PQgetisnull(res, i, i_relacl) &&- PQgetisnull(res, i, i_rrelacl) &&- PQgetisnull(res, i, i_initrelacl) &&- PQgetisnull(res, i, i_initrrelacl) &&- strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0))+ /* Mark whether table has an ACL */+ if (!PQgetisnull(res, i, i_relacl))
tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
+ tblinfo[i].hascolumnACLs = false; /* may get set later */
/*
* Read-lock target tables to make sure they aren't DROPPED or altered
@@ -7999,7 +7776,6 @@ getEventTriggers(Archive *fout, int *numEventTriggers)
ProcLangInfo *
getProcLangs(Archive *fout, int *numProcLangs)
{
- DumpOptions *dopt = fout->dopt;
PGresult *res;
int ntups;
int i;
@@ -8013,56 +7789,30 @@ getProcLangs(Archive *fout, int *numProcLangs)
int i_laninline;
int i_lanvalidator;
int i_lanacl;
- int i_rlanacl;- int i_initlanacl;- int i_initrlanacl;+ int i_acldefault;
int i_lanowner;
- if (fout->remoteVersion >= 90600)+ if (fout->remoteVersion >= 90200)
{
- PQExpBuffer acl_subquery = createPQExpBuffer();- PQExpBuffer racl_subquery = createPQExpBuffer();- PQExpBuffer initacl_subquery = createPQExpBuffer();- PQExpBuffer initracl_subquery = createPQExpBuffer();-- buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,- initracl_subquery, "l.lanacl", "l.lanowner",- "pip.initprivs", "'l'", dopt->binary_upgrade);-- /* pg_language has a laninline column */- appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "- "l.lanname, l.lanpltrusted, l.lanplcallfoid, "- "l.laninline, l.lanvalidator, "- "%s AS lanacl, "- "%s AS rlanacl, "- "%s AS initlanacl, "- "%s AS initrlanacl, "- "(%s l.lanowner) AS lanowner "- "FROM pg_language l "- "LEFT JOIN pg_init_privs pip ON "- "(l.oid = pip.objoid "- "AND pip.classoid = 'pg_language'::regclass "- "AND pip.objsubid = 0) "- "WHERE l.lanispl "- "ORDER BY l.oid",- acl_subquery->data,- racl_subquery->data,- initacl_subquery->data,- initracl_subquery->data,+ /* acldefault() exists */+ appendPQExpBuffer(query, "SELECT tableoid, oid, "+ "lanname, lanpltrusted, lanplcallfoid, "+ "laninline, lanvalidator, "+ "lanacl, "+ "acldefault('l', lanowner) AS acldefault, "+ "(%s lanowner) AS lanowner "+ "FROM pg_language "+ "WHERE lanispl "+ "ORDER BY oid",
username_subquery);
-- destroyPQExpBuffer(acl_subquery);- destroyPQExpBuffer(racl_subquery);- destroyPQExpBuffer(initacl_subquery);- destroyPQExpBuffer(initracl_subquery);
}
else if (fout->remoteVersion >= 90000)
{
/* pg_language has a laninline column */
appendPQExpBuffer(query, "SELECT tableoid, oid, "
"lanname, lanpltrusted, lanplcallfoid, "
- "laninline, lanvalidator, lanacl, NULL AS rlanacl, "- "NULL AS initlanacl, NULL AS initrlanacl, "+ "laninline, lanvalidator, "+ "lanacl, NULL AS acldefault, "
"(%s lanowner) AS lanowner "
"FROM pg_language "
"WHERE lanispl "
@@ -8075,8 +7825,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
appendPQExpBuffer(query, "SELECT tableoid, oid, "
"lanname, lanpltrusted, lanplcallfoid, "
"0 AS laninline, lanvalidator, lanacl, "
- "NULL AS rlanacl, "- "NULL AS initlanacl, NULL AS initrlanacl, "+ "NULL AS acldefault, "
"(%s lanowner) AS lanowner "
"FROM pg_language "
"WHERE lanispl "
@@ -8089,8 +7838,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
appendPQExpBuffer(query, "SELECT tableoid, oid, "
"lanname, lanpltrusted, lanplcallfoid, "
"0 AS laninline, lanvalidator, lanacl, "
- "NULL AS rlanacl, "- "NULL AS initlanacl, NULL AS initrlanacl, "+ "NULL AS acldefault, "
"(%s '10') AS lanowner "
"FROM pg_language "
"WHERE lanispl "
@@ -8103,8 +7851,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
appendPQExpBuffer(query, "SELECT tableoid, oid, "
"lanname, lanpltrusted, lanplcallfoid, "
"0 AS laninline, lanvalidator, lanacl, "
- "NULL AS rlanacl, "- "NULL AS initlanacl, NULL AS initrlanacl, "+ "NULL AS acldefault, "
"(%s '1') AS lanowner "
"FROM pg_language "
"WHERE lanispl "
@@ -8128,9 +7875,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
i_laninline = PQfnumber(res, "laninline");
i_lanvalidator = PQfnumber(res, "lanvalidator");
i_lanacl = PQfnumber(res, "lanacl");
- i_rlanacl = PQfnumber(res, "rlanacl");- i_initlanacl = PQfnumber(res, "initlanacl");- i_initrlanacl = PQfnumber(res, "initrlanacl");+ i_acldefault = PQfnumber(res, "acldefault");
i_lanowner = PQfnumber(res, "lanowner");
for (i = 0; i < ntups; i++)
@@ -8141,24 +7886,21 @@ getProcLangs(Archive *fout, int *numProcLangs)
AssignDumpId(&planginfo[i].dobj);
planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
+ planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));+ planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));+ planginfo[i].dacl.privtype = 0;+ planginfo[i].dacl.initprivs = NULL;
planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
- planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));- planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));- planginfo[i].initlanacl = pg_strdup(PQgetvalue(res, i, i_initlanacl));- planginfo[i].initrlanacl = pg_strdup(PQgetvalue(res, i, i_initrlanacl));
planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
/* Decide whether we want to dump it */
selectDumpableProcLang(&(planginfo[i]), fout);
/* Mark whether language has an ACL */
- if (!(PQgetisnull(res, i, i_lanacl) &&- PQgetisnull(res, i, i_rlanacl) &&- PQgetisnull(res, i, i_initlanacl) &&- PQgetisnull(res, i, i_initrlanacl)))+ if (!PQgetisnull(res, i, i_lanacl))
planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
}
@@ -9209,7 +8951,6 @@ getTSConfigurations(Archive *fout, int *numTSConfigs)
FdwInfo *
getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
{
- DumpOptions *dopt = fout->dopt;
PGresult *res;
int ntups;
int i;
@@ -9222,9 +8963,7 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
int i_fdwhandler;
int i_fdwvalidator;
int i_fdwacl;
- int i_rfdwacl;- int i_initfdwacl;- int i_initrfdwacl;+ int i_acldefault;
int i_fdwoptions;
/* Before 8.4, there are no foreign-data wrappers */
@@ -9236,46 +8975,22 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
query = createPQExpBuffer();
- if (fout->remoteVersion >= 90600)+ if (fout->remoteVersion >= 90200)
{
- PQExpBuffer acl_subquery = createPQExpBuffer();- PQExpBuffer racl_subquery = createPQExpBuffer();- PQExpBuffer initacl_subquery = createPQExpBuffer();- PQExpBuffer initracl_subquery = createPQExpBuffer();-- buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,- initracl_subquery, "f.fdwacl", "f.fdwowner",- "pip.initprivs", "'F'", dopt->binary_upgrade);-- appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "- "(%s f.fdwowner) AS rolname, "- "f.fdwhandler::pg_catalog.regproc, "- "f.fdwvalidator::pg_catalog.regproc, "- "%s AS fdwacl, "- "%s AS rfdwacl, "- "%s AS initfdwacl, "- "%s AS initrfdwacl, "+ appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "+ "(%s fdwowner) AS rolname, "+ "fdwhandler::pg_catalog.regproc, "+ "fdwvalidator::pg_catalog.regproc, "+ "fdwacl, "+ "acldefault('F', fdwowner) AS acldefault, "
"array_to_string(ARRAY("
"SELECT quote_ident(option_name) || ' ' || "
"quote_literal(option_value) "
- "FROM pg_options_to_table(f.fdwoptions) "+ "FROM pg_options_to_table(fdwoptions) "
"ORDER BY option_name"
"), E',\n ') AS fdwoptions "
- "FROM pg_foreign_data_wrapper f "- "LEFT JOIN pg_init_privs pip ON "- "(f.oid = pip.objoid "- "AND pip.classoid = 'pg_foreign_data_wrapper'::regclass "- "AND pip.objsubid = 0) ",- username_subquery,- acl_subquery->data,- racl_subquery->data,- initacl_subquery->data,- initracl_subquery->data);-- destroyPQExpBuffer(acl_subquery);- destroyPQExpBuffer(racl_subquery);- destroyPQExpBuffer(initacl_subquery);- destroyPQExpBuffer(initracl_subquery);+ "FROM pg_foreign_data_wrapper",+ username_subquery);
}
else if (fout->remoteVersion >= 90100)
{
@@ -9283,8 +8998,7 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
"(%s fdwowner) AS rolname, "
"fdwhandler::pg_catalog.regproc, "
"fdwvalidator::pg_catalog.regproc, fdwacl, "
- "NULL as rfdwacl, "- "NULL as initfdwacl, NULL AS initrfdwacl, "+ "NULL AS acldefault, "
"array_to_string(ARRAY("
"SELECT quote_ident(option_name) || ' ' || "
"quote_literal(option_value) "
@@ -9300,8 +9014,7 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
"(%s fdwowner) AS rolname, "
"'-' AS fdwhandler, "
"fdwvalidator::pg_catalog.regproc, fdwacl, "
- "NULL as rfdwacl, "- "NULL as initfdwacl, NULL AS initrfdwacl, "+ "NULL AS acldefault, "
"array_to_string(ARRAY("
"SELECT quote_ident(option_name) || ' ' || "
"quote_literal(option_value) "
@@ -9326,9 +9039,7 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
i_fdwhandler = PQfnumber(res, "fdwhandler");
i_fdwvalidator = PQfnumber(res, "fdwvalidator");
i_fdwacl = PQfnumber(res, "fdwacl");
- i_rfdwacl = PQfnumber(res, "rfdwacl");- i_initfdwacl = PQfnumber(res, "initfdwacl");- i_initrfdwacl = PQfnumber(res, "initrfdwacl");+ i_acldefault = PQfnumber(res, "acldefault");
i_fdwoptions = PQfnumber(res, "fdwoptions");
for (i = 0; i < ntups; i++)
@@ -9339,23 +9050,20 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
AssignDumpId(&fdwinfo[i].dobj);
fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
fdwinfo[i].dobj.namespace = NULL;
+ fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));+ fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));+ fdwinfo[i].dacl.privtype = 0;+ fdwinfo[i].dacl.initprivs = NULL;
fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
- fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));- fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));- fdwinfo[i].initfdwacl = pg_strdup(PQgetvalue(res, i, i_initfdwacl));- fdwinfo[i].initrfdwacl = pg_strdup(PQgetvalue(res, i, i_initrfdwacl));
/* Decide whether we want to dump it */
selectDumpableObject(&(fdwinfo[i].dobj), fout);
/* Mark whether FDW has an ACL */
- if (!(PQgetisnull(res, i, i_fdwacl) &&- PQgetisnull(res, i, i_rfdwacl) &&- PQgetisnull(res, i, i_initfdwacl) &&- PQgetisnull(res, i, i_initrfdwacl)))+ if (!PQgetisnull(res, i, i_fdwacl))
fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
}
@@ -9376,7 +9084,6 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
ForeignServerInfo *
getForeignServers(Archive *fout, int *numForeignServers)
{
- DumpOptions *dopt = fout->dopt;
PGresult *res;
int ntups;
int i;
@@ -9390,9 +9097,7 @@ getForeignServers(Archive *fout, int *numForeignServers)
int i_srvtype;
int i_srvversion;
int i_srvacl;
- int i_rsrvacl;- int i_initsrvacl;- int i_initrsrvacl;+ int i_acldefault;
int i_srvoptions;
/* Before 8.4, there are no foreign servers */
@@ -9404,53 +9109,27 @@ getForeignServers(Archive *fout, int *numForeignServers)
query = createPQExpBuffer();
- if (fout->remoteVersion >= 90600)+ if (fout->remoteVersion >= 90200)
{
- PQExpBuffer acl_subquery = createPQExpBuffer();- PQExpBuffer racl_subquery = createPQExpBuffer();- PQExpBuffer initacl_subquery = createPQExpBuffer();- PQExpBuffer initracl_subquery = createPQExpBuffer();-- buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,- initracl_subquery, "f.srvacl", "f.srvowner",- "pip.initprivs", "'S'", dopt->binary_upgrade);-- appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "- "(%s f.srvowner) AS rolname, "- "f.srvfdw, f.srvtype, f.srvversion, "- "%s AS srvacl, "- "%s AS rsrvacl, "- "%s AS initsrvacl, "- "%s AS initrsrvacl, "+ appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "+ "(%s srvowner) AS rolname, "+ "srvfdw, srvtype, srvversion, srvacl, "+ "acldefault('S', srvowner) AS acldefault, "
"array_to_string(ARRAY("
"SELECT quote_ident(option_name) || ' ' || "
"quote_literal(option_value) "
- "FROM pg_options_to_table(f.srvoptions) "+ "FROM pg_options_to_table(srvoptions) "
"ORDER BY option_name"
"), E',\n ') AS srvoptions "
- "FROM pg_foreign_server f "- "LEFT JOIN pg_init_privs pip "- "ON (f.oid = pip.objoid "- "AND pip.classoid = 'pg_foreign_server'::regclass "- "AND pip.objsubid = 0) ",- username_subquery,- acl_subquery->data,- racl_subquery->data,- initacl_subquery->data,- initracl_subquery->data);-- destroyPQExpBuffer(acl_subquery);- destroyPQExpBuffer(racl_subquery);- destroyPQExpBuffer(initacl_subquery);- destroyPQExpBuffer(initracl_subquery);+ "FROM pg_foreign_server",+ username_subquery);
}
else
{
appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
"(%s srvowner) AS rolname, "
"srvfdw, srvtype, srvversion, srvacl, "
- "NULL AS rsrvacl, "- "NULL AS initsrvacl, NULL AS initrsrvacl, "+ "NULL AS acldefault, "
"array_to_string(ARRAY("
"SELECT quote_ident(option_name) || ' ' || "
"quote_literal(option_value) "
@@ -9476,9 +9155,7 @@ getForeignServers(Archive *fout, int *numForeignServers)
i_srvtype = PQfnumber(res, "srvtype");
i_srvversion = PQfnumber(res, "srvversion");
i_srvacl = PQfnumber(res, "srvacl");
- i_rsrvacl = PQfnumber(res, "rsrvacl");- i_initsrvacl = PQfnumber(res, "initsrvacl");- i_initrsrvacl = PQfnumber(res, "initrsrvacl");+ i_acldefault = PQfnumber(res, "acldefault");
i_srvoptions = PQfnumber(res, "srvoptions");
for (i = 0; i < ntups; i++)
@@ -9489,15 +9166,15 @@ getForeignServers(Archive *fout, int *numForeignServers)
AssignDumpId(&srvinfo[i].dobj);
srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
srvinfo[i].dobj.namespace = NULL;
+ srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));+ srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));+ srvinfo[i].dacl.privtype = 0;+ srvinfo[i].dacl.initprivs = NULL;
srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
- srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));- srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));- srvinfo[i].initsrvacl = pg_strdup(PQgetvalue(res, i, i_initsrvacl));- srvinfo[i].initrsrvacl = pg_strdup(PQgetvalue(res, i, i_initrsrvacl));
/* Decide whether we want to dump it */
selectDumpableObject(&(srvinfo[i].dobj), fout);
@@ -9506,10 +9183,7 @@ getForeignServers(Archive *fout, int *numForeignServers)
srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
/* Mark whether server has an ACL */
- if (!(PQgetisnull(res, i, i_srvacl) &&- PQgetisnull(res, i, i_rsrvacl) &&- PQgetisnull(res, i, i_initsrvacl) &&- PQgetisnull(res, i, i_initrsrvacl)))+ if (!PQgetisnull(res, i, i_srvacl))
srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
}
@@ -9540,9 +9214,7 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)
int i_defaclnamespace;
int i_defaclobjtype;
int i_defaclacl;
- int i_rdefaclacl;- int i_initdefaclacl;- int i_initrdefaclacl;+ int i_acldefault;
int i,
ntups;
@@ -9554,13 +9226,16 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)
query = createPQExpBuffer();
- if (fout->remoteVersion >= 90600)- {- PQExpBuffer acl_subquery = createPQExpBuffer();- PQExpBuffer racl_subquery = createPQExpBuffer();- PQExpBuffer initacl_subquery = createPQExpBuffer();- PQExpBuffer initracl_subquery = createPQExpBuffer();+ appendPQExpBuffer(query,+ "SELECT oid, tableoid, "+ "(%s defaclrole) AS defaclrole, "+ "defaclnamespace, "+ "defaclobjtype, "+ "defaclacl, ",+ username_subquery);+ if (fout->remoteVersion >= 90200)+ {
/*
* Global entries (with defaclnamespace=0) replace the hard-wired
* default ACL for their object type. We should dump them as deltas
@@ -9568,59 +9243,24 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)
* for interpreting the ALTER DEFAULT PRIVILEGES commands. On the
* other hand, non-global entries can only add privileges not revoke
* them. We must dump those as-is (i.e., as deltas from an empty
- * ACL). We implement that by passing NULL as the object type for- * acldefault(), which works because acldefault() is STRICT.+ * ACL).
*
* We can use defaclobjtype as the object type for acldefault(),
* except for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be
* converted to 's'.
*/
- buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,- initracl_subquery, "defaclacl", "defaclrole",- "pip.initprivs",- "CASE WHEN defaclnamespace = 0 THEN"- " CASE WHEN defaclobjtype = 'S' THEN 's'::\"char\""- " ELSE defaclobjtype END "- "ELSE NULL END",- dopt->binary_upgrade);-- appendPQExpBuffer(query, "SELECT d.oid, d.tableoid, "- "(%s d.defaclrole) AS defaclrole, "- "d.defaclnamespace, "- "d.defaclobjtype, "- "%s AS defaclacl, "- "%s AS rdefaclacl, "- "%s AS initdefaclacl, "- "%s AS initrdefaclacl "- "FROM pg_default_acl d "- "LEFT JOIN pg_init_privs pip ON "- "(d.oid = pip.objoid "- "AND pip.classoid = 'pg_default_acl'::regclass "- "AND pip.objsubid = 0) ",- username_subquery,- acl_subquery->data,- racl_subquery->data,- initacl_subquery->data,- initracl_subquery->data);-- destroyPQExpBuffer(acl_subquery);- destroyPQExpBuffer(racl_subquery);- destroyPQExpBuffer(initacl_subquery);- destroyPQExpBuffer(initracl_subquery);+ appendPQExpBufferStr(query,+ "CASE WHEN defaclnamespace = 0 THEN "+ "acldefault(CASE WHEN defaclobjtype = 'S' "+ "THEN 's'::\"char\" ELSE defaclobjtype END, "+ "defaclrole) ELSE '{}' END AS acldefault ");
}
else
- {- appendPQExpBuffer(query, "SELECT oid, tableoid, "- "(%s defaclrole) AS defaclrole, "- "defaclnamespace, "- "defaclobjtype, "- "defaclacl, "- "NULL AS rdefaclacl, "- "NULL AS initdefaclacl, "- "NULL AS initrdefaclacl "- "FROM pg_default_acl",- username_subquery);- }+ appendPQExpBufferStr(query,+ "NULL AS acldefault ");++ appendPQExpBufferStr(query,+ "FROM pg_default_acl");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
@@ -9635,9 +9275,7 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)
i_defaclnamespace = PQfnumber(res, "defaclnamespace");
i_defaclobjtype = PQfnumber(res, "defaclobjtype");
i_defaclacl = PQfnumber(res, "defaclacl");
- i_rdefaclacl = PQfnumber(res, "rdefaclacl");- i_initdefaclacl = PQfnumber(res, "initdefaclacl");- i_initrdefaclacl = PQfnumber(res, "initrdefaclacl");+ i_acldefault = PQfnumber(res, "acldefault");
for (i = 0; i < ntups; i++)
{
@@ -9655,12 +9293,12 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)
else
daclinfo[i].dobj.namespace = NULL;
+ daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));+ daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));+ daclinfo[i].dacl.privtype = 0;+ daclinfo[i].dacl.initprivs = NULL;
daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
- daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));- daclinfo[i].rdefaclacl = pg_strdup(PQgetvalue(res, i, i_rdefaclacl));- daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));- daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));
/* Default ACLs are ACLs, of course */
daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
@@ -9676,6 +9314,126 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)
return daclinfo;
}
+/*+ * getAdditionalACLs+ *+ * We have now created all the DumpableObjects, and collected the ACL data+ * that appears in the directly-associated catalog entries. However, there's+ * more ACL-related info to collect. If any of a table's columns have ACLs,+ * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as+ * its hascolumnACLs flag (we won't store the ACLs themselves here, though).+ * Also, in versions having the pg_init_privs catalog, read that and load the+ * information into the relevant DumpableObjects.+ */+static void+getAdditionalACLs(Archive *fout)+{+ PQExpBuffer query = createPQExpBuffer();+ PGresult *res;+ int ntups,+ i;++ /* Check for per-column ACLs */+ if (fout->remoteVersion >= 80400)+ {+ appendPQExpBufferStr(query,+ "SELECT DISTINCT attrelid FROM pg_attribute "+ "WHERE attacl IS NOT NULL");++ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);++ ntups = PQntuples(res);+ for (i = 0; i < ntups; i++)+ {+ Oid relid = atooid(PQgetvalue(res, i, 0));+ TableInfo *tblinfo;++ tblinfo = findTableByOid(relid);+ /* OK to ignore tables we haven't got a DumpableObject for */+ if (tblinfo)+ {+ tblinfo->dobj.components |= DUMP_COMPONENT_ACL;+ tblinfo->hascolumnACLs = true;+ }+ }+ PQclear(res);+ }++ /* Fetch initial-privileges data */+ if (fout->remoteVersion >= 90600)+ {+ printfPQExpBuffer(query,+ "SELECT objoid, classoid, objsubid, privtype, initprivs "+ "FROM pg_init_privs");++ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);++ ntups = PQntuples(res);+ for (i = 0; i < ntups; i++)+ {+ Oid objoid = atooid(PQgetvalue(res, i, 0));+ Oid classoid = atooid(PQgetvalue(res, i, 1));+ int objsubid = atoi(PQgetvalue(res, i, 2));+ char privtype = *(PQgetvalue(res, i, 3));+ char *initprivs = PQgetvalue(res, i, 4);+ CatalogId objId;+ DumpableObject *dobj;++ objId.tableoid = classoid;+ objId.oid = objoid;+ dobj = findObjectByCatalogId(objId);+ /* OK to ignore entries we haven't got a DumpableObject for */+ if (dobj)+ {+ /* Cope with sub-object initprivs */+ if (objsubid != 0)+ {+ if (dobj->objType == DO_TABLE)+ {+ /* For a column initpriv, set the table's ACL flags */+ dobj->components |= DUMP_COMPONENT_ACL;+ ((TableInfo *) dobj)->hascolumnACLs = true;+ }+ else+ pg_log_warning("unsupported pg_init_privs entry: %u %u %d",+ classoid, objoid, objsubid);+ continue;+ }++ /*+ * We ignore any pg_init_privs.initprivs entry for the public+ * schema, as explained in getNamespaces().+ */+ if (dobj->objType == DO_NAMESPACE &&+ strcmp(dobj->name, "public") == 0)+ continue;++ /* Else it had better be of a type we think has ACLs */+ if (dobj->objType == DO_NAMESPACE ||+ dobj->objType == DO_TYPE ||+ dobj->objType == DO_FUNC ||+ dobj->objType == DO_AGG ||+ dobj->objType == DO_TABLE ||+ dobj->objType == DO_PROCLANG ||+ dobj->objType == DO_FDW ||+ dobj->objType == DO_FOREIGN_SERVER)+ {+ DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;++ daobj->dacl.privtype = privtype;+ daobj->dacl.initprivs = pstrdup(initprivs);+ }+ else+ pg_log_warning("unsupported pg_init_privs entry: %u %u %d",+ classoid, objoid, objsubid);+ }+ }+ PQclear(res);+ }++ destroyPQExpBuffer(query);+}+
/*
* dumpCommentExtended --
*
@@ -10324,8 +10082,7 @@ dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
qnspname, NULL, NULL,
- nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,- nspinfo->initnspacl, nspinfo->initrnspacl);+ nspinfo->rolname, &nspinfo->dacl);
free(qnspname);
@@ -10616,8 +10373,7 @@ dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
qtypname, NULL,
tyinfo->dobj.namespace->dobj.name,
- tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,- tyinfo->inittypacl, tyinfo->initrtypacl);+ tyinfo->rolname, &tyinfo->dacl);
PQclear(res);
destroyPQExpBuffer(q);
@@ -10756,8 +10512,7 @@ dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
qtypname, NULL,
tyinfo->dobj.namespace->dobj.name,
- tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,- tyinfo->inittypacl, tyinfo->initrtypacl);+ tyinfo->rolname, &tyinfo->dacl);
PQclear(res);
destroyPQExpBuffer(q);
@@ -10828,8 +10583,7 @@ dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
qtypname, NULL,
tyinfo->dobj.namespace->dobj.name,
- tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,- tyinfo->inittypacl, tyinfo->initrtypacl);+ tyinfo->rolname, &tyinfo->dacl);
destroyPQExpBuffer(q);
destroyPQExpBuffer(delq);
@@ -11088,8 +10842,7 @@ dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
qtypname, NULL,
tyinfo->dobj.namespace->dobj.name,
- tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,- tyinfo->inittypacl, tyinfo->initrtypacl);+ tyinfo->rolname, &tyinfo->dacl);
PQclear(res);
destroyPQExpBuffer(q);
@@ -11245,8 +10998,7 @@ dumpDomain(Archive *fout, const TypeInfo *tyinfo)
dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
qtypname, NULL,
tyinfo->dobj.namespace->dobj.name,
- tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,- tyinfo->inittypacl, tyinfo->initrtypacl);+ tyinfo->rolname, &tyinfo->dacl);
/* Dump any per-constraint comments */
for (i = 0; i < tyinfo->nDomChecks; i++)
@@ -11467,8 +11219,7 @@ dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
qtypname, NULL,
tyinfo->dobj.namespace->dobj.name,
- tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,- tyinfo->inittypacl, tyinfo->initrtypacl);+ tyinfo->rolname, &tyinfo->dacl);
PQclear(res);
destroyPQExpBuffer(q);
@@ -11766,8 +11517,7 @@ dumpProcLang(Archive *fout, const ProcLangInfo *plang)
if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
qlanname, NULL, NULL,
- plang->lanowner, plang->lanacl, plang->rlanacl,- plang->initlanacl, plang->initrlanacl);+ plang->lanowner, &plang->dacl);
free(qlanname);
@@ -12403,8 +12153,7 @@ dumpFunc(Archive *fout, const FuncInfo *finfo)
dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
funcsig, NULL,
finfo->dobj.namespace->dobj.name,
- finfo->rolname, finfo->proacl, finfo->rproacl,- finfo->initproacl, finfo->initrproacl);+ finfo->rolname, &finfo->dacl);
PQclear(res);
@@ -14308,9 +14057,7 @@ dumpAgg(Archive *fout, const AggInfo *agginfo)
dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
"FUNCTION", aggsig, NULL,
agginfo->aggfn.dobj.namespace->dobj.name,
- agginfo->aggfn.rolname, agginfo->aggfn.proacl,- agginfo->aggfn.rproacl,- agginfo->aggfn.initproacl, agginfo->aggfn.initrproacl);+ agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
free(aggsig);
if (aggfullsig)
@@ -14709,9 +14456,7 @@ dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
"FOREIGN DATA WRAPPER", qfdwname, NULL,
- NULL, fdwinfo->rolname,- fdwinfo->fdwacl, fdwinfo->rfdwacl,- fdwinfo->initfdwacl, fdwinfo->initrfdwacl);+ NULL, fdwinfo->rolname, &fdwinfo->dacl);
free(qfdwname);
@@ -14798,9 +14543,7 @@ dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
"FOREIGN SERVER", qsrvname, NULL,
- NULL, srvinfo->rolname,- srvinfo->srvacl, srvinfo->rsrvacl,- srvinfo->initsrvacl, srvinfo->initrsrvacl);+ NULL, srvinfo->rolname, &srvinfo->dacl);
/* Dump user mappings */
if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
@@ -14964,15 +14707,13 @@ dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
if (!buildDefaultACLCommands(type,
daclinfo->dobj.namespace != NULL ?
daclinfo->dobj.namespace->dobj.name : NULL,
- daclinfo->defaclacl,- daclinfo->rdefaclacl,- daclinfo->initdefaclacl,- daclinfo->initrdefaclacl,+ daclinfo->dacl.acl,+ daclinfo->dacl.acldefault,
daclinfo->defaclrole,
fout->remoteVersion,
q))
fatal("could not parse default ACL list (%s)",
- daclinfo->defaclacl);+ daclinfo->dacl.acl);
if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
@@ -15002,20 +14743,7 @@ dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
* (Currently we assume that subname is only provided for table columns.)
* 'nspname' is the namespace the object is in (NULL if none).
* 'owner' is the owner, NULL if there is no owner (for languages).
- * 'acls' contains the ACL string of the object from the appropriate system- * catalog field; it will be passed to buildACLCommands for building the- * appropriate GRANT commands.- * 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the- * object; it will be passed to buildACLCommands for building the- * appropriate REVOKE commands.- * 'initacls' In binary-upgrade mode, ACL string of the object's initial- * privileges, to be recorded into pg_init_privs- * 'initracls' In binary-upgrade mode, ACL string of the object's- * revoked-from-default privileges, to be recorded into pg_init_privs- *- * NB: initacls/initracls are needed because extensions can set privileges on- * an object during the extension's script file and we record those into- * pg_init_privs as that object's initial privileges.+ * 'dacl' is the DumpableAcl struct fpr the object.
*
* Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
* no ACL entry was created.
@@ -15025,11 +14753,15 @@ static DumpId
dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
const char *type, const char *name, const char *subname,
const char *nspname, const char *owner,
- const char *acls, const char *racls,- const char *initacls, const char *initracls)+ const DumpableAcl *dacl)
{
DumpId aclDumpId = InvalidDumpId;
DumpOptions *dopt = fout->dopt;
+ const char *acls = dacl->acl;+ const char *acldefault = dacl->acldefault;+ char privtype = dacl->privtype;+ const char *initprivs = dacl->initprivs;+ const char *baseacls;
PQExpBuffer sql;
/* Do nothing if ACL dump is not enabled */
@@ -15043,29 +14775,52 @@ dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
sql = createPQExpBuffer();
/*
- * Check to see if this object has had any initial ACLs included for it.- * If so, we are in binary upgrade mode and these are the ACLs to turn- * into GRANT and REVOKE statements to set and record the initial- * privileges for an extension object. Let the backend know that these- * are to be recorded by calling binary_upgrade_set_record_init_privs()- * before and after.+ * In binary upgrade mode, we don't run an extension's script but instead+ * dump out the objects independently and then recreate them. To preserve+ * any initial privileges which were set on extension objects, we need to+ * compute the set of GRANT and REVOKE commands necessary to get from the+ * default privileges of an object to its initial privileges as recorded+ * in pg_init_privs.+ *+ * At restore time, we apply these commands after having called+ * binary_upgrade_set_record_init_privs(true). That tells the backend to+ * copy the results into pg_init_privs. This is how we preserve the+ * contents of that catalog across binary upgrades.
*/
- if (strlen(initacls) != 0 || strlen(initracls) != 0)+ if (dopt->binary_upgrade && privtype == 'e' &&+ initprivs && *initprivs != '\0')
{
appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
if (!buildACLCommands(name, subname, nspname, type,
- initacls, initracls, owner,+ initprivs, acldefault, owner,
"", fout->remoteVersion, sql))
- fatal("could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)",- initacls, initracls, name, type);+ fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",+ initprivs, acldefault, name, type);
appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
}
+ /*+ * Now figure the GRANT and REVOKE commands needed to get to the object's+ * actual current ACL, starting from the initprivs if given, else from the+ * object-type-specific default. Also, while buildACLCommands will assume+ * that a NULL/empty acls string means it needn't do anything, what that+ * actually represents is the object-type-specific default; so we need to+ * substitute the acldefault string to get the right results in that case.+ */+ if (initprivs && *initprivs != '\0')+ {+ baseacls = initprivs;+ if (acls == NULL || *acls == '\0')+ acls = acldefault;+ }+ else+ baseacls = acldefault;+
if (!buildACLCommands(name, subname, nspname, type,
- acls, racls, owner,+ acls, baseacls, owner,
"", fout->remoteVersion, sql))
- fatal("could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)",- acls, racls, name, type);+ fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",+ acls, baseacls, name, type);
if (sql->len > 0)
{
@@ -15475,8 +15230,7 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
objtype, namecopy, NULL,
tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
- tbinfo->relacl, tbinfo->rrelacl,- tbinfo->initrelacl, tbinfo->initrrelacl);+ &tbinfo->dacl);
}
/*
@@ -15485,7 +15239,7 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
* miss ACLs on system columns. Doing it this way also allows us to dump
* ACLs for catalogs that we didn't mark "interesting" back in getTables.
*/
- if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)+ if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
{
PQExpBuffer query = createPQExpBuffer();
PGresult *res;
@@ -15493,55 +15247,37 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
if (fout->remoteVersion >= 90600)
{
- PQExpBuffer acl_subquery = createPQExpBuffer();- PQExpBuffer racl_subquery = createPQExpBuffer();- PQExpBuffer initacl_subquery = createPQExpBuffer();- PQExpBuffer initracl_subquery = createPQExpBuffer();-- buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,- initracl_subquery, "at.attacl", "c.relowner",- "pip.initprivs", "'c'", dopt->binary_upgrade);-+ /*+ * In principle we should call acldefault('c', relowner) to get+ * the default ACL for a column. However, we don't currently+ * store the numeric OID of the relowner in TableInfo. We could+ * convert the owner name using regrole, but that creates a risk+ * of failure due to concurrent role renames. Given that the+ * default ACL for columns is empty and is likely to stay that+ * way, it's not worth extra cycles and risk to avoid hard-wiring+ * that knowledge here.+ */
appendPQExpBuffer(query,
"SELECT at.attname, "
- "%s AS attacl, "- "%s AS rattacl, "- "%s AS initattacl, "- "%s AS initrattacl "+ "at.attacl, "+ "'{}' AS acldefault, "+ "pip.privtype, pip.initprivs "
"FROM pg_catalog.pg_attribute at "
- "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
"LEFT JOIN pg_catalog.pg_init_privs pip ON "
"(at.attrelid = pip.objoid "
"AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
"AND at.attnum = pip.objsubid) "
"WHERE at.attrelid = '%u'::pg_catalog.oid AND "
"NOT at.attisdropped "
- "AND ("- "%s IS NOT NULL OR "- "%s IS NOT NULL OR "- "%s IS NOT NULL OR "- "%s IS NOT NULL)"+ "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
"ORDER BY at.attnum",
- acl_subquery->data,- racl_subquery->data,- initacl_subquery->data,- initracl_subquery->data,- tbinfo->dobj.catId.oid,- acl_subquery->data,- racl_subquery->data,- initacl_subquery->data,- initracl_subquery->data);-- destroyPQExpBuffer(acl_subquery);- destroyPQExpBuffer(racl_subquery);- destroyPQExpBuffer(initacl_subquery);- destroyPQExpBuffer(initracl_subquery);+ tbinfo->dobj.catId.oid);
}
else
{
appendPQExpBuffer(query,
- "SELECT attname, attacl, NULL as rattacl, "- "NULL AS initattacl, NULL AS initrattacl "+ "SELECT attname, attacl, '{}' AS acldefault, "+ "NULL AS privtype, NULL AS initprivs "
"FROM pg_catalog.pg_attribute "
"WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped "
"AND attacl IS NOT NULL "
@@ -15555,11 +15291,16 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
{
char *attname = PQgetvalue(res, i, 0);
char *attacl = PQgetvalue(res, i, 1);
- char *rattacl = PQgetvalue(res, i, 2);- char *initattacl = PQgetvalue(res, i, 3);- char *initrattacl = PQgetvalue(res, i, 4);+ char *acldefault = PQgetvalue(res, i, 2);+ char privtype = *(PQgetvalue(res, i, 3));+ char *initprivs = PQgetvalue(res, i, 4);+ DumpableAcl coldacl;
char *attnamecopy;
+ coldacl.acl = attacl;+ coldacl.acldefault = acldefault;+ coldacl.privtype = privtype;+ coldacl.initprivs = initprivs;
attnamecopy = pg_strdup(fmtId(attname));
/*
@@ -15570,7 +15311,7 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
"TABLE", namecopy, attnamecopy,
tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
- attacl, rattacl, initattacl, initrattacl);+ &coldacl);
free(attnamecopy);
}
PQclear(res);
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.hindex 3db73f710c..e3b864f6ba 100644--- a/src/bin/pg_dump/pg_dump.h+++ b/src/bin/pg_dump/pg_dump.h@@ -145,16 +145,36 @@ typedef struct _dumpableObject
int allocDeps; /* allocated size of dependencies[] */
} DumpableObject;
+/*+ * Object types that have ACLs must store them in a DumpableAcl sub-struct,+ * which must immediately follow the DumpableObject base struct.+ *+ * Note: when dumping from a pre-9.2 server, which lacks the acldefault()+ * function, acldefault will be NULL or empty.+ */+typedef struct _dumpableAcl+{+ char *acl; /* the object's actual ACL string */+ char *acldefault; /* default ACL for the object's type & owner */+ /* these fields come from the object's pg_init_privs entry, if any: */+ char privtype; /* entry type, 'i' or 'e'; 0 if no entry */+ char *initprivs; /* the object's initial ACL string, or NULL */+} DumpableAcl;++/* Generic struct that can be used to access any object type having an ACL */+typedef struct _dumpableObjectWithAcl+{+ DumpableObject dobj;+ DumpableAcl dacl;+} DumpableObjectWithAcl;+
typedef struct _namespaceInfo
{
DumpableObject dobj;
+ DumpableAcl dacl;
bool create; /* CREATE SCHEMA, or just set owner? */
Oid nspowner;
char *rolname; /* name of owner, or empty string */
- char *nspacl;- char *rnspacl;- char *initnspacl;- char *initrnspacl;
} NamespaceInfo;
typedef struct _extensionInfo
@@ -170,6 +190,7 @@ typedef struct _extensionInfo
typedef struct _typeInfo
{
DumpableObject dobj;
+ DumpableAcl dacl;
/*
* Note: dobj.name is the raw pg_type.typname entry. ftypname is the
@@ -178,10 +199,6 @@ typedef struct _typeInfo
*/
char *ftypname;
char *rolname; /* name of owner, or empty string */
- char *typacl;- char *rtypacl;- char *inittypacl;- char *initrtypacl;
Oid typelem;
Oid typrelid;
char typrelkind; /* 'r', 'v', 'c', etc */
@@ -206,15 +223,12 @@ typedef struct _shellTypeInfo
typedef struct _funcInfo
{
DumpableObject dobj;
+ DumpableAcl dacl;
char *rolname; /* name of owner, or empty string */
Oid lang;
int nargs;
Oid *argtypes;
Oid prorettype;
- char *proacl;- char *rproacl;- char *initproacl;- char *initrproacl;
} FuncInfo;
/* AggInfo is a superset of FuncInfo */
@@ -269,11 +283,8 @@ typedef struct _tableInfo
* These fields are collected for every table in the database.
*/
DumpableObject dobj;
+ DumpableAcl dacl;
char *rolname; /* name of owner, or empty string */
- char *relacl;- char *rrelacl;- char *initrelacl;- char *initrrelacl;
char relkind;
char relpersistence; /* relation persistence */
bool relispopulated; /* relation is populated */
@@ -285,6 +296,7 @@ typedef struct _tableInfo
bool hasindex; /* does it have any indexes? */
bool hasrules; /* does it have any rules? */
bool hastriggers; /* does it have any triggers? */
+ bool hascolumnACLs; /* do any columns have non-default ACLs? */
bool rowsec; /* is row security enabled? */
bool forcerowsec; /* is row security forced? */
bool hasoids; /* does it have OIDs? */
@@ -477,14 +489,11 @@ typedef struct _constraintInfo
typedef struct _procLangInfo
{
DumpableObject dobj;
+ DumpableAcl dacl;
bool lanpltrusted;
Oid lanplcallfoid;
Oid laninline;
Oid lanvalidator;
- char *lanacl;- char *rlanacl;- char *initlanacl;- char *initrlanacl;
char *lanowner; /* name of owner, or empty string */
} ProcLangInfo;
@@ -549,49 +558,37 @@ typedef struct _cfgInfo
typedef struct _fdwInfo
{
DumpableObject dobj;
+ DumpableAcl dacl;
char *rolname;
char *fdwhandler;
char *fdwvalidator;
char *fdwoptions;
- char *fdwacl;- char *rfdwacl;- char *initfdwacl;- char *initrfdwacl;
} FdwInfo;
typedef struct _foreignServerInfo
{
DumpableObject dobj;
+ DumpableAcl dacl;
char *rolname;
Oid srvfdw;
char *srvtype;
char *srvversion;
- char *srvacl;- char *rsrvacl;- char *initsrvacl;- char *initrsrvacl;
char *srvoptions;
} ForeignServerInfo;
typedef struct _defaultACLInfo
{
DumpableObject dobj;
+ DumpableAcl dacl;
char *defaclrole;
char defaclobjtype;
- char *defaclacl;- char *rdefaclacl;- char *initdefaclacl;- char *initrdefaclacl;
} DefaultACLInfo;
typedef struct _blobInfo
{
DumpableObject dobj;
+ DumpableAcl dacl;
char *rolname;
- char *blobacl;- char *rblobacl;- char *initblobacl;- char *initrblobacl;
} BlobInfo;
/*
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.cindex c29101704a..44114f3f71 100644--- a/src/bin/pg_dump/pg_dumpall.c+++ b/src/bin/pg_dump/pg_dumpall.c@@ -1166,55 +1166,12 @@ dumpTablespaces(PGconn *conn)
/*
* Get all tablespaces except built-in ones (which we assume are named
* pg_xxx)
- *- * For the tablespace ACLs, as of 9.6, we extract both the positive (as- * spcacl) and negative (as rspcacl) ACLs, relative to the default ACL for- * tablespaces, which are then passed to buildACLCommands() below.- *- * See buildACLQueries() and buildACLCommands().- *- * The order in which privileges are in the ACL string (the order they- * have been GRANT'd in, which the backend maintains) must be preserved to- * ensure that GRANTs WITH GRANT OPTION and subsequent GRANTs based on- * those are dumped in the correct order.- *- * Note that we do not support initial privileges (pg_init_privs) on- * tablespaces, so this logic cannot make use of buildACLQueries().
*/
- if (server_version >= 90600)- res = executeQuery(conn, "SELECT oid, spcname, "- "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "- "pg_catalog.pg_tablespace_location(oid), "- "(SELECT array_agg(acl ORDER BY row_n) FROM "- " (SELECT acl, row_n FROM "- " unnest(coalesce(spcacl,acldefault('t',spcowner))) "- " WITH ORDINALITY AS perm(acl,row_n) "- " WHERE NOT EXISTS ( "- " SELECT 1 "- " FROM unnest(acldefault('t',spcowner)) "- " AS init(init_acl) "- " WHERE acl = init_acl)) AS spcacls) "- " AS spcacl, "- "(SELECT array_agg(acl ORDER BY row_n) FROM "- " (SELECT acl, row_n FROM "- " unnest(acldefault('t',spcowner)) "- " WITH ORDINALITY AS initp(acl,row_n) "- " WHERE NOT EXISTS ( "- " SELECT 1 "- " FROM unnest(coalesce(spcacl,acldefault('t',spcowner))) "- " AS permp(orig_acl) "- " WHERE acl = orig_acl)) AS rspcacls) "- " AS rspcacl, "- "array_to_string(spcoptions, ', '),"- "pg_catalog.shobj_description(oid, 'pg_tablespace') "- "FROM pg_catalog.pg_tablespace "- "WHERE spcname !~ '^pg_' "- "ORDER BY 1");- else if (server_version >= 90200)+ if (server_version >= 90200)
res = executeQuery(conn, "SELECT oid, spcname, "
"pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
"pg_catalog.pg_tablespace_location(oid), "
- "spcacl, '' as rspcacl, "+ "spcacl, acldefault('t', spcowner) AS acldefault, "
"array_to_string(spcoptions, ', '),"
"pg_catalog.shobj_description(oid, 'pg_tablespace') "
"FROM pg_catalog.pg_tablespace "
@@ -1223,7 +1180,7 @@ dumpTablespaces(PGconn *conn)
else if (server_version >= 90000)
res = executeQuery(conn, "SELECT oid, spcname, "
"pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
- "spclocation, spcacl, '' as rspcacl, "+ "spclocation, spcacl, NULL AS acldefault, "
"array_to_string(spcoptions, ', '),"
"pg_catalog.shobj_description(oid, 'pg_tablespace') "
"FROM pg_catalog.pg_tablespace "
@@ -1232,7 +1189,7 @@ dumpTablespaces(PGconn *conn)
else if (server_version >= 80200)
res = executeQuery(conn, "SELECT oid, spcname, "
"pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
- "spclocation, spcacl, '' as rspcacl, null, "+ "spclocation, spcacl, NULL AS acldefault, null, "
"pg_catalog.shobj_description(oid, 'pg_tablespace') "
"FROM pg_catalog.pg_tablespace "
"WHERE spcname !~ '^pg_' "
@@ -1240,7 +1197,7 @@ dumpTablespaces(PGconn *conn)
else
res = executeQuery(conn, "SELECT oid, spcname, "
"pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
- "spclocation, spcacl, '' as rspcacl, "+ "spclocation, spcacl, NULL AS acldefault, "
"null, null "
"FROM pg_catalog.pg_tablespace "
"WHERE spcname !~ '^pg_' "
@@ -1257,7 +1214,7 @@ dumpTablespaces(PGconn *conn)
char *spcowner = PQgetvalue(res, i, 2);
char *spclocation = PQgetvalue(res, i, 3);
char *spcacl = PQgetvalue(res, i, 4);
- char *rspcacl = PQgetvalue(res, i, 5);+ char *acldefault = PQgetvalue(res, i, 5);
char *spcoptions = PQgetvalue(res, i, 6);
char *spccomment = PQgetvalue(res, i, 7);
char *fspcname;
@@ -1276,9 +1233,11 @@ dumpTablespaces(PGconn *conn)
appendPQExpBuffer(buf, "ALTER TABLESPACE %s SET (%s);\n",
fspcname, spcoptions);
+ /* tablespaces can't have initprivs */+
if (!skip_acls &&
!buildACLCommands(fspcname, NULL, NULL, "TABLESPACE",
- spcacl, rspcacl,+ spcacl, acldefault,
spcowner, "", server_version, buf))
{
pg_log_error("could not parse ACL list (%s) for tablespace \"%s\"",
diff --git a/src/fe_utils/string_utils.c b/src/fe_utils/string_utils.cindex 3efee4e7ee..81e623602e 100644--- a/src/fe_utils/string_utils.c+++ b/src/fe_utils/string_utils.c@@ -726,6 +726,69 @@ parsePGArray(const char *atext, char ***itemarray, int *nitems)
}
+/*+ * Append one element to the text representation of a 1-dimensional Postgres+ * array.+ *+ * The caller must provide the initial '{' and closing '}' of the array.+ * This function handles all else, including insertion of commas and+ * quoting of values.+ *+ * We assume that typdelim is ','.+ */+void+appendPGArray(PQExpBuffer buffer, const char *value)+{+ bool needquote;+ const char *tmp;++ if (buffer->data[buffer->len - 1] != '{')+ appendPQExpBufferChar(buffer, ',');++ /* Decide if we need quotes; this should match array_out()'s choices. */+ if (value[0] == '\0')+ needquote = true; /* force quotes for empty string */+ else if (pg_strcasecmp(value, "NULL") == 0)+ needquote = true; /* force quotes for literal NULL */+ else+ needquote = false;++ if (!needquote)+ {+ for (tmp = value; *tmp; tmp++)+ {+ char ch = *tmp;++ if (ch == '"' || ch == '\\' ||+ ch == '{' || ch == '}' || ch == ',' ||+ /* these match array_isspace(): */+ ch == ' ' || ch == '\t' || ch == '\n' ||+ ch == '\r' || ch == '\v' || ch == '\f')+ {+ needquote = true;+ break;+ }+ }+ }++ if (needquote)+ {+ appendPQExpBufferChar(buffer, '"');+ for (tmp = value; *tmp; tmp++)+ {+ char ch = *tmp;++ if (ch == '"' || ch == '\\')+ appendPQExpBufferChar(buffer, '\\');+ appendPQExpBufferChar(buffer, ch);+ }+ appendPQExpBufferChar(buffer, '"');+ }+ else+ appendPQExpBufferStr(buffer, value);+}++
/*
* Format a reloptions array and append it to the given buffer.
*
diff --git a/src/include/fe_utils/string_utils.h b/src/include/fe_utils/string_utils.hindex caafb97d29..e12e61cddb 100644--- a/src/include/fe_utils/string_utils.h+++ b/src/include/fe_utils/string_utils.h@@ -46,6 +46,7 @@ extern void appendConnStrVal(PQExpBuffer buf, const char *str);
extern void appendPsqlMetaConnect(PQExpBuffer buf, const char *dbname);
extern bool parsePGArray(const char *atext, char ***itemarray, int *nitems);
+extern void appendPGArray(PQExpBuffer buffer, const char *value);
extern bool appendReloptionsArray(PQExpBuffer buffer, const char *reloptions,
const char *prefix, int encoding, bool std_strings);
[text/x-diff] 0003-move-unsafe-function-calls-2.patch (10.0K, ../177444.1635287465@sss.pgh.pa.us/4-0003-move-unsafe-function-calls-2.patch)
download | inline diff:diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.cindex 607abb97d3..d6075133a1 100644--- a/src/bin/pg_dump/pg_dump.c+++ b/src/bin/pg_dump/pg_dump.c@@ -6110,20 +6110,23 @@ getTables(Archive *fout, int *numTables)
int i_is_identity_sequence;
int i_relacl;
int i_acldefault;
- int i_partkeydef;
int i_ispartition;
- int i_partbound;
/*
* Find all the tables and table-like objects.
*
+ * We must fetch all tables in this phase because otherwise we cannot+ * correctly identify inherited columns, owned sequences, etc.+ *
* We include system catalogs, so that we can work if a user table is
* defined to inherit from a system catalog (pretty weird, but...)
*
* Note: in this phase we should collect only a minimal amount of
* information about each table, basically just enough to decide if it is
- * interesting. We must fetch all tables in this phase because otherwise- * we cannot correctly identify inherited columns, owned sequences, etc.+ * interesting. In particular, since we do not yet have lock on any user+ * table, we MUST NOT invoke any server-side data collection functions+ * (for instance, pg_get_partkeydef()). Those are likely to fail or give+ * wrong answers if any concurrent DDL is happening.
*/
appendPQExpBuffer(query,
@@ -6217,10 +6220,10 @@ getTables(Archive *fout, int *numTables)
if (fout->remoteVersion >= 90000)
appendPQExpBufferStr(query,
- "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, ");+ "c.reloftype, ");
else
appendPQExpBufferStr(query,
- "NULL AS reloftype, ");+ "0 AS reloftype, ");
if (fout->remoteVersion >= 90100)
appendPQExpBufferStr(query,
@@ -6261,14 +6264,10 @@ getTables(Archive *fout, int *numTables)
if (fout->remoteVersion >= 100000)
appendPQExpBufferStr(query,
- "pg_get_partkeydef(c.oid) AS partkeydef, "- "c.relispartition AS ispartition, "- "pg_get_expr(c.relpartbound, c.oid) AS partbound ");+ "c.relispartition AS ispartition ");
else
appendPQExpBufferStr(query,
- "NULL AS partkeydef, "- "false AS ispartition, "- "NULL AS partbound ");+ "false AS ispartition ");
/*
* Left join to pg_depend to pick up dependency info linking sequences to
@@ -6377,9 +6376,7 @@ getTables(Archive *fout, int *numTables)
i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
i_relacl = PQfnumber(res, "relacl");
i_acldefault = PQfnumber(res, "acldefault");
- i_partkeydef = PQfnumber(res, "partkeydef");
i_ispartition = PQfnumber(res, "ispartition");
- i_partbound = PQfnumber(res, "partbound");
if (dopt->lockWaitTimeout)
{
@@ -6445,19 +6442,14 @@ getTables(Archive *fout, int *numTables)
else
tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
- if (PQgetisnull(res, i, i_reloftype))- tblinfo[i].reloftype = NULL;- else- tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));+ tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
if (PQgetisnull(res, i, i_amname))
tblinfo[i].amname = NULL;
else
tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
- tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
- tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
/* other fields were zeroed above */
@@ -15485,12 +15477,34 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
}
else
{
+ char *partkeydef = NULL;
char *ftoptions = NULL;
char *srvname = NULL;
char *foreign = "";
+ /*+ * Set reltypename, and collect any relkind-specific data that we+ * didn't fetch during getTables().+ */
switch (tbinfo->relkind)
{
+ case RELKIND_PARTITIONED_TABLE:+ {+ PQExpBuffer query = createPQExpBuffer();+ PGresult *res;++ reltypename = "TABLE";++ /* retrieve partition key definition */+ appendPQExpBuffer(query,+ "SELECT pg_get_partkeydef('%u')",+ tbinfo->dobj.catId.oid);+ res = ExecuteSqlQueryForSingleRow(fout, query->data);+ partkeydef = pg_strdup(PQgetvalue(res, 0, 0));+ PQclear(res);+ destroyPQExpBuffer(query);+ break;+ }
case RELKIND_FOREIGN_TABLE:
{
PQExpBuffer query = createPQExpBuffer();
@@ -15530,6 +15544,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
break;
default:
reltypename = "TABLE";
+ break;
}
numParents = tbinfo->numParents;
@@ -15551,8 +15566,10 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
* Attach to type, if reloftype; except in case of a binary upgrade,
* we dump the table normally and attach it to the type afterward.
*/
- if (tbinfo->reloftype && !dopt->binary_upgrade)- appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);+ if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)+ appendPQExpBuffer(q, " OF %s",+ getFormattedTypeName(fout, tbinfo->reloftype,+ zeroIsError));
if (tbinfo->relkind != RELKIND_MATVIEW)
{
@@ -15590,7 +15607,8 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
* Skip column if fully defined by reloftype, except in
* binary upgrade
*/
- if (tbinfo->reloftype && !print_default && !print_notnull &&+ if (OidIsValid(tbinfo->reloftype) &&+ !print_default && !print_notnull &&
!dopt->binary_upgrade)
continue;
@@ -15623,7 +15641,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
* table ('OF type_name'), but in binary-upgrade mode,
* print it in that case too.
*/
- if (dopt->binary_upgrade || !tbinfo->reloftype)+ if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
{
appendPQExpBuffer(q, " %s",
tbinfo->atttypnames[j]);
@@ -15686,7 +15704,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
if (actual_atts)
appendPQExpBufferStr(q, "\n)");
- else if (!(tbinfo->reloftype && !dopt->binary_upgrade))+ else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
{
/*
* No attributes? we must have a parenthesized attribute list,
@@ -15715,7 +15733,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
}
if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
- appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);+ appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
@@ -15898,12 +15916,13 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
}
}
- if (tbinfo->reloftype)+ if (OidIsValid(tbinfo->reloftype))
{
appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
qualrelname,
- tbinfo->reloftype);+ getFormattedTypeName(fout, tbinfo->reloftype,+ zeroIsError));
}
}
@@ -16076,6 +16095,8 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
tbinfo->attfdwoptions[j]);
} /* end loop over columns */
+ if (partkeydef)+ free(partkeydef);
if (ftoptions)
free(ftoptions);
if (srvname)
@@ -16183,6 +16204,8 @@ dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
{
DumpOptions *dopt = fout->dopt;
PQExpBuffer q;
+ PGresult *res;+ char *partbound;
/* Do nothing in data-only dump */
if (dopt->dataOnly)
@@ -16193,14 +16216,23 @@ dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
q = createPQExpBuffer();
- /* Perform ALTER TABLE on the parent */+ /* Fetch the partition's partbound */
appendPQExpBuffer(q,
+ "SELECT pg_get_expr(c.relpartbound, c.oid) "+ "FROM pg_class c "+ "WHERE c.oid = '%u'",+ attachinfo->partitionTbl->dobj.catId.oid);+ res = ExecuteSqlQueryForSingleRow(fout, q->data);+ partbound = PQgetvalue(res, 0, 0);++ /* Perform ALTER TABLE on the parent */+ printfPQExpBuffer(q,
"ALTER TABLE ONLY %s ",
fmtQualifiedDumpable(attachinfo->parentTbl));
appendPQExpBuffer(q,
"ATTACH PARTITION %s %s;\n",
fmtQualifiedDumpable(attachinfo->partitionTbl),
- attachinfo->partitionTbl->partbound);+ partbound);
/*
* There is no point in creating a drop query as the drop is done by table
@@ -16217,6 +16249,7 @@ dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
.section = SECTION_PRE_DATA,
.createStmt = q->data));
+ PQclear(res);
destroyPQExpBuffer(q);
}
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.hindex e3b864f6ba..9061812c08 100644--- a/src/bin/pg_dump/pg_dump.h+++ b/src/bin/pg_dump/pg_dump.h@@ -307,7 +307,7 @@ typedef struct _tableInfo
uint32 toast_minmxid; /* toast table's relminmxid */
int ncheck; /* # of CHECK expressions */
Oid reltype; /* OID of table's composite type, if any */
- char *reloftype; /* underlying type for typed table */+ Oid reloftype; /* underlying type for typed table */
Oid foreign_server; /* foreign server oid, if applicable */
/* these two are set only if table is a sequence owned by a column: */
Oid owning_tab; /* OID of table owning sequence */
@@ -346,8 +346,6 @@ typedef struct _tableInfo
bool *inhNotNull; /* true if NOT NULL is inherited */
struct _attrDefInfo **attrdefs; /* DEFAULT expressions */
struct _constraintInfo *checkexprs; /* CHECK constraints */
- char *partkeydef; /* partition key definition */- char *partbound; /* partition bound definition */
bool needs_override; /* has GENERATED ALWAYS AS IDENTITY */
char *amname; /* relation access method */
=
[text/x-diff] 0004-bulk-queries-2.patch (74.2K, ../177444.1635287465@sss.pgh.pa.us/5-0004-bulk-queries-2.patch)
download | inline diff:diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.cindex d6075133a1..45bae2ffe1 100644--- a/src/bin/pg_dump/pg_dump.c+++ b/src/bin/pg_dump/pg_dump.c@@ -6650,13 +6650,15 @@ getInherits(Archive *fout, int *numInherits)
void
getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
{
- int i,- j;
PQExpBuffer query = createPQExpBuffer();
+ PQExpBuffer tbloids = createPQExpBuffer();
PGresult *res;
+ int ntups;+ int curtblindx;
IndxInfo *indxinfo;
int i_tableoid,
i_oid,
+ i_indrelid,
i_indexname,
i_parentidx,
i_indexdef,
@@ -6676,9 +6678,17 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
i_indreloptions,
i_indstatcols,
i_indstatvals;
- int ntups;- for (i = 0; i < numTables; i++)+ /*+ * We want to perform just one query against pg_index. However, we+ * mustn't try to select every row of the catalog and then sort it out on+ * the client side, because some of the server-side functions we need+ * would be unsafe to apply to tables we don't have lock on. Hence, we+ * build an array of the OIDs of tables we care about (and now have lock+ * on!), and use a WHERE clause to constrain which rows are selected.+ */+ appendPQExpBufferChar(tbloids, '{');+ for (int i = 0; i < numTables; i++)
{
TableInfo *tbinfo = &tblinfo[i];
@@ -6691,232 +6701,270 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
if (!tbinfo->interesting)
continue;
- pg_log_info("reading indexes for table \"%s.%s\"",- tbinfo->dobj.namespace->dobj.name,- tbinfo->dobj.name);+ /* OK, we need info for this table */+ if (tbloids->len > 1)+ appendPQExpBufferChar(tbloids, ',');+ appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);+ }+ appendPQExpBufferChar(tbloids, '}');+ /*+ * The point of the messy-looking outer join is to find a constraint that+ * is related by an internal dependency link to the index. If we find one,+ * create a CONSTRAINT entry linked to the INDEX entry. We assume an+ * index won't have more than one internal dependency.+ *+ * As of 9.0 we don't need to look at pg_depend but can check for a match+ * to pg_constraint.conindid. The check on conrelid is redundant but+ * useful because that column is indexed while conindid is not.+ */+ if (fout->remoteVersion >= 110000)+ {+ appendPQExpBuffer(query,+ "SELECT t.tableoid, t.oid, i.indrelid, "+ "t.relname AS indexname, "+ "inh.inhparent AS parentidx, "+ "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "+ "i.indnkeyatts AS indnkeyatts, "+ "i.indnatts AS indnatts, "+ "i.indkey, i.indisclustered, "+ "i.indisreplident, "+ "c.contype, c.conname, "+ "c.condeferrable, c.condeferred, "+ "c.tableoid AS contableoid, "+ "c.oid AS conoid, "+ "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "+ "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "+ "t.reloptions AS indreloptions, "+ "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "+ " FROM pg_catalog.pg_attribute "+ " WHERE attrelid = i.indexrelid AND "+ " attstattarget >= 0) AS indstatcols,"+ "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "+ " FROM pg_catalog.pg_attribute "+ " WHERE attrelid = i.indexrelid AND "+ " attstattarget >= 0) AS indstatvals "+ "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"+ "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "+ "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "+ "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "+ "LEFT JOIN pg_catalog.pg_constraint c "+ "ON (i.indrelid = c.conrelid AND "+ "i.indexrelid = c.conindid AND "+ "c.contype IN ('p','u','x')) "+ "LEFT JOIN pg_catalog.pg_inherits inh "+ "ON (inh.inhrelid = indexrelid) "+ "WHERE (i.indisvalid OR t2.relkind = 'p') "+ "AND i.indisready "+ "ORDER BY i.indrelid, indexname",+ tbloids->data);+ }+ else if (fout->remoteVersion >= 90400)+ {
/*
- * The point of the messy-looking outer join is to find a constraint- * that is related by an internal dependency link to the index. If we- * find one, create a CONSTRAINT entry linked to the INDEX entry. We- * assume an index won't have more than one internal dependency.- *- * As of 9.0 we don't need to look at pg_depend but can check for a- * match to pg_constraint.conindid. The check on conrelid is- * redundant but useful because that column is indexed while conindid- * is not.+ * the test on indisready is necessary in 9.2, and harmless in+ * earlier/later versions
*/
- resetPQExpBuffer(query);- if (fout->remoteVersion >= 110000)- {- appendPQExpBuffer(query,- "SELECT t.tableoid, t.oid, "- "t.relname AS indexname, "- "inh.inhparent AS parentidx, "- "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "- "i.indnkeyatts AS indnkeyatts, "- "i.indnatts AS indnatts, "- "i.indkey, i.indisclustered, "- "i.indisreplident, "- "c.contype, c.conname, "- "c.condeferrable, c.condeferred, "- "c.tableoid AS contableoid, "- "c.oid AS conoid, "- "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "- "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "- "t.reloptions AS indreloptions, "- "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "- " FROM pg_catalog.pg_attribute "- " WHERE attrelid = i.indexrelid AND "- " attstattarget >= 0) AS indstatcols,"- "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "- " FROM pg_catalog.pg_attribute "- " WHERE attrelid = i.indexrelid AND "- " attstattarget >= 0) AS indstatvals "- "FROM pg_catalog.pg_index i "- "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "- "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "- "LEFT JOIN pg_catalog.pg_constraint c "- "ON (i.indrelid = c.conrelid AND "- "i.indexrelid = c.conindid AND "- "c.contype IN ('p','u','x')) "- "LEFT JOIN pg_catalog.pg_inherits inh "- "ON (inh.inhrelid = indexrelid) "- "WHERE i.indrelid = '%u'::pg_catalog.oid "- "AND (i.indisvalid OR t2.relkind = 'p') "- "AND i.indisready "- "ORDER BY indexname",- tbinfo->dobj.catId.oid);- }- else if (fout->remoteVersion >= 90400)- {- /*- * the test on indisready is necessary in 9.2, and harmless in- * earlier/later versions- */- appendPQExpBuffer(query,- "SELECT t.tableoid, t.oid, "- "t.relname AS indexname, "- "0 AS parentidx, "- "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "- "i.indnatts AS indnkeyatts, "- "i.indnatts AS indnatts, "- "i.indkey, i.indisclustered, "- "i.indisreplident, "- "c.contype, c.conname, "- "c.condeferrable, c.condeferred, "- "c.tableoid AS contableoid, "- "c.oid AS conoid, "- "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "- "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "- "t.reloptions AS indreloptions, "- "'' AS indstatcols, "- "'' AS indstatvals "- "FROM pg_catalog.pg_index i "- "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "- "LEFT JOIN pg_catalog.pg_constraint c "- "ON (i.indrelid = c.conrelid AND "- "i.indexrelid = c.conindid AND "- "c.contype IN ('p','u','x')) "- "WHERE i.indrelid = '%u'::pg_catalog.oid "- "AND i.indisvalid AND i.indisready "- "ORDER BY indexname",- tbinfo->dobj.catId.oid);- }- else if (fout->remoteVersion >= 90000)- {- /*- * the test on indisready is necessary in 9.2, and harmless in- * earlier/later versions- */- appendPQExpBuffer(query,- "SELECT t.tableoid, t.oid, "- "t.relname AS indexname, "- "0 AS parentidx, "- "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "- "i.indnatts AS indnkeyatts, "- "i.indnatts AS indnatts, "- "i.indkey, i.indisclustered, "- "false AS indisreplident, "- "c.contype, c.conname, "- "c.condeferrable, c.condeferred, "- "c.tableoid AS contableoid, "- "c.oid AS conoid, "- "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "- "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "- "t.reloptions AS indreloptions, "- "'' AS indstatcols, "- "'' AS indstatvals "- "FROM pg_catalog.pg_index i "- "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "- "LEFT JOIN pg_catalog.pg_constraint c "- "ON (i.indrelid = c.conrelid AND "- "i.indexrelid = c.conindid AND "- "c.contype IN ('p','u','x')) "- "WHERE i.indrelid = '%u'::pg_catalog.oid "- "AND i.indisvalid AND i.indisready "- "ORDER BY indexname",- tbinfo->dobj.catId.oid);- }- else if (fout->remoteVersion >= 80200)- {- appendPQExpBuffer(query,- "SELECT t.tableoid, t.oid, "- "t.relname AS indexname, "- "0 AS parentidx, "- "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "- "i.indnatts AS indnkeyatts, "- "i.indnatts AS indnatts, "- "i.indkey, i.indisclustered, "- "false AS indisreplident, "- "c.contype, c.conname, "- "c.condeferrable, c.condeferred, "- "c.tableoid AS contableoid, "- "c.oid AS conoid, "- "null AS condef, "- "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "- "t.reloptions AS indreloptions, "- "'' AS indstatcols, "- "'' AS indstatvals "- "FROM pg_catalog.pg_index i "- "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "- "LEFT JOIN pg_catalog.pg_depend d "- "ON (d.classid = t.tableoid "- "AND d.objid = t.oid "- "AND d.deptype = 'i') "- "LEFT JOIN pg_catalog.pg_constraint c "- "ON (d.refclassid = c.tableoid "- "AND d.refobjid = c.oid) "- "WHERE i.indrelid = '%u'::pg_catalog.oid "- "AND i.indisvalid "- "ORDER BY indexname",- tbinfo->dobj.catId.oid);- }- else- {- appendPQExpBuffer(query,- "SELECT t.tableoid, t.oid, "- "t.relname AS indexname, "- "0 AS parentidx, "- "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "- "t.relnatts AS indnkeyatts, "- "t.relnatts AS indnatts, "- "i.indkey, i.indisclustered, "- "false AS indisreplident, "- "c.contype, c.conname, "- "c.condeferrable, c.condeferred, "- "c.tableoid AS contableoid, "- "c.oid AS conoid, "- "null AS condef, "- "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "- "null AS indreloptions, "- "'' AS indstatcols, "- "'' AS indstatvals "- "FROM pg_catalog.pg_index i "- "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "- "LEFT JOIN pg_catalog.pg_depend d "- "ON (d.classid = t.tableoid "- "AND d.objid = t.oid "- "AND d.deptype = 'i') "- "LEFT JOIN pg_catalog.pg_constraint c "- "ON (d.refclassid = c.tableoid "- "AND d.refobjid = c.oid) "- "WHERE i.indrelid = '%u'::pg_catalog.oid "- "ORDER BY indexname",- tbinfo->dobj.catId.oid);- }+ appendPQExpBuffer(query,+ "SELECT t.tableoid, t.oid, i.indrelid, "+ "t.relname AS indexname, "+ "0 AS parentidx, "+ "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "+ "i.indnatts AS indnkeyatts, "+ "i.indnatts AS indnatts, "+ "i.indkey, i.indisclustered, "+ "i.indisreplident, "+ "c.contype, c.conname, "+ "c.condeferrable, c.condeferred, "+ "c.tableoid AS contableoid, "+ "c.oid AS conoid, "+ "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "+ "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "+ "t.reloptions AS indreloptions, "+ "'' AS indstatcols, "+ "'' AS indstatvals "+ "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"+ "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "+ "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "+ "LEFT JOIN pg_catalog.pg_constraint c "+ "ON (i.indrelid = c.conrelid AND "+ "i.indexrelid = c.conindid AND "+ "c.contype IN ('p','u','x')) "+ "WHERE i.indisvalid AND i.indisready "+ "ORDER BY i.indrelid, indexname",+ tbloids->data);+ }+ else if (fout->remoteVersion >= 90000)+ {+ /*+ * the test on indisready is necessary in 9.2, and harmless in+ * earlier/later versions+ */+ appendPQExpBuffer(query,+ "SELECT t.tableoid, t.oid, i.indrelid, "+ "t.relname AS indexname, "+ "0 AS parentidx, "+ "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "+ "i.indnatts AS indnkeyatts, "+ "i.indnatts AS indnatts, "+ "i.indkey, i.indisclustered, "+ "false AS indisreplident, "+ "c.contype, c.conname, "+ "c.condeferrable, c.condeferred, "+ "c.tableoid AS contableoid, "+ "c.oid AS conoid, "+ "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "+ "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "+ "t.reloptions AS indreloptions, "+ "'' AS indstatcols, "+ "'' AS indstatvals "+ "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"+ "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "+ "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "+ "LEFT JOIN pg_catalog.pg_constraint c "+ "ON (i.indrelid = c.conrelid AND "+ "i.indexrelid = c.conindid AND "+ "c.contype IN ('p','u','x')) "+ "WHERE i.indisvalid AND i.indisready "+ "ORDER BY i.indrelid, indexname",+ tbloids->data);+ }+ else if (fout->remoteVersion >= 80200)+ {+ appendPQExpBuffer(query,+ "SELECT t.tableoid, t.oid, i.indrelid, "+ "t.relname AS indexname, "+ "0 AS parentidx, "+ "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "+ "i.indnatts AS indnkeyatts, "+ "i.indnatts AS indnatts, "+ "i.indkey, i.indisclustered, "+ "false AS indisreplident, "+ "c.contype, c.conname, "+ "c.condeferrable, c.condeferred, "+ "c.tableoid AS contableoid, "+ "c.oid AS conoid, "+ "null AS condef, "+ "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "+ "t.reloptions AS indreloptions, "+ "'' AS indstatcols, "+ "'' AS indstatvals "+ "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"+ "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "+ "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "+ "LEFT JOIN pg_catalog.pg_depend d "+ "ON (d.classid = t.tableoid "+ "AND d.objid = t.oid "+ "AND d.deptype = 'i') "+ "LEFT JOIN pg_catalog.pg_constraint c "+ "ON (d.refclassid = c.tableoid "+ "AND d.refobjid = c.oid) "+ "WHERE i.indisvalid "+ "ORDER BY i.indrelid, indexname",+ tbloids->data);+ }+ else+ {+ appendPQExpBuffer(query,+ "SELECT t.tableoid, t.oid, i.indrelid, "+ "t.relname AS indexname, "+ "0 AS parentidx, "+ "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "+ "t.relnatts AS indnkeyatts, "+ "t.relnatts AS indnatts, "+ "i.indkey, i.indisclustered, "+ "false AS indisreplident, "+ "c.contype, c.conname, "+ "c.condeferrable, c.condeferred, "+ "c.tableoid AS contableoid, "+ "c.oid AS conoid, "+ "null AS condef, "+ "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "+ "null AS indreloptions, "+ "'' AS indstatcols, "+ "'' AS indstatvals "+ "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"+ "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "+ "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "+ "LEFT JOIN pg_catalog.pg_depend d "+ "ON (d.classid = t.tableoid "+ "AND d.objid = t.oid "+ "AND d.deptype = 'i') "+ "LEFT JOIN pg_catalog.pg_constraint c "+ "ON (d.refclassid = c.tableoid "+ "AND d.refobjid = c.oid) "+ "ORDER BY i.indrelid, indexname",+ tbloids->data);+ }- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);+ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);- ntups = PQntuples(res);+ ntups = PQntuples(res);- i_tableoid = PQfnumber(res, "tableoid");- i_oid = PQfnumber(res, "oid");- i_indexname = PQfnumber(res, "indexname");- i_parentidx = PQfnumber(res, "parentidx");- i_indexdef = PQfnumber(res, "indexdef");- i_indnkeyatts = PQfnumber(res, "indnkeyatts");- i_indnatts = PQfnumber(res, "indnatts");- i_indkey = PQfnumber(res, "indkey");- i_indisclustered = PQfnumber(res, "indisclustered");- i_indisreplident = PQfnumber(res, "indisreplident");- i_contype = PQfnumber(res, "contype");- i_conname = PQfnumber(res, "conname");- i_condeferrable = PQfnumber(res, "condeferrable");- i_condeferred = PQfnumber(res, "condeferred");- i_contableoid = PQfnumber(res, "contableoid");- i_conoid = PQfnumber(res, "conoid");- i_condef = PQfnumber(res, "condef");- i_tablespace = PQfnumber(res, "tablespace");- i_indreloptions = PQfnumber(res, "indreloptions");- i_indstatcols = PQfnumber(res, "indstatcols");- i_indstatvals = PQfnumber(res, "indstatvals");-- tbinfo->indexes = indxinfo =- (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));- tbinfo->numIndexes = ntups;+ i_tableoid = PQfnumber(res, "tableoid");+ i_oid = PQfnumber(res, "oid");+ i_indrelid = PQfnumber(res, "indrelid");+ i_indexname = PQfnumber(res, "indexname");+ i_parentidx = PQfnumber(res, "parentidx");+ i_indexdef = PQfnumber(res, "indexdef");+ i_indnkeyatts = PQfnumber(res, "indnkeyatts");+ i_indnatts = PQfnumber(res, "indnatts");+ i_indkey = PQfnumber(res, "indkey");+ i_indisclustered = PQfnumber(res, "indisclustered");+ i_indisreplident = PQfnumber(res, "indisreplident");+ i_contype = PQfnumber(res, "contype");+ i_conname = PQfnumber(res, "conname");+ i_condeferrable = PQfnumber(res, "condeferrable");+ i_condeferred = PQfnumber(res, "condeferred");+ i_contableoid = PQfnumber(res, "contableoid");+ i_conoid = PQfnumber(res, "conoid");+ i_condef = PQfnumber(res, "condef");+ i_tablespace = PQfnumber(res, "tablespace");+ i_indreloptions = PQfnumber(res, "indreloptions");+ i_indstatcols = PQfnumber(res, "indstatcols");+ i_indstatvals = PQfnumber(res, "indstatvals");- for (j = 0; j < ntups; j++)+ indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));++ /*+ * Outer loop iterates once per table, not once per row. Incrementing of+ * j is handled by the inner loop.+ */+ curtblindx = -1;+ for (int j = 0; j < ntups;)+ {+ Oid indrelid = atooid(PQgetvalue(res, j, i_indrelid));+ TableInfo *tbinfo = NULL;+ int numinds;++ /* Count rows for this table */+ for (numinds = 1; numinds < ntups - j; numinds++)+ if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)+ break;++ /*+ * Locate the associated TableInfo; we rely on tblinfo[] being in OID+ * order.+ */+ while (++curtblindx < numTables)+ {+ tbinfo = &tblinfo[curtblindx];+ if (tbinfo->dobj.catId.oid == indrelid)+ break;+ }+ if (curtblindx >= numTables)+ fatal("unrecognized table OID %u", indrelid);+ /* cross-check that we only got requested tables */+ if (!tbinfo->hasindex ||+ !tbinfo->interesting)+ fatal("unexpected index data for table \"%s\"",+ tbinfo->dobj.name);++ /* Save data for this table */+ tbinfo->indexes = indxinfo + j;+ tbinfo->numIndexes = numinds;++ for (int c = 0; c < numinds; c++, j++)
{
char contype;
@@ -6985,11 +7033,12 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
indxinfo[j].indexconstraint = 0;
}
}
-- PQclear(res);
}
+ PQclear(res);+
destroyPQExpBuffer(query);
+ destroyPQExpBuffer(tbloids);
}
/*
@@ -7076,22 +7125,31 @@ getExtendedStatistics(Archive *fout)
void
getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
{
- int i,- j;- ConstraintInfo *constrinfo;- PQExpBuffer query;+ PQExpBuffer query = createPQExpBuffer();+ PQExpBuffer tbloids = createPQExpBuffer();
PGresult *res;
+ int ntups;+ int curtblindx;+ TableInfo *tbinfo = NULL;+ ConstraintInfo *constrinfo;
int i_contableoid,
i_conoid,
+ i_conrelid,
i_conname,
i_confrelid,
i_conindid,
i_condef;
- int ntups;- query = createPQExpBuffer();-- for (i = 0; i < numTables; i++)+ /*+ * We want to perform just one query against pg_constraint. However, we+ * mustn't try to select every row of the catalog and then sort it out on+ * the client side, because some of the server-side functions we need+ * would be unsafe to apply to tables we don't have lock on. Hence, we+ * build an array of the OIDs of tables we care about (and now have lock+ * on!), and use a WHERE clause to constrain which rows are selected.+ */+ appendPQExpBufferChar(tbloids, '{');+ for (int i = 0; i < numTables; i++)
{
TableInfo *tbinfo = &tblinfo[i];
@@ -7104,95 +7162,118 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
continue;
- pg_log_info("reading foreign key constraints for table \"%s.%s\"",- tbinfo->dobj.namespace->dobj.name,- tbinfo->dobj.name);+ /* OK, we need info for this table */+ if (tbloids->len > 1)+ appendPQExpBufferChar(tbloids, ',');+ appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);+ }+ appendPQExpBufferChar(tbloids, '}');- resetPQExpBuffer(query);- if (fout->remoteVersion >= 110000)- appendPQExpBuffer(query,- "SELECT tableoid, oid, conname, confrelid, conindid, "- "pg_catalog.pg_get_constraintdef(oid) AS condef "- "FROM pg_catalog.pg_constraint "- "WHERE conrelid = '%u'::pg_catalog.oid "- "AND conparentid = 0 "- "AND contype = 'f'",- tbinfo->dobj.catId.oid);- else- appendPQExpBuffer(query,- "SELECT tableoid, oid, conname, confrelid, 0 as conindid, "- "pg_catalog.pg_get_constraintdef(oid) AS condef "- "FROM pg_catalog.pg_constraint "- "WHERE conrelid = '%u'::pg_catalog.oid "- "AND contype = 'f'",- tbinfo->dobj.catId.oid);- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);+ appendPQExpBufferStr(query,+ "SELECT c.tableoid, c.oid, "+ "conrelid, conname, confrelid, ");+ if (fout->remoteVersion >= 110000)+ appendPQExpBufferStr(query, "conindid, ");+ else+ appendPQExpBufferStr(query, "0 AS conindid, ");+ appendPQExpBuffer(query,+ "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"+ "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"+ "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"+ "WHERE contype = 'f' ",+ tbloids->data);+ if (fout->remoteVersion >= 110000)+ appendPQExpBufferStr(query,+ "AND conparentid = 0 ");+ appendPQExpBufferStr(query,+ "ORDER BY conrelid, conname");- ntups = PQntuples(res);+ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);- i_contableoid = PQfnumber(res, "tableoid");- i_conoid = PQfnumber(res, "oid");- i_conname = PQfnumber(res, "conname");- i_confrelid = PQfnumber(res, "confrelid");- i_conindid = PQfnumber(res, "conindid");- i_condef = PQfnumber(res, "condef");+ ntups = PQntuples(res);- constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));+ i_contableoid = PQfnumber(res, "tableoid");+ i_conoid = PQfnumber(res, "oid");+ i_conrelid = PQfnumber(res, "conrelid");+ i_conname = PQfnumber(res, "conname");+ i_confrelid = PQfnumber(res, "confrelid");+ i_conindid = PQfnumber(res, "conindid");+ i_condef = PQfnumber(res, "condef");- for (j = 0; j < ntups; j++)- {- TableInfo *reftable;-- constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;- constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));- constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));- AssignDumpId(&constrinfo[j].dobj);- constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));- constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;- constrinfo[j].contable = tbinfo;- constrinfo[j].condomain = NULL;- constrinfo[j].contype = 'f';- constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));- constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));- constrinfo[j].conindex = 0;- constrinfo[j].condeferrable = false;- constrinfo[j].condeferred = false;- constrinfo[j].conislocal = true;- constrinfo[j].separate = true;+ constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));- /*- * Restoring an FK that points to a partitioned table requires- * that all partition indexes have been attached beforehand.- * Ensure that happens by making the constraint depend on each- * index partition attach object.- */- reftable = findTableByOid(constrinfo[j].confrelid);- if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)+ curtblindx = -1;+ for (int j = 0; j < ntups; j++)+ {+ Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));+ TableInfo *reftable;++ /*+ * Locate the associated TableInfo; we rely on tblinfo[] being in OID+ * order.+ */+ if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)+ {+ while (++curtblindx < numTables)
{
- Oid indexOid = atooid(PQgetvalue(res, j, i_conindid));+ tbinfo = &tblinfo[curtblindx];+ if (tbinfo->dobj.catId.oid == conrelid)+ break;+ }+ if (curtblindx >= numTables)+ fatal("unrecognized table OID %u", conrelid);+ }++ constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;+ constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));+ constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));+ AssignDumpId(&constrinfo[j].dobj);+ constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));+ constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;+ constrinfo[j].contable = tbinfo;+ constrinfo[j].condomain = NULL;+ constrinfo[j].contype = 'f';+ constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));+ constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));+ constrinfo[j].conindex = 0;+ constrinfo[j].condeferrable = false;+ constrinfo[j].condeferred = false;+ constrinfo[j].conislocal = true;+ constrinfo[j].separate = true;++ /*+ * Restoring an FK that points to a partitioned table requires that+ * all partition indexes have been attached beforehand. Ensure that+ * happens by making the constraint depend on each index partition+ * attach object.+ */+ reftable = findTableByOid(constrinfo[j].confrelid);+ if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)+ {+ Oid indexOid = atooid(PQgetvalue(res, j, i_conindid));- if (indexOid != InvalidOid)+ if (indexOid != InvalidOid)+ {+ for (int k = 0; k < reftable->numIndexes; k++)
{
- for (int k = 0; k < reftable->numIndexes; k++)- {- IndxInfo *refidx;+ IndxInfo *refidx;- /* not our index? */- if (reftable->indexes[k].dobj.catId.oid != indexOid)- continue;+ /* not our index? */+ if (reftable->indexes[k].dobj.catId.oid != indexOid)+ continue;- refidx = &reftable->indexes[k];- addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);- break;- }+ refidx = &reftable->indexes[k];+ addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);+ break;
}
}
}
-- PQclear(res);
}
+ PQclear(res);+
destroyPQExpBuffer(query);
+ destroyPQExpBuffer(tbloids);
}
/*
@@ -7436,13 +7517,15 @@ getRules(Archive *fout, int *numRules)
void
getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
{
- int i,- j;
PQExpBuffer query = createPQExpBuffer();
+ PQExpBuffer tbloids = createPQExpBuffer();
PGresult *res;
+ int ntups;+ int curtblindx;
TriggerInfo *tginfo;
int i_tableoid,
i_oid,
+ i_tgrelid,
i_tgname,
i_tgfname,
i_tgtype,
@@ -7457,9 +7540,17 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
i_tgdeferrable,
i_tginitdeferred,
i_tgdef;
- int ntups;- for (i = 0; i < numTables; i++)+ /*+ * We want to perform just one query against pg_trigger. However, we+ * mustn't try to select every row of the catalog and then sort it out on+ * the client side, because some of the server-side functions we need+ * would be unsafe to apply to tables we don't have lock on. Hence, we+ * build an array of the OIDs of tables we care about (and now have lock+ * on!), and use a WHERE clause to constrain which rows are selected.+ */+ appendPQExpBufferChar(tbloids, '{');+ for (int i = 0; i < numTables; i++)
{
TableInfo *tbinfo = &tblinfo[i];
@@ -7467,143 +7558,178 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
continue;
- pg_log_info("reading triggers for table \"%s.%s\"",- tbinfo->dobj.namespace->dobj.name,- tbinfo->dobj.name);+ /* OK, we need info for this table */+ if (tbloids->len > 1)+ appendPQExpBufferChar(tbloids, ',');+ appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);+ }+ appendPQExpBufferChar(tbloids, '}');- resetPQExpBuffer(query);- if (fout->remoteVersion >= 130000)- {- /*- * NB: think not to use pretty=true in pg_get_triggerdef. It- * could result in non-forward-compatible dumps of WHEN clauses- * due to under-parenthesization.- *- * NB: We need to see tgisinternal triggers in partitions, in case- * the tgenabled flag has been changed from the parent.- */- appendPQExpBuffer(query,- "SELECT t.tgname, "- "t.tgfoid::pg_catalog.regproc AS tgfname, "- "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "- "t.tgenabled, t.tableoid, t.oid, t.tgisinternal "- "FROM pg_catalog.pg_trigger t "- "LEFT JOIN pg_catalog.pg_trigger u ON u.oid = t.tgparentid "- "WHERE t.tgrelid = '%u'::pg_catalog.oid "- "AND (NOT t.tgisinternal OR t.tgenabled != u.tgenabled)",- tbinfo->dobj.catId.oid);- }- else if (fout->remoteVersion >= 110000)- {- /*- * NB: We need to see tgisinternal triggers in partitions, in case- * the tgenabled flag has been changed from the parent. No- * tgparentid in version 11-12, so we have to match them via- * pg_depend.- *- * See above about pretty=true in pg_get_triggerdef.- */- appendPQExpBuffer(query,- "SELECT t.tgname, "- "t.tgfoid::pg_catalog.regproc AS tgfname, "- "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "- "t.tgenabled, t.tableoid, t.oid, t.tgisinternal "- "FROM pg_catalog.pg_trigger t "- "LEFT JOIN pg_catalog.pg_depend AS d ON "- " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "- " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "- " d.objid = t.oid "- "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "- "WHERE t.tgrelid = '%u'::pg_catalog.oid "- "AND (NOT t.tgisinternal%s)",- tbinfo->dobj.catId.oid,- tbinfo->ispartition ?- " OR t.tgenabled != pt.tgenabled" : "");- }- else if (fout->remoteVersion >= 90000)- {- /* See above about pretty=true in pg_get_triggerdef */- appendPQExpBuffer(query,- "SELECT t.tgname, "- "t.tgfoid::pg_catalog.regproc AS tgfname, "- "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "- "t.tgenabled, false as tgisinternal, "- "t.tableoid, t.oid "- "FROM pg_catalog.pg_trigger t "- "WHERE tgrelid = '%u'::pg_catalog.oid "- "AND NOT tgisinternal",- tbinfo->dobj.catId.oid);- }- else if (fout->remoteVersion >= 80300)- {- /*- * We ignore triggers that are tied to a foreign-key constraint- */- appendPQExpBuffer(query,- "SELECT tgname, "- "tgfoid::pg_catalog.regproc AS tgfname, "- "tgtype, tgnargs, tgargs, tgenabled, "- "false as tgisinternal, "- "tgisconstraint, tgconstrname, tgdeferrable, "- "tgconstrrelid, tginitdeferred, tableoid, oid, "- "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "- "FROM pg_catalog.pg_trigger t "- "WHERE tgrelid = '%u'::pg_catalog.oid "- "AND tgconstraint = 0",- tbinfo->dobj.catId.oid);- }- else- {- /*- * We ignore triggers that are tied to a foreign-key constraint,- * but in these versions we have to grovel through pg_constraint- * to find out- */- appendPQExpBuffer(query,- "SELECT tgname, "- "tgfoid::pg_catalog.regproc AS tgfname, "- "tgtype, tgnargs, tgargs, tgenabled, "- "false as tgisinternal, "- "tgisconstraint, tgconstrname, tgdeferrable, "- "tgconstrrelid, tginitdeferred, tableoid, oid, "- "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "- "FROM pg_catalog.pg_trigger t "- "WHERE tgrelid = '%u'::pg_catalog.oid "- "AND (NOT tgisconstraint "- " OR NOT EXISTS"- " (SELECT 1 FROM pg_catalog.pg_depend d "- " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "- " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",- tbinfo->dobj.catId.oid);- }+ if (fout->remoteVersion >= 130000)+ {+ /*+ * NB: think not to use pretty=true in pg_get_triggerdef. It could+ * result in non-forward-compatible dumps of WHEN clauses due to+ * under-parenthesization.+ *+ * NB: We need to see tgisinternal triggers in partitions, in case the+ * tgenabled flag has been changed from the parent.+ */+ appendPQExpBuffer(query,+ "SELECT t.tgrelid, t.tgname, "+ "t.tgfoid::pg_catalog.regproc AS tgfname, "+ "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "+ "t.tgenabled, t.tableoid, t.oid, t.tgisinternal\n"+ "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"+ "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "+ "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "+ "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "+ "ORDER BY t.tgrelid, t.tgname",+ tbloids->data);+ }+ else if (fout->remoteVersion >= 110000)+ {+ /*+ * NB: We need to see tgisinternal triggers in partitions, in case the+ * tgenabled flag has been changed from the parent. No tgparentid in+ * version 11-12, so we have to match them via pg_depend.+ *+ * See above about pretty=true in pg_get_triggerdef.+ */+ appendPQExpBuffer(query,+ "SELECT t.tgrelid, t.tgname, "+ "t.tgfoid::pg_catalog.regproc AS tgfname, "+ "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "+ "t.tgenabled, t.tableoid, t.oid, t.tgisinternal "+ "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"+ "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "+ "LEFT JOIN pg_catalog.pg_depend AS d ON "+ " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "+ " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "+ " d.objid = t.oid "+ "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "+ "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "+ "ORDER BY t.tgrelid, t.tgname",+ tbloids->data);+ }+ else if (fout->remoteVersion >= 90000)+ {+ /* See above about pretty=true in pg_get_triggerdef */+ appendPQExpBuffer(query,+ "SELECT t.tgrelid, t.tgname, "+ "t.tgfoid::pg_catalog.regproc AS tgfname, "+ "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "+ "t.tgenabled, false as tgisinternal, "+ "t.tableoid, t.oid "+ "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"+ "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "+ "WHERE NOT tgisinternal "+ "ORDER BY t.tgrelid, t.tgname",+ tbloids->data);+ }+ else if (fout->remoteVersion >= 80300)+ {+ /*+ * We ignore triggers that are tied to a foreign-key constraint+ */+ appendPQExpBuffer(query,+ "SELECT t.tgrelid, tgname, "+ "tgfoid::pg_catalog.regproc AS tgfname, "+ "tgtype, tgnargs, tgargs, tgenabled, "+ "false as tgisinternal, "+ "tgisconstraint, tgconstrname, tgdeferrable, "+ "tgconstrrelid, tginitdeferred, t.tableoid, t.oid, "+ "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "+ "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"+ "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "+ "WHERE tgconstraint = 0 "+ "ORDER BY t.tgrelid, t.tgname",+ tbloids->data);+ }+ else+ {+ /*+ * We ignore triggers that are tied to a foreign-key constraint, but+ * in these versions we have to grovel through pg_constraint to find+ * out+ */+ appendPQExpBuffer(query,+ "SELECT t.tgrelid, tgname, "+ "tgfoid::pg_catalog.regproc AS tgfname, "+ "tgtype, tgnargs, tgargs, tgenabled, "+ "false as tgisinternal, "+ "tgisconstraint, tgconstrname, tgdeferrable, "+ "tgconstrrelid, tginitdeferred, t.tableoid, t.oid, "+ "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "+ "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"+ "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "+ "WHERE (NOT tgisconstraint "+ " OR NOT EXISTS"+ " (SELECT 1 FROM pg_catalog.pg_depend d "+ " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "+ " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f')) "+ "ORDER BY t.tgrelid, t.tgname",+ tbloids->data);+ }- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);+ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);- ntups = PQntuples(res);+ ntups = PQntuples(res);- i_tableoid = PQfnumber(res, "tableoid");- i_oid = PQfnumber(res, "oid");- i_tgname = PQfnumber(res, "tgname");- i_tgfname = PQfnumber(res, "tgfname");- i_tgtype = PQfnumber(res, "tgtype");- i_tgnargs = PQfnumber(res, "tgnargs");- i_tgargs = PQfnumber(res, "tgargs");- i_tgisconstraint = PQfnumber(res, "tgisconstraint");- i_tgconstrname = PQfnumber(res, "tgconstrname");- i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");- i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");- i_tgenabled = PQfnumber(res, "tgenabled");- i_tgisinternal = PQfnumber(res, "tgisinternal");- i_tgdeferrable = PQfnumber(res, "tgdeferrable");- i_tginitdeferred = PQfnumber(res, "tginitdeferred");- i_tgdef = PQfnumber(res, "tgdef");-- tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));-- tbinfo->numTriggers = ntups;- tbinfo->triggers = tginfo;+ i_tableoid = PQfnumber(res, "tableoid");+ i_oid = PQfnumber(res, "oid");+ i_tgrelid = PQfnumber(res, "tgrelid");+ i_tgname = PQfnumber(res, "tgname");+ i_tgfname = PQfnumber(res, "tgfname");+ i_tgtype = PQfnumber(res, "tgtype");+ i_tgnargs = PQfnumber(res, "tgnargs");+ i_tgargs = PQfnumber(res, "tgargs");+ i_tgisconstraint = PQfnumber(res, "tgisconstraint");+ i_tgconstrname = PQfnumber(res, "tgconstrname");+ i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");+ i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");+ i_tgenabled = PQfnumber(res, "tgenabled");+ i_tgisinternal = PQfnumber(res, "tgisinternal");+ i_tgdeferrable = PQfnumber(res, "tgdeferrable");+ i_tginitdeferred = PQfnumber(res, "tginitdeferred");+ i_tgdef = PQfnumber(res, "tgdef");++ tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));- for (j = 0; j < ntups; j++)+ /*+ * Outer loop iterates once per table, not once per row. Incrementing of+ * j is handled by the inner loop.+ */+ curtblindx = -1;+ for (int j = 0; j < ntups;)+ {+ Oid tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));+ TableInfo *tbinfo = NULL;+ int numtrigs;++ /* Count rows for this table */+ for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)+ if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)+ break;++ /*+ * Locate the associated TableInfo; we rely on tblinfo[] being in OID+ * order.+ */+ while (++curtblindx < numTables)+ {+ tbinfo = &tblinfo[curtblindx];+ if (tbinfo->dobj.catId.oid == tgrelid)+ break;+ }+ if (curtblindx >= numTables)+ fatal("unrecognized table OID %u", tgrelid);++ /* Save data for this table */+ tbinfo->triggers = tginfo + j;+ tbinfo->numTriggers = numtrigs;++ for (int c = 0; c < numtrigs; c++, j++)
{
tginfo[j].dobj.objType = DO_TRIGGER;
tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
@@ -7666,11 +7792,12 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
}
}
}
-- PQclear(res);
}
+ PQclear(res);+
destroyPQExpBuffer(query);
+ destroyPQExpBuffer(tbloids);
}
/*
@@ -8124,12 +8251,6 @@ getTransforms(Archive *fout, int *numTransforms)
* for each interesting table, read info about its attributes
* (names, types, default values, CHECK constraints, etc)
*
- * This is implemented in a very inefficient way right now, looping- * through the tblinfo and doing a join per table to find the attrs and their- * types. However, because we want type names and so forth to be named- * relative to the schema of each table, we couldn't do it in just one- * query. (Maybe one query per schema?)- *
* modifies tblinfo
*/
void
@@ -8137,6 +8258,12 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
{
DumpOptions *dopt = fout->dopt;
PQExpBuffer q = createPQExpBuffer();
+ PQExpBuffer tbloids = createPQExpBuffer();+ PQExpBuffer checkoids = createPQExpBuffer();+ PGresult *res;+ int ntups;+ int curtblindx;+ int i_attrelid;
int i_attnum;
int i_attname;
int i_atttypname;
@@ -8158,12 +8285,21 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
int i_attmissingval;
int i_atthasdef;
+ /*+ * We want to perform just one query against pg_attribute, and then just+ * one against pg_attrdef (for DEFAULTs) and one against pg_constraint+ * (for CHECK constraints). However, we mustn't try to select every row+ * of those catalogs and then sort it out on the client side, because some+ * of the server-side functions we need would be unsafe to apply to tables+ * we don't have lock on. Hence, we build an array of the OIDs of tables+ * we care about (and now have lock on!), and use a WHERE clause to+ * constrain which rows are selected.+ */+ appendPQExpBufferChar(tbloids, '{');+ appendPQExpBufferChar(checkoids, '{');
for (int i = 0; i < numTables; i++)
{
TableInfo *tbinfo = &tblinfo[i];
- PGresult *res;- int ntups;- bool hasdefaults;
/* Don't bother to collect info for sequences */
if (tbinfo->relkind == RELKIND_SEQUENCE)
@@ -8173,390 +8309,499 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
if (!tbinfo->interesting)
continue;
- /* find all the user attributes and their types */+ /* OK, we need info for this table */+ if (tbloids->len > 1)+ appendPQExpBufferChar(tbloids, ',');+ appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);++ if (tbinfo->ncheck > 0)+ {+ /* Also make a list of the ones with check constraints */+ if (checkoids->len > 1)+ appendPQExpBufferChar(checkoids, ',');+ appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);+ }+ }+ appendPQExpBufferChar(tbloids, '}');+ appendPQExpBufferChar(checkoids, '}');++ /* find all the user attributes and their types */+ appendPQExpBufferStr(q,+ "SELECT\n"+ "a.attrelid,\n"+ "a.attnum,\n"+ "a.attname,\n"+ "a.atttypmod,\n"+ "a.attstattarget,\n"+ "a.attstorage,\n"+ "t.typstorage,\n"+ "a.attnotnull,\n"+ "a.atthasdef,\n"+ "a.attisdropped,\n"+ "a.attlen,\n"+ "a.attalign,\n"+ "a.attislocal,\n"+ "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n");+ if (fout->remoteVersion >= 90000)+ appendPQExpBufferStr(q,+ "array_to_string(a.attoptions, ', ') AS attoptions,\n");+ else+ appendPQExpBufferStr(q,+ "'' AS attoptions,\n");++ if (fout->remoteVersion >= 90100)+ {
/*
- * we must read the attribute names in attribute number order! because- * we will use the attnum to index into the attnames array later.+ * Since we only want to dump COLLATE clauses for attributes whose+ * collation is different from their type's default, we use a CASE+ * here to suppress uninteresting attcollations cheaply.
*/
- pg_log_info("finding the columns and types of table \"%s.%s\"",- tbinfo->dobj.namespace->dobj.name,- tbinfo->dobj.name);+ appendPQExpBufferStr(q,+ "CASE WHEN a.attcollation <> t.typcollation "+ "THEN a.attcollation ELSE 0 END AS attcollation,\n");+ }+ else+ appendPQExpBufferStr(q,+ "0 AS attcollation,\n");- resetPQExpBuffer(q);+ if (fout->remoteVersion >= 140000)+ appendPQExpBufferStr(q,+ "a.attcompression AS attcompression,\n");+ else+ appendPQExpBufferStr(q,+ "'' AS attcompression,\n");+ if (fout->remoteVersion >= 90200)
appendPQExpBufferStr(q,
- "SELECT\n"- "a.attnum,\n"- "a.attname,\n"- "a.atttypmod,\n"- "a.attstattarget,\n"- "a.attstorage,\n"- "t.typstorage,\n"- "a.attnotnull,\n"- "a.atthasdef,\n"- "a.attisdropped,\n"- "a.attlen,\n"- "a.attalign,\n"- "a.attislocal,\n"- "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n");-- if (fout->remoteVersion >= 90000)- appendPQExpBufferStr(q,- "array_to_string(a.attoptions, ', ') AS attoptions,\n");- else- appendPQExpBufferStr(q,- "'' AS attoptions,\n");+ "pg_catalog.array_to_string(ARRAY("+ "SELECT pg_catalog.quote_ident(option_name) || "+ "' ' || pg_catalog.quote_literal(option_value) "+ "FROM pg_catalog.pg_options_to_table(attfdwoptions) "+ "ORDER BY option_name"+ "), E',\n ') AS attfdwoptions,\n");+ else+ appendPQExpBufferStr(q,+ "'' AS attfdwoptions,\n");- if (fout->remoteVersion >= 90100)- {- /*- * Since we only want to dump COLLATE clauses for attributes whose- * collation is different from their type's default, we use a CASE- * here to suppress uninteresting attcollations cheaply.- */- appendPQExpBufferStr(q,- "CASE WHEN a.attcollation <> t.typcollation "- "THEN a.attcollation ELSE 0 END AS attcollation,\n");- }- else- appendPQExpBufferStr(q,- "0 AS attcollation,\n");+ if (fout->remoteVersion >= 100000)+ appendPQExpBufferStr(q,+ "a.attidentity,\n");+ else+ appendPQExpBufferStr(q,+ "'' AS attidentity,\n");- if (fout->remoteVersion >= 140000)- appendPQExpBuffer(q,- "a.attcompression AS attcompression,\n");- else- appendPQExpBuffer(q,- "'' AS attcompression,\n");+ if (fout->remoteVersion >= 110000)+ appendPQExpBufferStr(q,+ "CASE WHEN a.atthasmissing AND NOT a.attisdropped "+ "THEN a.attmissingval ELSE null END AS attmissingval,\n");+ else+ appendPQExpBufferStr(q,+ "NULL AS attmissingval,\n");- if (fout->remoteVersion >= 90200)- appendPQExpBufferStr(q,- "pg_catalog.array_to_string(ARRAY("- "SELECT pg_catalog.quote_ident(option_name) || "- "' ' || pg_catalog.quote_literal(option_value) "- "FROM pg_catalog.pg_options_to_table(attfdwoptions) "- "ORDER BY option_name"- "), E',\n ') AS attfdwoptions,\n");- else- appendPQExpBufferStr(q,- "'' AS attfdwoptions,\n");+ if (fout->remoteVersion >= 120000)+ appendPQExpBufferStr(q,+ "a.attgenerated\n");+ else+ appendPQExpBufferStr(q,+ "'' AS attgenerated\n");- if (fout->remoteVersion >= 100000)- appendPQExpBufferStr(q,- "a.attidentity,\n");- else- appendPQExpBufferStr(q,- "'' AS attidentity,\n");+ /* need left join to pg_type to not fail on dropped columns ... */+ appendPQExpBuffer(q,+ "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"+ "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "+ "LEFT JOIN pg_catalog.pg_type t "+ "ON (a.atttypid = t.oid)\n"+ "WHERE a.attnum > 0::pg_catalog.int2\n"+ "ORDER BY a.attrelid, a.attnum",+ tbloids->data);- if (fout->remoteVersion >= 110000)- appendPQExpBufferStr(q,- "CASE WHEN a.atthasmissing AND NOT a.attisdropped "- "THEN a.attmissingval ELSE null END AS attmissingval,\n");- else- appendPQExpBufferStr(q,- "NULL AS attmissingval,\n");+ res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);- if (fout->remoteVersion >= 120000)- appendPQExpBufferStr(q,- "a.attgenerated\n");- else- appendPQExpBufferStr(q,- "'' AS attgenerated\n");+ ntups = PQntuples(res);- /* need left join here to not fail on dropped columns ... */- appendPQExpBuffer(q,- "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "- "ON a.atttypid = t.oid\n"- "WHERE a.attrelid = '%u'::pg_catalog.oid "- "AND a.attnum > 0::pg_catalog.int2\n"- "ORDER BY a.attnum",- tbinfo->dobj.catId.oid);+ i_attrelid = PQfnumber(res, "attrelid");+ i_attnum = PQfnumber(res, "attnum");+ i_attname = PQfnumber(res, "attname");+ i_atttypname = PQfnumber(res, "atttypname");+ i_atttypmod = PQfnumber(res, "atttypmod");+ i_attstattarget = PQfnumber(res, "attstattarget");+ i_attstorage = PQfnumber(res, "attstorage");+ i_typstorage = PQfnumber(res, "typstorage");+ i_attidentity = PQfnumber(res, "attidentity");+ i_attgenerated = PQfnumber(res, "attgenerated");+ i_attisdropped = PQfnumber(res, "attisdropped");+ i_attlen = PQfnumber(res, "attlen");+ i_attalign = PQfnumber(res, "attalign");+ i_attislocal = PQfnumber(res, "attislocal");+ i_attnotnull = PQfnumber(res, "attnotnull");+ i_attoptions = PQfnumber(res, "attoptions");+ i_attcollation = PQfnumber(res, "attcollation");+ i_attcompression = PQfnumber(res, "attcompression");+ i_attfdwoptions = PQfnumber(res, "attfdwoptions");+ i_attmissingval = PQfnumber(res, "attmissingval");+ i_atthasdef = PQfnumber(res, "atthasdef");- res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);+ /* Within the next loop, we'll accumulate OIDs of tables with defaults */+ resetPQExpBuffer(tbloids);+ appendPQExpBufferChar(tbloids, '{');- ntups = PQntuples(res);+ /*+ * Outer loop iterates once per table, not once per row. Incrementing of+ * r is handled by the inner loop.+ */+ curtblindx = -1;+ for (int r = 0; r < ntups;)+ {+ Oid attrelid = atooid(PQgetvalue(res, r, i_attrelid));+ TableInfo *tbinfo = NULL;+ int numatts;+ bool hasdefaults;++ /* Count rows for this table */+ for (numatts = 1; numatts < ntups - r; numatts++)+ if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)+ break;- tbinfo->numatts = ntups;- tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));- tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));- tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));- tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));- tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));- tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));- tbinfo->attidentity = (char *) pg_malloc(ntups * sizeof(char));- tbinfo->attgenerated = (char *) pg_malloc(ntups * sizeof(char));- tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));- tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));- tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));- tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));- tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));- tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));- tbinfo->attcompression = (char *) pg_malloc(ntups * sizeof(char));- tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));- tbinfo->attmissingval = (char **) pg_malloc(ntups * sizeof(char *));- tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));- tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));- tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));+ /*+ * Locate the associated TableInfo; we rely on tblinfo[] being in OID+ * order.+ */+ while (++curtblindx < numTables)+ {+ tbinfo = &tblinfo[curtblindx];+ if (tbinfo->dobj.catId.oid == attrelid)+ break;+ }+ if (curtblindx >= numTables)+ fatal("unrecognized table OID %u", attrelid);+ /* cross-check that we only got requested tables */+ if (tbinfo->relkind == RELKIND_SEQUENCE ||+ !tbinfo->interesting)+ fatal("unexpected column data for table \"%s\"",+ tbinfo->dobj.name);++ /* Save data for this table */+ tbinfo->numatts = numatts;+ tbinfo->attnames = (char **) pg_malloc(numatts * sizeof(char *));+ tbinfo->atttypnames = (char **) pg_malloc(numatts * sizeof(char *));+ tbinfo->atttypmod = (int *) pg_malloc(numatts * sizeof(int));+ tbinfo->attstattarget = (int *) pg_malloc(numatts * sizeof(int));+ tbinfo->attstorage = (char *) pg_malloc(numatts * sizeof(char));+ tbinfo->typstorage = (char *) pg_malloc(numatts * sizeof(char));+ tbinfo->attidentity = (char *) pg_malloc(numatts * sizeof(char));+ tbinfo->attgenerated = (char *) pg_malloc(numatts * sizeof(char));+ tbinfo->attisdropped = (bool *) pg_malloc(numatts * sizeof(bool));+ tbinfo->attlen = (int *) pg_malloc(numatts * sizeof(int));+ tbinfo->attalign = (char *) pg_malloc(numatts * sizeof(char));+ tbinfo->attislocal = (bool *) pg_malloc(numatts * sizeof(bool));+ tbinfo->attoptions = (char **) pg_malloc(numatts * sizeof(char *));+ tbinfo->attcollation = (Oid *) pg_malloc(numatts * sizeof(Oid));+ tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));+ tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));+ tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));+ tbinfo->notnull = (bool *) pg_malloc(numatts * sizeof(bool));+ tbinfo->inhNotNull = (bool *) pg_malloc(numatts * sizeof(bool));+ tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
hasdefaults = false;
- i_attnum = PQfnumber(res, "attnum");- i_attname = PQfnumber(res, "attname");- i_atttypname = PQfnumber(res, "atttypname");- i_atttypmod = PQfnumber(res, "atttypmod");- i_attstattarget = PQfnumber(res, "attstattarget");- i_attstorage = PQfnumber(res, "attstorage");- i_typstorage = PQfnumber(res, "typstorage");- i_attidentity = PQfnumber(res, "attidentity");- i_attgenerated = PQfnumber(res, "attgenerated");- i_attisdropped = PQfnumber(res, "attisdropped");- i_attlen = PQfnumber(res, "attlen");- i_attalign = PQfnumber(res, "attalign");- i_attislocal = PQfnumber(res, "attislocal");- i_attnotnull = PQfnumber(res, "attnotnull");- i_attoptions = PQfnumber(res, "attoptions");- i_attcollation = PQfnumber(res, "attcollation");- i_attcompression = PQfnumber(res, "attcompression");- i_attfdwoptions = PQfnumber(res, "attfdwoptions");- i_attmissingval = PQfnumber(res, "attmissingval");- i_atthasdef = PQfnumber(res, "atthasdef");-- for (int j = 0; j < ntups; j++)+ for (int j = 0; j < numatts; j++, r++)
{
- if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))+ if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
fatal("invalid column numbering in table \"%s\"",
tbinfo->dobj.name);
- tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));- tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));- tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));- tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));- tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));- tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));- tbinfo->attidentity[j] = *(PQgetvalue(res, j, i_attidentity));- tbinfo->attgenerated[j] = *(PQgetvalue(res, j, i_attgenerated));+ tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));+ tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));+ tbinfo->atttypmod[j] = atoi(PQgetvalue(res, r, i_atttypmod));+ tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));+ tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));+ tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));+ tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));+ tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
- tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');- tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));- tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));- tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');- tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');- tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));- tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));- tbinfo->attcompression[j] = *(PQgetvalue(res, j, i_attcompression));- tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));- tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, j, i_attmissingval));+ tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');+ tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));+ tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));+ tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');+ tbinfo->notnull[j] = (PQgetvalue(res, r, i_attnotnull)[0] == 't');+ tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));+ tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));+ tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));+ tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));+ tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
tbinfo->attrdefs[j] = NULL; /* fix below */
- if (PQgetvalue(res, j, i_atthasdef)[0] == 't')+ if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
hasdefaults = true;
/* these flags will be set in flagInhAttrs() */
tbinfo->inhNotNull[j] = false;
}
- PQclear(res);-- /*- * Get info about column defaults. This is skipped for a data-only- * dump, as it is only needed for table schemas.- */- if (!dopt->dataOnly && hasdefaults)+ if (hasdefaults)
{
- AttrDefInfo *attrdefs;- int numDefaults;-- pg_log_info("finding default expressions of table \"%s.%s\"",- tbinfo->dobj.namespace->dobj.name,- tbinfo->dobj.name);-- printfPQExpBuffer(q, "SELECT tableoid, oid, adnum, "- "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "- "FROM pg_catalog.pg_attrdef "- "WHERE adrelid = '%u'::pg_catalog.oid",- tbinfo->dobj.catId.oid);-- res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);+ /* Collect OIDs of interesting tables that have defaults */+ if (tbloids->len > 1)+ appendPQExpBufferChar(tbloids, ',');+ appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);+ }+ }- numDefaults = PQntuples(res);- attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));+ PQclear(res);- for (int j = 0; j < numDefaults; j++)- {- int adnum;+ /*+ * Now get info about column defaults. This is skipped for a data-only+ * dump, as it is only needed for table schemas.+ */+ if (!dopt->dataOnly && tbloids->len > 1)+ {+ AttrDefInfo *attrdefs;+ int numDefaults;+ TableInfo *tbinfo = NULL;- adnum = atoi(PQgetvalue(res, j, 2));+ pg_log_info("finding table default expressions");- if (adnum <= 0 || adnum > ntups)- fatal("invalid adnum value %d for table \"%s\"",- adnum, tbinfo->dobj.name);+ appendPQExpBufferChar(tbloids, '}');- /*- * dropped columns shouldn't have defaults, but just in case,- * ignore 'em- */- if (tbinfo->attisdropped[adnum - 1])- continue;+ printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "+ "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"+ "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"+ "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"+ "ORDER BY a.adrelid, a.adnum",+ tbloids->data);- attrdefs[j].dobj.objType = DO_ATTRDEF;- attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));- attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));- AssignDumpId(&attrdefs[j].dobj);- attrdefs[j].adtable = tbinfo;- attrdefs[j].adnum = adnum;- attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));+ res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);- attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);- attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;+ numDefaults = PQntuples(res);+ attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));- attrdefs[j].dobj.dump = tbinfo->dobj.dump;+ curtblindx = -1;+ for (int j = 0; j < numDefaults; j++)+ {+ Oid adtableoid = atooid(PQgetvalue(res, j, 0));+ Oid adoid = atooid(PQgetvalue(res, j, 1));+ Oid adrelid = atooid(PQgetvalue(res, j, 2));+ int adnum = atoi(PQgetvalue(res, j, 3));+ char *adsrc = PQgetvalue(res, j, 4);- /*- * Figure out whether the default/generation expression should- * be dumped as part of the main CREATE TABLE (or similar)- * command or as a separate ALTER TABLE (or similar) command.- * The preference is to put it into the CREATE command, but in- * some cases that's not possible.- */- if (tbinfo->attgenerated[adnum - 1])- {- /*- * Column generation expressions cannot be dumped- * separately, because there is no syntax for it. The- * !shouldPrintColumn case below will be tempted to set- * them to separate if they are attached to an inherited- * column without a local definition, but that would be- * wrong and unnecessary, because generation expressions- * are always inherited, so there is no need to set them- * again in child tables, and there is no syntax for it- * either. By setting separate to false here we prevent- * the "default" from being processed as its own dumpable- * object, and flagInhAttrs() will remove it from the- * table when it detects that it belongs to an inherited- * column.- */- attrdefs[j].separate = false;- }- else if (tbinfo->relkind == RELKIND_VIEW)- {- /*- * Defaults on a VIEW must always be dumped as separate- * ALTER TABLE commands.- */- attrdefs[j].separate = true;- }- else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))- {- /* column will be suppressed, print default separately */- attrdefs[j].separate = true;- }- else+ /*+ * Locate the associated TableInfo; we rely on tblinfo[] being in+ * OID order.+ */+ if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)+ {+ while (++curtblindx < numTables)
{
- attrdefs[j].separate = false;+ tbinfo = &tblinfo[curtblindx];+ if (tbinfo->dobj.catId.oid == adrelid)+ break;
}
+ if (curtblindx >= numTables)+ fatal("unrecognized table OID %u", adrelid);+ }- if (!attrdefs[j].separate)- {- /*- * Mark the default as needing to appear before the table,- * so that any dependencies it has must be emitted before- * the CREATE TABLE. If this is not possible, we'll- * change to "separate" mode while sorting dependencies.- */- addObjectDependency(&tbinfo->dobj,- attrdefs[j].dobj.dumpId);- }+ if (adnum <= 0 || adnum > tbinfo->numatts)+ fatal("invalid adnum value %d for table \"%s\"",+ adnum, tbinfo->dobj.name);- tbinfo->attrdefs[adnum - 1] = &attrdefs[j];- }- PQclear(res);- }+ /*+ * dropped columns shouldn't have defaults, but just in case,+ * ignore 'em+ */+ if (tbinfo->attisdropped[adnum - 1])+ continue;- /*- * Get info about table CHECK constraints. This is skipped for a- * data-only dump, as it is only needed for table schemas.- */- if (tbinfo->ncheck > 0 && !dopt->dataOnly)- {- ConstraintInfo *constrs;- int numConstrs;+ attrdefs[j].dobj.objType = DO_ATTRDEF;+ attrdefs[j].dobj.catId.tableoid = adtableoid;+ attrdefs[j].dobj.catId.oid = adoid;+ AssignDumpId(&attrdefs[j].dobj);+ attrdefs[j].adtable = tbinfo;+ attrdefs[j].adnum = adnum;+ attrdefs[j].adef_expr = pg_strdup(adsrc);++ attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);+ attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;- pg_log_info("finding check constraints for table \"%s.%s\"",- tbinfo->dobj.namespace->dobj.name,- tbinfo->dobj.name);+ attrdefs[j].dobj.dump = tbinfo->dobj.dump;- resetPQExpBuffer(q);- if (fout->remoteVersion >= 90200)+ /*+ * Figure out whether the default/generation expression should be+ * dumped as part of the main CREATE TABLE (or similar) command or+ * as a separate ALTER TABLE (or similar) command. The preference+ * is to put it into the CREATE command, but in some cases that's+ * not possible.+ */+ if (tbinfo->attgenerated[adnum - 1])+ {+ /*+ * Column generation expressions cannot be dumped separately,+ * because there is no syntax for it. The !shouldPrintColumn+ * case below will be tempted to set them to separate if they+ * are attached to an inherited column without a local+ * definition, but that would be wrong and unnecessary,+ * because generation expressions are always inherited, so+ * there is no need to set them again in child tables, and+ * there is no syntax for it either. By setting separate to+ * false here we prevent the "default" from being processed as+ * its own dumpable object, and flagInhAttrs() will remove it+ * from the table when it detects that it belongs to an+ * inherited column.+ */+ attrdefs[j].separate = false;+ }+ else if (tbinfo->relkind == RELKIND_VIEW)
{
/*
- * convalidated is new in 9.2 (actually, it is there in 9.1,- * but it wasn't ever false for check constraints until 9.2).+ * Defaults on a VIEW must always be dumped as separate ALTER+ * TABLE commands.
*/
- appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "- "pg_catalog.pg_get_constraintdef(oid) AS consrc, "- "conislocal, convalidated "- "FROM pg_catalog.pg_constraint "- "WHERE conrelid = '%u'::pg_catalog.oid "- " AND contype = 'c' "- "ORDER BY conname",- tbinfo->dobj.catId.oid);+ attrdefs[j].separate = true;
}
- else if (fout->remoteVersion >= 80400)+ else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
{
- /* conislocal is new in 8.4 */- appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "- "pg_catalog.pg_get_constraintdef(oid) AS consrc, "- "conislocal, true AS convalidated "- "FROM pg_catalog.pg_constraint "- "WHERE conrelid = '%u'::pg_catalog.oid "- " AND contype = 'c' "- "ORDER BY conname",- tbinfo->dobj.catId.oid);+ /* column will be suppressed, print default separately */+ attrdefs[j].separate = true;
}
else
{
- appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "- "pg_catalog.pg_get_constraintdef(oid) AS consrc, "- "true AS conislocal, true AS convalidated "- "FROM pg_catalog.pg_constraint "- "WHERE conrelid = '%u'::pg_catalog.oid "- " AND contype = 'c' "- "ORDER BY conname",- tbinfo->dobj.catId.oid);+ attrdefs[j].separate = false;
}
- res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);+ if (!attrdefs[j].separate)+ {+ /*+ * Mark the default as needing to appear before the table, so+ * that any dependencies it has must be emitted before the+ * CREATE TABLE. If this is not possible, we'll change to+ * "separate" mode while sorting dependencies.+ */+ addObjectDependency(&tbinfo->dobj,+ attrdefs[j].dobj.dumpId);+ }++ tbinfo->attrdefs[adnum - 1] = &attrdefs[j];+ }++ PQclear(res);+ }- numConstrs = PQntuples(res);- if (numConstrs != tbinfo->ncheck)+ /*+ * Get info about table CHECK constraints. This is skipped for a+ * data-only dump, as it is only needed for table schemas.+ */+ if (!dopt->dataOnly && checkoids->len > 2)+ {+ ConstraintInfo *constrs;+ int numConstrs;+ int i_tableoid;+ int i_oid;+ int i_conrelid;+ int i_conname;+ int i_consrc;+ int i_conislocal;+ int i_convalidated;++ pg_log_info("finding table check constraints");++ resetPQExpBuffer(q);+ appendPQExpBufferStr(q,+ "SELECT c.tableoid, c.oid, conrelid, conname, "+ "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, ");+ if (fout->remoteVersion >= 90200)+ {+ /*+ * convalidated is new in 9.2 (actually, it is there in 9.1, but+ * it wasn't ever false for check constraints until 9.2).+ */+ appendPQExpBufferStr(q,+ "conislocal, convalidated ");+ }+ else if (fout->remoteVersion >= 80400)+ {+ /* conislocal is new in 8.4 */+ appendPQExpBufferStr(q,+ "conislocal, true AS convalidated ");+ }+ else+ {+ appendPQExpBufferStr(q,+ "true AS conislocal, true AS convalidated ");+ }+ appendPQExpBuffer(q,+ "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"+ "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"+ "WHERE contype = 'c' "+ "ORDER BY c.conrelid, c.conname",+ checkoids->data);++ res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);++ numConstrs = PQntuples(res);+ constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));++ i_tableoid = PQfnumber(res, "tableoid");+ i_oid = PQfnumber(res, "oid");+ i_conrelid = PQfnumber(res, "conrelid");+ i_conname = PQfnumber(res, "conname");+ i_consrc = PQfnumber(res, "consrc");+ i_conislocal = PQfnumber(res, "conislocal");+ i_convalidated = PQfnumber(res, "convalidated");++ /* As above, this loop iterates once per table, not once per row */+ curtblindx = -1;+ for (int j = 0; j < numConstrs;)+ {+ Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));+ TableInfo *tbinfo = NULL;+ int numcons;++ /* Count rows for this table */+ for (numcons = 1; numcons < numConstrs - j; numcons++)+ if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)+ break;++ /*+ * Locate the associated TableInfo; we rely on tblinfo[] being in+ * OID order.+ */+ while (++curtblindx < numTables)+ {+ tbinfo = &tblinfo[curtblindx];+ if (tbinfo->dobj.catId.oid == conrelid)+ break;+ }+ if (curtblindx >= numTables)+ fatal("unrecognized table OID %u", conrelid);++ if (numcons != tbinfo->ncheck)
{
pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
"expected %d check constraints on table \"%s\" but found %d",
tbinfo->ncheck),
- tbinfo->ncheck, tbinfo->dobj.name, numConstrs);+ tbinfo->ncheck, tbinfo->dobj.name, numcons);
pg_log_error("(The system catalogs might be corrupted.)");
exit_nicely(1);
}
- constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));- tbinfo->checkexprs = constrs;+ tbinfo->checkexprs = constrs + j;- for (int j = 0; j < numConstrs; j++)+ for (int c = 0; c < numcons; c++, j++)
{
- bool validated = PQgetvalue(res, j, 5)[0] == 't';+ bool validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
constrs[j].dobj.objType = DO_CONSTRAINT;
- constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));- constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));+ constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));+ constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
AssignDumpId(&constrs[j].dobj);
- constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));+ constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
constrs[j].dobj.namespace = tbinfo->dobj.namespace;
constrs[j].contable = tbinfo;
constrs[j].condomain = NULL;
constrs[j].contype = 'c';
- constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));+ constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
constrs[j].confrelid = InvalidOid;
constrs[j].conindex = 0;
constrs[j].condeferrable = false;
constrs[j].condeferred = false;
- constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');+ constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
/*
* An unvalidated constraint needs to be dumped separately, so
@@ -8586,11 +8831,14 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
* constraint must be split out from the table definition.
*/
}
- PQclear(res);
}
++ PQclear(res);
}
destroyPQExpBuffer(q);
+ destroyPQExpBuffer(tbloids);+ destroyPQExpBuffer(checkoids);
}
/*
[text/x-diff] 0005-fix-toast-sched-2.patch (4.6K, ../177444.1635287465@sss.pgh.pa.us/6-0005-fix-toast-sched-2.patch)
download | inline diff:diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.cindex 45bae2ffe1..e54c3c04cb 100644--- a/src/bin/pg_dump/pg_dump.c+++ b/src/bin/pg_dump/pg_dump.c@@ -2425,13 +2425,26 @@ dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
/*
* Set the TocEntry's dataLength in case we are doing a parallel dump
* and want to order dump jobs by table size. We choose to measure
- * dataLength in table pages during dump, so no scaling is needed.+ * dataLength in table pages (including TOAST pages) during dump, so+ * no scaling is needed.+ *
* However, relpages is declared as "integer" in pg_class, and hence
* also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
* Cast so that we get the right interpretation of table sizes
* exceeding INT_MAX pages.
*/
te->dataLength = (BlockNumber) tbinfo->relpages;
+ te->dataLength += (BlockNumber) tbinfo->toastpages;++ /*+ * If pgoff_t is only 32 bits wide, the above refinement is useless,+ * and instead we'd better worry about integer overflow. Clamp to+ * INT_MAX if the correct result exceeds that.+ */+ if (sizeof(te->dataLength) == 4 &&+ (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||+ te->dataLength < 0))+ te->dataLength = INT_MAX;
}
destroyPQExpBuffer(copyBuf);
@@ -6086,6 +6099,7 @@ getTables(Archive *fout, int *numTables)
int i_relhasindex;
int i_relhasrules;
int i_relpages;
+ int i_toastpages;
int i_owning_tab;
int i_owning_col;
int i_reltablespace;
@@ -6135,6 +6149,7 @@ getTables(Archive *fout, int *numTables)
"(%s c.relowner) AS rolname, "
"c.relchecks, "
"c.relhasindex, c.relhasrules, c.relpages, "
+ "tc.relpages AS toastpages, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"tsp.spcname AS reltablespace, ",
@@ -6291,17 +6306,14 @@ getTables(Archive *fout, int *numTables)
"LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
/*
- * We don't need any data from the TOAST table before 8.2.- *
* We purposefully ignore toast OIDs for partitioned tables; the reason is
* that versions 10 and 11 have them, but later versions do not, so
* emitting them causes the upgrade to fail.
*/
- if (fout->remoteVersion >= 80200)- appendPQExpBufferStr(query,- "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"- " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)- " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");+ appendPQExpBufferStr(query,+ "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"+ " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)+ " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
/*
* Restrict to interesting relkinds (in particular, not indexes). Not all
@@ -6352,6 +6364,7 @@ getTables(Archive *fout, int *numTables)
i_relhasindex = PQfnumber(res, "relhasindex");
i_relhasrules = PQfnumber(res, "relhasrules");
i_relpages = PQfnumber(res, "relpages");
+ i_toastpages = PQfnumber(res, "toastpages");
i_owning_tab = PQfnumber(res, "owning_tab");
i_owning_col = PQfnumber(res, "owning_col");
i_reltablespace = PQfnumber(res, "reltablespace");
@@ -6413,6 +6426,10 @@ getTables(Archive *fout, int *numTables)
tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
+ if (PQgetisnull(res, i, i_toastpages))+ tblinfo[i].toastpages = 0;+ else+ tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
if (PQgetisnull(res, i, i_owning_tab))
{
tblinfo[i].owning_tab = InvalidOid;
@@ -10229,7 +10246,7 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
* about is allowing blob dumping to be parallelized, not just
* getting a smarter estimate for the single TOC entry.)
*/
- te->dataLength = MaxBlockNumber;+ te->dataLength = INT_MAX;
}
break;
case DO_POLICY:
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.hindex 9061812c08..0936ec49bf 100644--- a/src/bin/pg_dump/pg_dump.h+++ b/src/bin/pg_dump/pg_dump.h@@ -314,6 +314,7 @@ typedef struct _tableInfo
int owning_col; /* attr # of column owning sequence */
bool is_identity_sequence;
int relpages; /* table's size in pages (from pg_class) */
+ int toastpages; /* toast table's size in pages, if any */
bool interesting; /* true if need to collect more data */
bool dummy_view; /* view's real definition must be postponed */
[text/x-diff] 0006-prepare-repeated-queries-3.patch (34.9K, ../177444.1635287465@sss.pgh.pa.us/7-0006-prepare-repeated-queries-3.patch)
download | inline diff:diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.hindex 6af10a85a2..d3aac0dbdf 100644--- a/src/bin/pg_dump/pg_backup.h+++ b/src/bin/pg_dump/pg_backup.h@@ -58,6 +58,23 @@ typedef enum _teSection
SECTION_POST_DATA /* stuff to be processed after data */
} teSection;
+/* We need one enum entry per prepared query in pg_dump */+enum _dumpPreparedQueries+{+ PREPQUERY_DUMPAGG,+ PREPQUERY_DUMPBASETYPE,+ PREPQUERY_DUMPCOMPOSITETYPE,+ PREPQUERY_DUMPDOMAIN,+ PREPQUERY_DUMPENUMTYPE,+ PREPQUERY_DUMPFUNC,+ PREPQUERY_DUMPOPR,+ PREPQUERY_DUMPRANGETYPE,+ PREPQUERY_DUMPTABLEATTACH,+ PREPQUERY_GETCOLUMNACLS,+ PREPQUERY_GETDOMAINCONSTRAINTS,+ NUM_PREP_QUERIES /* must be last */+};+
/* Parameters needed by ConnectDatabase; same for dump and restore */
typedef struct _connParams
{
@@ -214,6 +231,9 @@ typedef struct Archive
bool exit_on_error; /* whether to exit on SQL errors... */
int n_errors; /* number of errors (if no die) */
+ /* prepared-query status */+ bool *is_prepared; /* indexed by enum _dumpPreparedQueries */+
/* The rest is private */
} Archive;
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.cindex e54c3c04cb..212203a32e 100644--- a/src/bin/pg_dump/pg_dump.c+++ b/src/bin/pg_dump/pg_dump.c@@ -1208,6 +1208,12 @@ setup_connection(Archive *AH, const char *dumpencoding,
ExecuteSqlStatement(AH, "SET row_security = off");
}
+ /*+ * Initialize prepared-query state to "nothing prepared". We do this here+ * so that a parallel dump worker will have its own state.+ */+ AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));+
/*
* Start transaction-snapshot mode transaction to dump consistent data.
*/
@@ -7332,7 +7338,7 @@ getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
{
int i;
ConstraintInfo *constrinfo;
- PQExpBuffer query;+ PQExpBuffer query = createPQExpBuffer();
PGresult *res;
int i_tableoid,
i_oid,
@@ -7340,25 +7346,35 @@ getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
i_consrc;
int ntups;
- query = createPQExpBuffer();+ if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])+ {+ /* Set up query for constraint-specific details */+ appendPQExpBufferStr(query,+ "PREPARE getDomainConstraints(pg_catalog.oid) AS\n");++ if (fout->remoteVersion >= 90100)+ appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "+ "pg_catalog.pg_get_constraintdef(oid) AS consrc, "+ "convalidated "+ "FROM pg_catalog.pg_constraint "+ "WHERE contypid = $1 "+ "ORDER BY conname");+ else+ appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "+ "pg_catalog.pg_get_constraintdef(oid) AS consrc, "+ "true as convalidated "+ "FROM pg_catalog.pg_constraint "+ "WHERE contypid = $1 "+ "ORDER BY conname");- if (fout->remoteVersion >= 90100)- appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "- "pg_catalog.pg_get_constraintdef(oid) AS consrc, "- "convalidated "- "FROM pg_catalog.pg_constraint "- "WHERE contypid = '%u'::pg_catalog.oid "- "ORDER BY conname",- tyinfo->dobj.catId.oid);+ ExecuteSqlStatement(fout, query->data);- else- appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "- "pg_catalog.pg_get_constraintdef(oid) AS consrc, "- "true as convalidated "- "FROM pg_catalog.pg_constraint "- "WHERE contypid = '%u'::pg_catalog.oid "- "ORDER BY conname",- tyinfo->dobj.catId.oid);+ fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;+ }++ printfPQExpBuffer(query,+ "EXECUTE getDomainConstraints('%u')",+ tyinfo->dobj.catId.oid);
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
@@ -10527,18 +10543,31 @@ dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
int i_enumlabel;
int i_oid;
- if (fout->remoteVersion >= 90100)- appendPQExpBuffer(query, "SELECT oid, enumlabel "- "FROM pg_catalog.pg_enum "- "WHERE enumtypid = '%u'"- "ORDER BY enumsortorder",- tyinfo->dobj.catId.oid);- else- appendPQExpBuffer(query, "SELECT oid, enumlabel "- "FROM pg_catalog.pg_enum "- "WHERE enumtypid = '%u'"- "ORDER BY oid",- tyinfo->dobj.catId.oid);+ if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])+ {+ /* Set up query for enum-specific details */+ appendPQExpBufferStr(query,+ "PREPARE dumpEnumType(pg_catalog.oid) AS\n");++ if (fout->remoteVersion >= 90100)+ appendPQExpBufferStr(query, "SELECT oid, enumlabel "+ "FROM pg_catalog.pg_enum "+ "WHERE enumtypid = $1 "+ "ORDER BY enumsortorder");+ else+ appendPQExpBufferStr(query, "SELECT oid, enumlabel "+ "FROM pg_catalog.pg_enum "+ "WHERE enumtypid = $1 "+ "ORDER BY oid");++ ExecuteSqlStatement(fout, query->data);++ fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;+ }++ printfPQExpBuffer(query,+ "EXECUTE dumpEnumType('%u')",+ tyinfo->dobj.catId.oid);
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
@@ -10657,29 +10686,43 @@ dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
char *qualtypname;
char *procname;
- appendPQExpBuffer(query,- "SELECT ");+ if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])+ {+ /* Set up query for range-specific details */+ appendPQExpBufferStr(query,+ "PREPARE dumpRangeType(pg_catalog.oid) AS\n");- if (fout->remoteVersion >= 140000)- appendPQExpBuffer(query,- "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");- else- appendPQExpBuffer(query,- "NULL AS rngmultitype, ");+ appendPQExpBufferStr(query,+ "SELECT ");- appendPQExpBuffer(query,- "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "- "opc.opcname AS opcname, "- "(SELECT nspname FROM pg_catalog.pg_namespace nsp "- " WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "- "opc.opcdefault, "- "CASE WHEN rngcollation = st.typcollation THEN 0 "- " ELSE rngcollation END AS collation, "- "rngcanonical, rngsubdiff "- "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "- " pg_catalog.pg_opclass opc "- "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "- "rngtypid = '%u'",+ if (fout->remoteVersion >= 140000)+ appendPQExpBufferStr(query,+ "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");+ else+ appendPQExpBufferStr(query,+ "NULL AS rngmultitype, ");++ appendPQExpBufferStr(query,+ "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "+ "opc.opcname AS opcname, "+ "(SELECT nspname FROM pg_catalog.pg_namespace nsp "+ " WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "+ "opc.opcdefault, "+ "CASE WHEN rngcollation = st.typcollation THEN 0 "+ " ELSE rngcollation END AS collation, "+ "rngcanonical, rngsubdiff "+ "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "+ " pg_catalog.pg_opclass opc "+ "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "+ "rngtypid = $1");++ ExecuteSqlStatement(fout, query->data);++ fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;+ }++ printfPQExpBuffer(query,+ "EXECUTE dumpRangeType('%u')",
tyinfo->dobj.catId.oid);
res = ExecuteSqlQueryForSingleRow(fout, query->data);
@@ -10887,55 +10930,68 @@ dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
char *typdefault;
bool typdefault_is_literal = false;
- /* Fetch type-specific details */- appendPQExpBufferStr(query, "SELECT typlen, "- "typinput, typoutput, typreceive, typsend, "- "typreceive::pg_catalog.oid AS typreceiveoid, "- "typsend::pg_catalog.oid AS typsendoid, "- "typanalyze, "- "typanalyze::pg_catalog.oid AS typanalyzeoid, "- "typdelim, typbyval, typalign, typstorage, ");-- if (fout->remoteVersion >= 80300)- appendPQExpBufferStr(query,- "typmodin, typmodout, "- "typmodin::pg_catalog.oid AS typmodinoid, "- "typmodout::pg_catalog.oid AS typmodoutoid, ");- else+ if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])+ {+ /* Set up query for type-specific details */
appendPQExpBufferStr(query,
- "'-' AS typmodin, '-' AS typmodout, "- "0 AS typmodinoid, 0 AS typmodoutoid, ");+ "PREPARE dumpBaseType(pg_catalog.oid) AS\n");- if (fout->remoteVersion >= 80400)- appendPQExpBufferStr(query,- "typcategory, typispreferred, ");- else- appendPQExpBufferStr(query,- "'U' AS typcategory, false AS typispreferred, ");+ appendPQExpBufferStr(query, "SELECT typlen, "+ "typinput, typoutput, typreceive, typsend, "+ "typreceive::pg_catalog.oid AS typreceiveoid, "+ "typsend::pg_catalog.oid AS typsendoid, "+ "typanalyze, "+ "typanalyze::pg_catalog.oid AS typanalyzeoid, "+ "typdelim, typbyval, typalign, typstorage, ");- if (fout->remoteVersion >= 90100)- appendPQExpBufferStr(query, "(typcollation <> 0) AS typcollatable, ");- else- appendPQExpBufferStr(query, "false AS typcollatable, ");+ if (fout->remoteVersion >= 80300)+ appendPQExpBufferStr(query,+ "typmodin, typmodout, "+ "typmodin::pg_catalog.oid AS typmodinoid, "+ "typmodout::pg_catalog.oid AS typmodoutoid, ");+ else+ appendPQExpBufferStr(query,+ "'-' AS typmodin, '-' AS typmodout, "+ "0 AS typmodinoid, 0 AS typmodoutoid, ");- if (fout->remoteVersion >= 140000)- appendPQExpBufferStr(query,- "typsubscript, "- "typsubscript::pg_catalog.oid AS typsubscriptoid, ");- else- appendPQExpBufferStr(query,- "'-' AS typsubscript, 0 AS typsubscriptoid, ");+ if (fout->remoteVersion >= 80400)+ appendPQExpBufferStr(query,+ "typcategory, typispreferred, ");+ else+ appendPQExpBufferStr(query,+ "'U' AS typcategory, false AS typispreferred, ");- /* Before 8.4, pg_get_expr does not allow 0 for its second arg */- if (fout->remoteVersion >= 80400)- appendPQExpBufferStr(query,- "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault ");- else- appendPQExpBufferStr(query,- "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault ");+ if (fout->remoteVersion >= 90100)+ appendPQExpBufferStr(query, "(typcollation <> 0) AS typcollatable, ");+ else+ appendPQExpBufferStr(query, "false AS typcollatable, ");- appendPQExpBuffer(query, "FROM pg_catalog.pg_type "- "WHERE oid = '%u'::pg_catalog.oid",+ if (fout->remoteVersion >= 140000)+ appendPQExpBufferStr(query,+ "typsubscript, "+ "typsubscript::pg_catalog.oid AS typsubscriptoid, ");+ else+ appendPQExpBufferStr(query,+ "'-' AS typsubscript, 0 AS typsubscriptoid, ");++ /* Before 8.4, pg_get_expr does not allow 0 for its second arg */+ if (fout->remoteVersion >= 80400)+ appendPQExpBufferStr(query,+ "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault ");+ else+ appendPQExpBufferStr(query,+ "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault ");++ appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "+ "WHERE oid = $1");++ ExecuteSqlStatement(fout, query->data);++ fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;+ }++ printfPQExpBuffer(query,+ "EXECUTE dumpBaseType('%u')",
tyinfo->dobj.catId.oid);
res = ExecuteSqlQueryForSingleRow(fout, query->data);
@@ -11130,32 +11186,44 @@ dumpDomain(Archive *fout, const TypeInfo *tyinfo)
Oid typcollation;
bool typdefault_is_literal = false;
- /* Fetch domain specific details */- if (fout->remoteVersion >= 90100)+ if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
{
- /* typcollation is new in 9.1 */- appendPQExpBuffer(query, "SELECT t.typnotnull, "- "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "- "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "- "t.typdefault, "- "CASE WHEN t.typcollation <> u.typcollation "- "THEN t.typcollation ELSE 0 END AS typcollation "- "FROM pg_catalog.pg_type t "- "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "- "WHERE t.oid = '%u'::pg_catalog.oid",- tyinfo->dobj.catId.oid);- }- else- {- appendPQExpBuffer(query, "SELECT typnotnull, "- "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "- "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "- "typdefault, 0 AS typcollation "- "FROM pg_catalog.pg_type "- "WHERE oid = '%u'::pg_catalog.oid",- tyinfo->dobj.catId.oid);+ /* Set up query for domain-specific details */+ appendPQExpBufferStr(query,+ "PREPARE dumpDomain(pg_catalog.oid) AS\n");++ if (fout->remoteVersion >= 90100)+ {+ /* typcollation is new in 9.1 */+ appendPQExpBufferStr(query, "SELECT t.typnotnull, "+ "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "+ "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "+ "t.typdefault, "+ "CASE WHEN t.typcollation <> u.typcollation "+ "THEN t.typcollation ELSE 0 END AS typcollation "+ "FROM pg_catalog.pg_type t "+ "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "+ "WHERE t.oid = $1");+ }+ else+ {+ appendPQExpBufferStr(query, "SELECT typnotnull, "+ "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "+ "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "+ "typdefault, 0 AS typcollation "+ "FROM pg_catalog.pg_type "+ "WHERE oid = $1");+ }++ ExecuteSqlStatement(fout, query->data);++ fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
}
+ printfPQExpBuffer(query,+ "EXECUTE dumpDomain('%u')",+ tyinfo->dobj.catId.oid);+
res = ExecuteSqlQueryForSingleRow(fout, query->data);
typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
@@ -11308,45 +11376,57 @@ dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
int i;
int actual_atts;
- /* Fetch type specific details */- if (fout->remoteVersion >= 90100)- {- /*- * attcollation is new in 9.1. Since we only want to dump COLLATE- * clauses for attributes whose collation is different from their- * type's default, we use a CASE here to suppress uninteresting- * attcollations cheaply. atttypid will be 0 for dropped columns;- * collation does not matter for those.- */- appendPQExpBuffer(query, "SELECT a.attname, "- "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "- "a.attlen, a.attalign, a.attisdropped, "- "CASE WHEN a.attcollation <> at.typcollation "- "THEN a.attcollation ELSE 0 END AS attcollation "- "FROM pg_catalog.pg_type ct "- "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "- "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "- "WHERE ct.oid = '%u'::pg_catalog.oid "- "ORDER BY a.attnum ",- tyinfo->dobj.catId.oid);- }- else+ if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
{
- /*- * Since ALTER TYPE could not drop columns until 9.1, attisdropped- * should always be false.- */- appendPQExpBuffer(query, "SELECT a.attname, "- "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "- "a.attlen, a.attalign, a.attisdropped, "- "0 AS attcollation "- "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "- "WHERE ct.oid = '%u'::pg_catalog.oid "- "AND a.attrelid = ct.typrelid "- "ORDER BY a.attnum ",- tyinfo->dobj.catId.oid);+ /* Set up query for type-specific details */+ appendPQExpBufferStr(query,+ "PREPARE dumpCompositeType(pg_catalog.oid) AS\n");++ if (fout->remoteVersion >= 90100)+ {+ /*+ * attcollation is new in 9.1. Since we only want to dump COLLATE+ * clauses for attributes whose collation is different from their+ * type's default, we use a CASE here to suppress uninteresting+ * attcollations cheaply. atttypid will be 0 for dropped columns;+ * collation does not matter for those.+ */+ appendPQExpBufferStr(query, "SELECT a.attname, "+ "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "+ "a.attlen, a.attalign, a.attisdropped, "+ "CASE WHEN a.attcollation <> at.typcollation "+ "THEN a.attcollation ELSE 0 END AS attcollation "+ "FROM pg_catalog.pg_type ct "+ "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "+ "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "+ "WHERE ct.oid = $1 "+ "ORDER BY a.attnum");+ }+ else+ {+ /*+ * Since ALTER TYPE could not drop columns until 9.1, attisdropped+ * should always be false.+ */+ appendPQExpBufferStr(query, "SELECT a.attname, "+ "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "+ "a.attlen, a.attalign, a.attisdropped, "+ "0 AS attcollation "+ "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "+ "WHERE ct.oid = $1 "+ "AND a.attrelid = ct.typrelid "+ "ORDER BY a.attnum");+ }++ ExecuteSqlStatement(fout, query->data);++ fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
}
+ printfPQExpBuffer(query,+ "EXECUTE dumpCompositeType('%u')",+ tyinfo->dobj.catId.oid);+
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
ntups = PQntuples(res);
@@ -11965,96 +12045,109 @@ dumpFunc(Archive *fout, const FuncInfo *finfo)
delqry = createPQExpBuffer();
asPart = createPQExpBuffer();
- /* Fetch function-specific details */- appendPQExpBufferStr(query,- "SELECT\n"- "proretset,\n"- "prosrc,\n"- "probin,\n"- "provolatile,\n"- "proisstrict,\n"- "prosecdef,\n"- "lanname,\n");-- if (fout->remoteVersion >= 80300)- appendPQExpBufferStr(query,- "proconfig,\n"- "procost,\n"- "prorows,\n");- else- appendPQExpBufferStr(query,- "null AS proconfig,\n"- "0 AS procost,\n"- "0 AS prorows,\n");-- if (fout->remoteVersion >= 80400)+ if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
{
- /*- * In 8.4 and up we rely on pg_get_function_arguments and- * pg_get_function_result instead of examining proallargtypes etc.- */+ /* Set up query for function-specific details */
appendPQExpBufferStr(query,
- "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"- "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"- "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n");- }- else if (fout->remoteVersion >= 80100)- appendPQExpBufferStr(query,- "proallargtypes,\n"- "proargmodes,\n"- "proargnames,\n");- else- appendPQExpBufferStr(query,- "null AS proallargtypes,\n"- "null AS proargmodes,\n"- "proargnames,\n");+ "PREPARE dumpFunc(pg_catalog.oid) AS\n");- if (fout->remoteVersion >= 90200)- appendPQExpBufferStr(query,- "proleakproof,\n");- else
appendPQExpBufferStr(query,
- "false AS proleakproof,\n");+ "SELECT\n"+ "proretset,\n"+ "prosrc,\n"+ "probin,\n"+ "provolatile,\n"+ "proisstrict,\n"+ "prosecdef,\n"+ "lanname,\n");++ if (fout->remoteVersion >= 80300)+ appendPQExpBufferStr(query,+ "proconfig,\n"+ "procost,\n"+ "prorows,\n");+ else+ appendPQExpBufferStr(query,+ "null AS proconfig,\n"+ "0 AS procost,\n"+ "0 AS prorows,\n");- if (fout->remoteVersion >= 90500)- appendPQExpBufferStr(query,- "array_to_string(protrftypes, ' ') AS protrftypes,\n");+ if (fout->remoteVersion >= 80400)+ {+ /*+ * In 8.4 and up we rely on pg_get_function_arguments and+ * pg_get_function_result instead of examining proallargtypes etc.+ */+ appendPQExpBufferStr(query,+ "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"+ "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"+ "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n");+ }+ else if (fout->remoteVersion >= 80100)+ appendPQExpBufferStr(query,+ "proallargtypes,\n"+ "proargmodes,\n"+ "proargnames,\n");+ else+ appendPQExpBufferStr(query,+ "null AS proallargtypes,\n"+ "null AS proargmodes,\n"+ "proargnames,\n");- if (fout->remoteVersion >= 90600)- appendPQExpBufferStr(query,- "proparallel,\n");- else- appendPQExpBufferStr(query,- "'u' AS proparallel,\n");+ if (fout->remoteVersion >= 90200)+ appendPQExpBufferStr(query,+ "proleakproof,\n");+ else+ appendPQExpBufferStr(query,+ "false AS proleakproof,\n");- if (fout->remoteVersion >= 110000)- appendPQExpBufferStr(query,- "prokind,\n");- else if (fout->remoteVersion >= 80400)- appendPQExpBufferStr(query,- "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");- else- appendPQExpBufferStr(query,- "'f' AS prokind,\n");+ if (fout->remoteVersion >= 90500)+ appendPQExpBufferStr(query,+ "array_to_string(protrftypes, ' ') AS protrftypes,\n");- if (fout->remoteVersion >= 120000)- appendPQExpBufferStr(query,- "prosupport,\n");- else- appendPQExpBufferStr(query,- "'-' AS prosupport,\n");+ if (fout->remoteVersion >= 90600)+ appendPQExpBufferStr(query,+ "proparallel,\n");+ else+ appendPQExpBufferStr(query,+ "'u' AS proparallel,\n");++ if (fout->remoteVersion >= 110000)+ appendPQExpBufferStr(query,+ "prokind,\n");+ else if (fout->remoteVersion >= 80400)+ appendPQExpBufferStr(query,+ "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");+ else+ appendPQExpBufferStr(query,+ "'f' AS prokind,\n");++ if (fout->remoteVersion >= 120000)+ appendPQExpBufferStr(query,+ "prosupport,\n");+ else+ appendPQExpBufferStr(query,+ "'-' AS prosupport,\n");++ if (fout->remoteVersion >= 140000)+ appendPQExpBufferStr(query,+ "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");+ else+ appendPQExpBufferStr(query,+ "NULL AS prosqlbody\n");- if (fout->remoteVersion >= 140000)- appendPQExpBufferStr(query,- "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");- else
appendPQExpBufferStr(query,
- "NULL AS prosqlbody\n");+ "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"+ "WHERE p.oid = $1 "+ "AND l.oid = p.prolang");- appendPQExpBuffer(query,- "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"- "WHERE p.oid = '%u'::pg_catalog.oid "- "AND l.oid = p.prolang",+ ExecuteSqlStatement(fout, query->data);++ fout->is_prepared[PREPQUERY_DUMPFUNC] = true;+ }++ printfPQExpBuffer(query,+ "EXECUTE dumpFunc('%u')",
finfo->dobj.catId.oid);
res = ExecuteSqlQueryForSingleRow(fout, query->data);
@@ -12721,38 +12814,51 @@ dumpOpr(Archive *fout, const OprInfo *oprinfo)
oprid = createPQExpBuffer();
details = createPQExpBuffer();
- if (fout->remoteVersion >= 80300)- {- appendPQExpBuffer(query, "SELECT oprkind, "- "oprcode::pg_catalog.regprocedure, "- "oprleft::pg_catalog.regtype, "- "oprright::pg_catalog.regtype, "- "oprcom, "- "oprnegate, "- "oprrest::pg_catalog.regprocedure, "- "oprjoin::pg_catalog.regprocedure, "- "oprcanmerge, oprcanhash "- "FROM pg_catalog.pg_operator "- "WHERE oid = '%u'::pg_catalog.oid",- oprinfo->dobj.catId.oid);- }- else+ if (!fout->is_prepared[PREPQUERY_DUMPOPR])
{
- appendPQExpBuffer(query, "SELECT oprkind, "- "oprcode::pg_catalog.regprocedure, "- "oprleft::pg_catalog.regtype, "- "oprright::pg_catalog.regtype, "- "oprcom, "- "oprnegate, "- "oprrest::pg_catalog.regprocedure, "- "oprjoin::pg_catalog.regprocedure, "- "(oprlsortop != 0) AS oprcanmerge, "- "oprcanhash "- "FROM pg_catalog.pg_operator "- "WHERE oid = '%u'::pg_catalog.oid",- oprinfo->dobj.catId.oid);+ /* Set up query for operator-specific details */+ appendPQExpBufferStr(query,+ "PREPARE dumpOpr(pg_catalog.oid) AS\n");++ if (fout->remoteVersion >= 80300)+ {+ appendPQExpBufferStr(query, "SELECT oprkind, "+ "oprcode::pg_catalog.regprocedure, "+ "oprleft::pg_catalog.regtype, "+ "oprright::pg_catalog.regtype, "+ "oprcom, "+ "oprnegate, "+ "oprrest::pg_catalog.regprocedure, "+ "oprjoin::pg_catalog.regprocedure, "+ "oprcanmerge, oprcanhash "+ "FROM pg_catalog.pg_operator "+ "WHERE oid = $1");+ }+ else+ {+ appendPQExpBufferStr(query, "SELECT oprkind, "+ "oprcode::pg_catalog.regprocedure, "+ "oprleft::pg_catalog.regtype, "+ "oprright::pg_catalog.regtype, "+ "oprcom, "+ "oprnegate, "+ "oprrest::pg_catalog.regprocedure, "+ "oprjoin::pg_catalog.regprocedure, "+ "(oprlsortop != 0) AS oprcanmerge, "+ "oprcanhash "+ "FROM pg_catalog.pg_operator "+ "WHERE oid = $1");+ }++ ExecuteSqlStatement(fout, query->data);++ fout->is_prepared[PREPQUERY_DUMPOPR] = true;
}
+ printfPQExpBuffer(query,+ "EXECUTE dumpOpr('%u')",+ oprinfo->dobj.catId.oid);+
res = ExecuteSqlQueryForSingleRow(fout, query->data);
i_oprkind = PQfnumber(res, "oprkind");
@@ -14018,77 +14124,90 @@ dumpAgg(Archive *fout, const AggInfo *agginfo)
delq = createPQExpBuffer();
details = createPQExpBuffer();
- /* Get aggregate-specific details */- appendPQExpBufferStr(query,- "SELECT\n"- "aggtransfn,\n"- "aggfinalfn,\n"- "aggtranstype::pg_catalog.regtype,\n"- "agginitval,\n");-- if (fout->remoteVersion >= 80100)- appendPQExpBufferStr(query,- "aggsortop,\n");- else+ if (!fout->is_prepared[PREPQUERY_DUMPAGG])+ {+ /* Set up query for aggregate-specific details */
appendPQExpBufferStr(query,
- "0 AS aggsortop,\n");+ "PREPARE dumpAgg(pg_catalog.oid) AS\n");- if (fout->remoteVersion >= 80400)
appendPQExpBufferStr(query,
- "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"- "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");+ "SELECT "+ "aggtransfn,\n"+ "aggfinalfn,\n"+ "aggtranstype::pg_catalog.regtype,\n"+ "agginitval,\n");- if (fout->remoteVersion >= 90400)- appendPQExpBufferStr(query,- "aggkind,\n"- "aggmtransfn,\n"- "aggminvtransfn,\n"- "aggmfinalfn,\n"- "aggmtranstype::pg_catalog.regtype,\n"- "aggfinalextra,\n"- "aggmfinalextra,\n"- "aggtransspace,\n"- "aggmtransspace,\n"- "aggminitval,\n");- else- appendPQExpBufferStr(query,- "'n' AS aggkind,\n"- "'-' AS aggmtransfn,\n"- "'-' AS aggminvtransfn,\n"- "'-' AS aggmfinalfn,\n"- "0 AS aggmtranstype,\n"- "false AS aggfinalextra,\n"- "false AS aggmfinalextra,\n"- "0 AS aggtransspace,\n"- "0 AS aggmtransspace,\n"- "NULL AS aggminitval,\n");+ if (fout->remoteVersion >= 80100)+ appendPQExpBufferStr(query,+ "aggsortop,\n");+ else+ appendPQExpBufferStr(query,+ "0 AS aggsortop,\n");- if (fout->remoteVersion >= 90600)- appendPQExpBufferStr(query,- "aggcombinefn,\n"- "aggserialfn,\n"- "aggdeserialfn,\n"- "proparallel,\n");- else- appendPQExpBufferStr(query,- "'-' AS aggcombinefn,\n"- "'-' AS aggserialfn,\n"- "'-' AS aggdeserialfn,\n"- "'u' AS proparallel,\n");+ if (fout->remoteVersion >= 80400)+ appendPQExpBufferStr(query,+ "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"+ "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");++ if (fout->remoteVersion >= 90400)+ appendPQExpBufferStr(query,+ "aggkind,\n"+ "aggmtransfn,\n"+ "aggminvtransfn,\n"+ "aggmfinalfn,\n"+ "aggmtranstype::pg_catalog.regtype,\n"+ "aggfinalextra,\n"+ "aggmfinalextra,\n"+ "aggtransspace,\n"+ "aggmtransspace,\n"+ "aggminitval,\n");+ else+ appendPQExpBufferStr(query,+ "'n' AS aggkind,\n"+ "'-' AS aggmtransfn,\n"+ "'-' AS aggminvtransfn,\n"+ "'-' AS aggmfinalfn,\n"+ "0 AS aggmtranstype,\n"+ "false AS aggfinalextra,\n"+ "false AS aggmfinalextra,\n"+ "0 AS aggtransspace,\n"+ "0 AS aggmtransspace,\n"+ "NULL AS aggminitval,\n");++ if (fout->remoteVersion >= 90600)+ appendPQExpBufferStr(query,+ "aggcombinefn,\n"+ "aggserialfn,\n"+ "aggdeserialfn,\n"+ "proparallel,\n");+ else+ appendPQExpBufferStr(query,+ "'-' AS aggcombinefn,\n"+ "'-' AS aggserialfn,\n"+ "'-' AS aggdeserialfn,\n"+ "'u' AS proparallel,\n");++ if (fout->remoteVersion >= 110000)+ appendPQExpBufferStr(query,+ "aggfinalmodify,\n"+ "aggmfinalmodify\n");+ else+ appendPQExpBufferStr(query,+ "'0' AS aggfinalmodify,\n"+ "'0' AS aggmfinalmodify\n");- if (fout->remoteVersion >= 110000)- appendPQExpBufferStr(query,- "aggfinalmodify,\n"- "aggmfinalmodify\n");- else
appendPQExpBufferStr(query,
- "'0' AS aggfinalmodify,\n"- "'0' AS aggmfinalmodify\n");+ "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "+ "WHERE a.aggfnoid = p.oid "+ "AND p.oid = $1");- appendPQExpBuffer(query,- "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "- "WHERE a.aggfnoid = p.oid "- "AND p.oid = '%u'::pg_catalog.oid",+ ExecuteSqlStatement(fout, query->data);++ fout->is_prepared[PREPQUERY_DUMPAGG] = true;+ }++ printfPQExpBuffer(query,+ "EXECUTE dumpAgg('%u')",
agginfo->aggfn.dobj.catId.oid);
res = ExecuteSqlQueryForSingleRow(fout, query->data);
@@ -15502,46 +15621,59 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
PGresult *res;
int i;
- if (fout->remoteVersion >= 90600)+ if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
{
- /*- * In principle we should call acldefault('c', relowner) to get- * the default ACL for a column. However, we don't currently- * store the numeric OID of the relowner in TableInfo. We could- * convert the owner name using regrole, but that creates a risk- * of failure due to concurrent role renames. Given that the- * default ACL for columns is empty and is likely to stay that- * way, it's not worth extra cycles and risk to avoid hard-wiring- * that knowledge here.- */- appendPQExpBuffer(query,- "SELECT at.attname, "- "at.attacl, "- "'{}' AS acldefault, "- "pip.privtype, pip.initprivs "- "FROM pg_catalog.pg_attribute at "- "LEFT JOIN pg_catalog.pg_init_privs pip ON "- "(at.attrelid = pip.objoid "- "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "- "AND at.attnum = pip.objsubid) "- "WHERE at.attrelid = '%u'::pg_catalog.oid AND "- "NOT at.attisdropped "- "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "- "ORDER BY at.attnum",- tbinfo->dobj.catId.oid);- }- else- {- appendPQExpBuffer(query,- "SELECT attname, attacl, '{}' AS acldefault, "- "NULL AS privtype, NULL AS initprivs "- "FROM pg_catalog.pg_attribute "- "WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped "- "AND attacl IS NOT NULL "- "ORDER BY attnum",- tbinfo->dobj.catId.oid);+ /* Set up query for column ACLs */+ appendPQExpBufferStr(query,+ "PREPARE getColumnACLs(pg_catalog.oid) AS\n");++ if (fout->remoteVersion >= 90600)+ {+ /*+ * In principle we should call acldefault('c', relowner) to+ * get the default ACL for a column. However, we don't+ * currently store the numeric OID of the relowner in+ * TableInfo. We could convert the owner name using regrole,+ * but that creates a risk of failure due to concurrent role+ * renames. Given that the default ACL for columns is empty+ * and is likely to stay that way, it's not worth extra cycles+ * and risk to avoid hard-wiring that knowledge here.+ */+ appendPQExpBufferStr(query,+ "SELECT at.attname, "+ "at.attacl, "+ "'{}' AS acldefault, "+ "pip.privtype, pip.initprivs "+ "FROM pg_catalog.pg_attribute at "+ "LEFT JOIN pg_catalog.pg_init_privs pip ON "+ "(at.attrelid = pip.objoid "+ "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "+ "AND at.attnum = pip.objsubid) "+ "WHERE at.attrelid = $1 AND "+ "NOT at.attisdropped "+ "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "+ "ORDER BY at.attnum");+ }+ else+ {+ appendPQExpBufferStr(query,+ "SELECT attname, attacl, '{}' AS acldefault, "+ "NULL AS privtype, NULL AS initprivs "+ "FROM pg_catalog.pg_attribute "+ "WHERE attrelid = $1 AND NOT attisdropped "+ "AND attacl IS NOT NULL "+ "ORDER BY attnum");+ }++ ExecuteSqlStatement(fout, query->data);++ fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
}
+ printfPQExpBuffer(query,+ "EXECUTE getColumnACLs('%u')",+ tbinfo->dobj.catId.oid);+
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
for (i = 0; i < PQntuples(res); i++)
@@ -16481,12 +16613,26 @@ dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
q = createPQExpBuffer();
- /* Fetch the partition's partbound */- appendPQExpBuffer(q,- "SELECT pg_get_expr(c.relpartbound, c.oid) "- "FROM pg_class c "- "WHERE c.oid = '%u'",+ if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])+ {+ /* Set up query for partbound details */+ appendPQExpBufferStr(q,+ "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");++ appendPQExpBufferStr(q,+ "SELECT pg_get_expr(c.relpartbound, c.oid) "+ "FROM pg_class c "+ "WHERE c.oid = $1");++ ExecuteSqlStatement(fout, q->data);++ fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;+ }++ printfPQExpBuffer(q,+ "EXECUTE dumpTableAttach('%u')",
attachinfo->partitionTbl->dobj.catId.oid);
+
res = ExecuteSqlQueryForSingleRow(fout, q->data);
partbound = PQgetvalue(res, 0, 0);
=
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: tgl@sss.pgh.pa.us, andres@anarazel.de, buschmann@nidsa.net
Subject: Re: Assorted improvements in pg_dump
In-Reply-To: <177444.1635287465@sss.pgh.pa.us>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox