mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-18 18:44:06 +08:00
pg_dump: Add a --load-via-partition-root option.
Rushabh Lathia, reviewed and somewhat revised by me. Testing by Rajkumar Raghuwanshi. Discussion: http://postgr.es/m/CAGPqQf0C1he087bz9xRBOGZBuESYz9X=Fp8Ca_g+TfHgAff75g@mail.gmail.com
This commit is contained in:
parent
d2bc501573
commit
23d7680d04
@ -888,6 +888,21 @@ PostgreSQL documentation
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--load-via-partition-root</></term>
|
||||
<listitem>
|
||||
<para>
|
||||
When dumping a COPY or INSERT statement for a partitioned table,
|
||||
target the root of the partitioning hierarchy which contains it rather
|
||||
than the partition itself. This may be useful when reloading data on
|
||||
a server where rows do not always fall into the same partitions as
|
||||
they did on the original server. This could happen, for example, if
|
||||
the partitioning column is of type text and the two system have
|
||||
different definitions of the collation used to partition the data.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--section=<replaceable class="parameter">sectionname</replaceable></option></term>
|
||||
<listitem>
|
||||
|
@ -430,6 +430,21 @@ PostgreSQL documentation
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--load-via-partition-root</></term>
|
||||
<listitem>
|
||||
<para>
|
||||
When dumping a COPY or INSERT statement for a partitioned table,
|
||||
target the root of the partitioning hierarchy which contains it rather
|
||||
than the partition itself. This may be useful when reloading data on
|
||||
a server where rows do not always fall into the same partitions as
|
||||
they did on the original server. This could happen, for example, if
|
||||
the partitioning column is of type text and the two system have
|
||||
different definitions of the collation used to partition the data.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--use-set-session-authorization</></term>
|
||||
<listitem>
|
||||
|
@ -66,7 +66,7 @@ static int numExtensions;
|
||||
static ExtensionMemberId *extmembers;
|
||||
static int numextmembers;
|
||||
|
||||
static void flagInhTables(TableInfo *tbinfo, int numTables,
|
||||
static void flagInhTables(Archive *fout, TableInfo *tbinfo, int numTables,
|
||||
InhInfo *inhinfo, int numInherits);
|
||||
static void flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables);
|
||||
static DumpableObject **buildIndexArray(void *objArray, int numObjs,
|
||||
@ -243,7 +243,7 @@ getSchemaData(Archive *fout, int *numTablesPtr)
|
||||
/* Link tables to parents, mark parents of target tables interesting */
|
||||
if (g_verbose)
|
||||
write_msg(NULL, "finding inheritance relationships\n");
|
||||
flagInhTables(tblinfo, numTables, inhinfo, numInherits);
|
||||
flagInhTables(fout, tblinfo, numTables, inhinfo, numInherits);
|
||||
|
||||
if (g_verbose)
|
||||
write_msg(NULL, "reading column info for interesting tables\n");
|
||||
@ -294,8 +294,8 @@ getSchemaData(Archive *fout, int *numTablesPtr)
|
||||
}
|
||||
|
||||
/* flagInhTables -
|
||||
* Fill in parent link fields of every target table, and mark
|
||||
* parents of target tables as interesting
|
||||
* Fill in parent link fields of tables for which we need that information,
|
||||
* and mark parents of target tables as interesting
|
||||
*
|
||||
* Note that only direct ancestors of targets are marked interesting.
|
||||
* This is sufficient; we don't much care whether they inherited their
|
||||
@ -304,34 +304,53 @@ getSchemaData(Archive *fout, int *numTablesPtr)
|
||||
* modifies tblinfo
|
||||
*/
|
||||
static void
|
||||
flagInhTables(TableInfo *tblinfo, int numTables,
|
||||
flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
|
||||
InhInfo *inhinfo, int numInherits)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
int i,
|
||||
j;
|
||||
int numParents;
|
||||
TableInfo **parents;
|
||||
|
||||
for (i = 0; i < numTables; i++)
|
||||
{
|
||||
bool find_parents = true;
|
||||
bool mark_parents = true;
|
||||
|
||||
/* Some kinds never have parents */
|
||||
if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
|
||||
tblinfo[i].relkind == RELKIND_VIEW ||
|
||||
tblinfo[i].relkind == RELKIND_MATVIEW)
|
||||
continue;
|
||||
|
||||
/* Don't bother computing anything for non-target tables, either */
|
||||
/*
|
||||
* Normally, we don't bother computing anything for non-target tables,
|
||||
* but if load-via-partition-root is specified, we gather information
|
||||
* on every partition in the system so that getRootTableInfo can trace
|
||||
* from any given to leaf partition all the way up to the root. (We
|
||||
* don't need to mark them as interesting for getTableAttrs, though.)
|
||||
*/
|
||||
if (!tblinfo[i].dobj.dump)
|
||||
continue;
|
||||
{
|
||||
mark_parents = false;
|
||||
|
||||
/* Find all the immediate parent tables */
|
||||
findParentsByOid(&tblinfo[i], inhinfo, numInherits);
|
||||
if (!dopt->load_via_partition_root ||
|
||||
!tblinfo[i].ispartition)
|
||||
find_parents = false;
|
||||
}
|
||||
|
||||
/* Mark the parents as interesting for getTableAttrs */
|
||||
numParents = tblinfo[i].numParents;
|
||||
parents = tblinfo[i].parents;
|
||||
for (j = 0; j < numParents; j++)
|
||||
parents[j]->interesting = true;
|
||||
/* If needed, find all the immediate parent tables. */
|
||||
if (find_parents)
|
||||
findParentsByOid(&tblinfo[i], inhinfo, numInherits);
|
||||
|
||||
/* If needed, mark the parents as interesting for getTableAttrs. */
|
||||
if (mark_parents)
|
||||
{
|
||||
int numParents = tblinfo[i].numParents;
|
||||
TableInfo **parents = tblinfo[i].parents;
|
||||
|
||||
for (j = 0; j < numParents; j++)
|
||||
parents[j]->interesting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,6 +157,7 @@ typedef struct _dumpOptions
|
||||
int outputNoTablespaces;
|
||||
int use_setsessauth;
|
||||
int enable_row_security;
|
||||
int load_via_partition_root;
|
||||
|
||||
/* default, if no "inclusion" switches appear, is to dump everything */
|
||||
bool include_everything;
|
||||
|
@ -269,6 +269,7 @@ static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
|
||||
const char *prefix, Archive *fout);
|
||||
static char *get_synchronized_snapshot(Archive *fout);
|
||||
static void setupDumpWorker(Archive *AHX);
|
||||
static TableInfo *getRootTableInfo(TableInfo *tbinfo);
|
||||
|
||||
|
||||
int
|
||||
@ -345,6 +346,7 @@ main(int argc, char **argv)
|
||||
{"lock-wait-timeout", required_argument, NULL, 2},
|
||||
{"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
|
||||
{"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
|
||||
{"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
|
||||
{"role", required_argument, NULL, 3},
|
||||
{"section", required_argument, NULL, 5},
|
||||
{"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
|
||||
@ -959,6 +961,7 @@ help(const char *progname)
|
||||
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
|
||||
printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
|
||||
printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
|
||||
printf(_(" --load-via-partition-root load partitions via the root table\n"));
|
||||
printf(_(" --section=SECTION dump named section (pre-data, data, or post-data)\n"));
|
||||
printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
|
||||
printf(_(" --snapshot=SNAPSHOT use given snapshot for the dump\n"));
|
||||
@ -1902,8 +1905,32 @@ dumpTableData_insert(Archive *fout, void *dcontext)
|
||||
if (insertStmt == NULL)
|
||||
{
|
||||
insertStmt = createPQExpBuffer();
|
||||
|
||||
/*
|
||||
* When load-via-partition-root is set, get the root table
|
||||
* name for the partition table, so that we can reload data
|
||||
* through the root table.
|
||||
*/
|
||||
if (dopt->load_via_partition_root && tbinfo->ispartition)
|
||||
{
|
||||
TableInfo *parentTbinfo;
|
||||
|
||||
parentTbinfo = getRootTableInfo(tbinfo);
|
||||
|
||||
/*
|
||||
* When we loading data through the root, we will qualify
|
||||
* the table name. This is needed because earlier
|
||||
* search_path will be set for the partition table.
|
||||
*/
|
||||
classname = (char *) fmtQualifiedId(fout->remoteVersion,
|
||||
parentTbinfo->dobj.namespace->dobj.name,
|
||||
parentTbinfo->dobj.name);
|
||||
}
|
||||
else
|
||||
classname = fmtId(tbinfo->dobj.name);
|
||||
|
||||
appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
|
||||
fmtId(classname));
|
||||
classname);
|
||||
|
||||
/* corner case for zero-column table */
|
||||
if (nfields == 0)
|
||||
@ -2025,6 +2052,27 @@ dumpTableData_insert(Archive *fout, void *dcontext)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* getRootTableInfo:
|
||||
* get the root TableInfo for the given partition table.
|
||||
*/
|
||||
static TableInfo *
|
||||
getRootTableInfo(TableInfo *tbinfo)
|
||||
{
|
||||
TableInfo *parentTbinfo;
|
||||
|
||||
Assert(tbinfo->ispartition);
|
||||
Assert(tbinfo->numParents == 1);
|
||||
|
||||
parentTbinfo = tbinfo->parents[0];
|
||||
while (parentTbinfo->ispartition)
|
||||
{
|
||||
Assert(parentTbinfo->numParents == 1);
|
||||
parentTbinfo = parentTbinfo->parents[0];
|
||||
}
|
||||
|
||||
return parentTbinfo;
|
||||
}
|
||||
|
||||
/*
|
||||
* dumpTableData -
|
||||
@ -2041,14 +2089,38 @@ dumpTableData(Archive *fout, TableDataInfo *tdinfo)
|
||||
PQExpBuffer clistBuf = createPQExpBuffer();
|
||||
DataDumperPtr dumpFn;
|
||||
char *copyStmt;
|
||||
const char *copyFrom;
|
||||
|
||||
if (!dopt->dump_inserts)
|
||||
{
|
||||
/* Dump/restore using COPY */
|
||||
dumpFn = dumpTableData_copy;
|
||||
|
||||
/*
|
||||
* When load-via-partition-root is set, get the root table name for
|
||||
* the partition table, so that we can reload data through the root
|
||||
* table.
|
||||
*/
|
||||
if (dopt->load_via_partition_root && tbinfo->ispartition)
|
||||
{
|
||||
TableInfo *parentTbinfo;
|
||||
|
||||
parentTbinfo = getRootTableInfo(tbinfo);
|
||||
|
||||
/*
|
||||
* When we load data through the root, we will qualify the table
|
||||
* name, because search_path is set for the partition.
|
||||
*/
|
||||
copyFrom = fmtQualifiedId(fout->remoteVersion,
|
||||
parentTbinfo->dobj.namespace->dobj.name,
|
||||
parentTbinfo->dobj.name);
|
||||
}
|
||||
else
|
||||
copyFrom = fmtId(tbinfo->dobj.name);
|
||||
|
||||
/* must use 2 steps here 'cause fmtId is nonreentrant */
|
||||
appendPQExpBuffer(copyBuf, "COPY %s ",
|
||||
fmtId(tbinfo->dobj.name));
|
||||
copyFrom);
|
||||
appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
|
||||
fmtCopyColumnList(tbinfo, clistBuf),
|
||||
(tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
|
||||
|
@ -80,6 +80,7 @@ static int no_subscriptions = 0;
|
||||
static int no_unlogged_table_data = 0;
|
||||
static int no_role_passwords = 0;
|
||||
static int server_version;
|
||||
static int load_via_partition_root = 0;
|
||||
|
||||
static char role_catalog[10];
|
||||
#define PG_AUTHID "pg_authid"
|
||||
@ -128,6 +129,7 @@ main(int argc, char *argv[])
|
||||
{"lock-wait-timeout", required_argument, NULL, 2},
|
||||
{"no-tablespaces", no_argument, &no_tablespaces, 1},
|
||||
{"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
|
||||
{"load-via-partition-root", no_argument, &load_via_partition_root, 1},
|
||||
{"role", required_argument, NULL, 3},
|
||||
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
|
||||
{"no-publications", no_argument, &no_publications, 1},
|
||||
@ -385,6 +387,8 @@ main(int argc, char *argv[])
|
||||
appendPQExpBufferStr(pgdumpopts, " --no-tablespaces");
|
||||
if (quote_all_identifiers)
|
||||
appendPQExpBufferStr(pgdumpopts, " --quote-all-identifiers");
|
||||
if (load_via_partition_root)
|
||||
appendPQExpBufferStr(pgdumpopts, " --load-via-partition-root");
|
||||
if (use_setsessauth)
|
||||
appendPQExpBufferStr(pgdumpopts, " --use-set-session-authorization");
|
||||
if (no_publications)
|
||||
@ -606,6 +610,7 @@ help(void)
|
||||
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
|
||||
printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
|
||||
printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
|
||||
printf(_(" --load-via-partition-root load partitions via the root table\n"));
|
||||
printf(_(" --use-set-session-authorization\n"
|
||||
" use SET SESSION AUTHORIZATION commands instead of\n"
|
||||
" ALTER OWNER commands to set ownership\n"));
|
||||
|
Loading…
Reference in New Issue
Block a user