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>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
<varlistentry>
|
||||||
<term><option>--section=<replaceable class="parameter">sectionname</replaceable></option></term>
|
<term><option>--section=<replaceable class="parameter">sectionname</replaceable></option></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -430,6 +430,21 @@ PostgreSQL documentation
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
<varlistentry>
|
||||||
<term><option>--use-set-session-authorization</></term>
|
<term><option>--use-set-session-authorization</></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -66,7 +66,7 @@ static int numExtensions;
|
|||||||
static ExtensionMemberId *extmembers;
|
static ExtensionMemberId *extmembers;
|
||||||
static int numextmembers;
|
static int numextmembers;
|
||||||
|
|
||||||
static void flagInhTables(TableInfo *tbinfo, int numTables,
|
static void flagInhTables(Archive *fout, TableInfo *tbinfo, int numTables,
|
||||||
InhInfo *inhinfo, int numInherits);
|
InhInfo *inhinfo, int numInherits);
|
||||||
static void flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables);
|
static void flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables);
|
||||||
static DumpableObject **buildIndexArray(void *objArray, int numObjs,
|
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 */
|
/* Link tables to parents, mark parents of target tables interesting */
|
||||||
if (g_verbose)
|
if (g_verbose)
|
||||||
write_msg(NULL, "finding inheritance relationships\n");
|
write_msg(NULL, "finding inheritance relationships\n");
|
||||||
flagInhTables(tblinfo, numTables, inhinfo, numInherits);
|
flagInhTables(fout, tblinfo, numTables, inhinfo, numInherits);
|
||||||
|
|
||||||
if (g_verbose)
|
if (g_verbose)
|
||||||
write_msg(NULL, "reading column info for interesting tables\n");
|
write_msg(NULL, "reading column info for interesting tables\n");
|
||||||
@ -294,8 +294,8 @@ getSchemaData(Archive *fout, int *numTablesPtr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* flagInhTables -
|
/* flagInhTables -
|
||||||
* Fill in parent link fields of every target table, and mark
|
* Fill in parent link fields of tables for which we need that information,
|
||||||
* parents of target tables as interesting
|
* and mark parents of target tables as interesting
|
||||||
*
|
*
|
||||||
* Note that only direct ancestors of targets are marked interesting.
|
* Note that only direct ancestors of targets are marked interesting.
|
||||||
* This is sufficient; we don't much care whether they inherited their
|
* This is sufficient; we don't much care whether they inherited their
|
||||||
@ -304,34 +304,53 @@ getSchemaData(Archive *fout, int *numTablesPtr)
|
|||||||
* modifies tblinfo
|
* modifies tblinfo
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
flagInhTables(TableInfo *tblinfo, int numTables,
|
flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
|
||||||
InhInfo *inhinfo, int numInherits)
|
InhInfo *inhinfo, int numInherits)
|
||||||
{
|
{
|
||||||
|
DumpOptions *dopt = fout->dopt;
|
||||||
int i,
|
int i,
|
||||||
j;
|
j;
|
||||||
int numParents;
|
|
||||||
TableInfo **parents;
|
|
||||||
|
|
||||||
for (i = 0; i < numTables; i++)
|
for (i = 0; i < numTables; i++)
|
||||||
{
|
{
|
||||||
|
bool find_parents = true;
|
||||||
|
bool mark_parents = true;
|
||||||
|
|
||||||
/* Some kinds never have parents */
|
/* Some kinds never have parents */
|
||||||
if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
|
if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
|
||||||
tblinfo[i].relkind == RELKIND_VIEW ||
|
tblinfo[i].relkind == RELKIND_VIEW ||
|
||||||
tblinfo[i].relkind == RELKIND_MATVIEW)
|
tblinfo[i].relkind == RELKIND_MATVIEW)
|
||||||
continue;
|
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)
|
if (!tblinfo[i].dobj.dump)
|
||||||
continue;
|
{
|
||||||
|
mark_parents = false;
|
||||||
|
|
||||||
/* Find all the immediate parent tables */
|
if (!dopt->load_via_partition_root ||
|
||||||
findParentsByOid(&tblinfo[i], inhinfo, numInherits);
|
!tblinfo[i].ispartition)
|
||||||
|
find_parents = false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Mark the parents as interesting for getTableAttrs */
|
/* If needed, find all the immediate parent tables. */
|
||||||
numParents = tblinfo[i].numParents;
|
if (find_parents)
|
||||||
parents = tblinfo[i].parents;
|
findParentsByOid(&tblinfo[i], inhinfo, numInherits);
|
||||||
for (j = 0; j < numParents; j++)
|
|
||||||
parents[j]->interesting = true;
|
/* 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 outputNoTablespaces;
|
||||||
int use_setsessauth;
|
int use_setsessauth;
|
||||||
int enable_row_security;
|
int enable_row_security;
|
||||||
|
int load_via_partition_root;
|
||||||
|
|
||||||
/* default, if no "inclusion" switches appear, is to dump everything */
|
/* default, if no "inclusion" switches appear, is to dump everything */
|
||||||
bool include_everything;
|
bool include_everything;
|
||||||
|
@ -269,6 +269,7 @@ static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
|
|||||||
const char *prefix, Archive *fout);
|
const char *prefix, Archive *fout);
|
||||||
static char *get_synchronized_snapshot(Archive *fout);
|
static char *get_synchronized_snapshot(Archive *fout);
|
||||||
static void setupDumpWorker(Archive *AHX);
|
static void setupDumpWorker(Archive *AHX);
|
||||||
|
static TableInfo *getRootTableInfo(TableInfo *tbinfo);
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -345,6 +346,7 @@ main(int argc, char **argv)
|
|||||||
{"lock-wait-timeout", required_argument, NULL, 2},
|
{"lock-wait-timeout", required_argument, NULL, 2},
|
||||||
{"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
|
{"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
|
||||||
{"quote-all-identifiers", no_argument, "e_all_identifiers, 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},
|
{"role", required_argument, NULL, 3},
|
||||||
{"section", required_argument, NULL, 5},
|
{"section", required_argument, NULL, 5},
|
||||||
{"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
|
{"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-tablespaces do not dump tablespace assignments\n"));
|
||||||
printf(_(" --no-unlogged-table-data do not dump unlogged table data\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(_(" --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(_(" --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(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
|
||||||
printf(_(" --snapshot=SNAPSHOT use given snapshot for the dump\n"));
|
printf(_(" --snapshot=SNAPSHOT use given snapshot for the dump\n"));
|
||||||
@ -1902,8 +1905,32 @@ dumpTableData_insert(Archive *fout, void *dcontext)
|
|||||||
if (insertStmt == NULL)
|
if (insertStmt == NULL)
|
||||||
{
|
{
|
||||||
insertStmt = createPQExpBuffer();
|
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 ",
|
appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
|
||||||
fmtId(classname));
|
classname);
|
||||||
|
|
||||||
/* corner case for zero-column table */
|
/* corner case for zero-column table */
|
||||||
if (nfields == 0)
|
if (nfields == 0)
|
||||||
@ -2025,6 +2052,27 @@ dumpTableData_insert(Archive *fout, void *dcontext)
|
|||||||
return 1;
|
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 -
|
* dumpTableData -
|
||||||
@ -2041,14 +2089,38 @@ dumpTableData(Archive *fout, TableDataInfo *tdinfo)
|
|||||||
PQExpBuffer clistBuf = createPQExpBuffer();
|
PQExpBuffer clistBuf = createPQExpBuffer();
|
||||||
DataDumperPtr dumpFn;
|
DataDumperPtr dumpFn;
|
||||||
char *copyStmt;
|
char *copyStmt;
|
||||||
|
const char *copyFrom;
|
||||||
|
|
||||||
if (!dopt->dump_inserts)
|
if (!dopt->dump_inserts)
|
||||||
{
|
{
|
||||||
/* Dump/restore using COPY */
|
/* Dump/restore using COPY */
|
||||||
dumpFn = dumpTableData_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 */
|
/* must use 2 steps here 'cause fmtId is nonreentrant */
|
||||||
appendPQExpBuffer(copyBuf, "COPY %s ",
|
appendPQExpBuffer(copyBuf, "COPY %s ",
|
||||||
fmtId(tbinfo->dobj.name));
|
copyFrom);
|
||||||
appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
|
appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
|
||||||
fmtCopyColumnList(tbinfo, clistBuf),
|
fmtCopyColumnList(tbinfo, clistBuf),
|
||||||
(tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
|
(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_unlogged_table_data = 0;
|
||||||
static int no_role_passwords = 0;
|
static int no_role_passwords = 0;
|
||||||
static int server_version;
|
static int server_version;
|
||||||
|
static int load_via_partition_root = 0;
|
||||||
|
|
||||||
static char role_catalog[10];
|
static char role_catalog[10];
|
||||||
#define PG_AUTHID "pg_authid"
|
#define PG_AUTHID "pg_authid"
|
||||||
@ -128,6 +129,7 @@ main(int argc, char *argv[])
|
|||||||
{"lock-wait-timeout", required_argument, NULL, 2},
|
{"lock-wait-timeout", required_argument, NULL, 2},
|
||||||
{"no-tablespaces", no_argument, &no_tablespaces, 1},
|
{"no-tablespaces", no_argument, &no_tablespaces, 1},
|
||||||
{"quote-all-identifiers", no_argument, "e_all_identifiers, 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},
|
{"role", required_argument, NULL, 3},
|
||||||
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
|
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
|
||||||
{"no-publications", no_argument, &no_publications, 1},
|
{"no-publications", no_argument, &no_publications, 1},
|
||||||
@ -385,6 +387,8 @@ main(int argc, char *argv[])
|
|||||||
appendPQExpBufferStr(pgdumpopts, " --no-tablespaces");
|
appendPQExpBufferStr(pgdumpopts, " --no-tablespaces");
|
||||||
if (quote_all_identifiers)
|
if (quote_all_identifiers)
|
||||||
appendPQExpBufferStr(pgdumpopts, " --quote-all-identifiers");
|
appendPQExpBufferStr(pgdumpopts, " --quote-all-identifiers");
|
||||||
|
if (load_via_partition_root)
|
||||||
|
appendPQExpBufferStr(pgdumpopts, " --load-via-partition-root");
|
||||||
if (use_setsessauth)
|
if (use_setsessauth)
|
||||||
appendPQExpBufferStr(pgdumpopts, " --use-set-session-authorization");
|
appendPQExpBufferStr(pgdumpopts, " --use-set-session-authorization");
|
||||||
if (no_publications)
|
if (no_publications)
|
||||||
@ -606,6 +610,7 @@ help(void)
|
|||||||
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
|
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
|
||||||
printf(_(" --no-unlogged-table-data do not dump unlogged table data\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(_(" --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"
|
printf(_(" --use-set-session-authorization\n"
|
||||||
" use SET SESSION AUTHORIZATION commands instead of\n"
|
" use SET SESSION AUTHORIZATION commands instead of\n"
|
||||||
" ALTER OWNER commands to set ownership\n"));
|
" ALTER OWNER commands to set ownership\n"));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user