@@ -119,6 +119,8 @@ static SimpleStringList table_exclude_patterns = {NULL, NULL};
119
119
static SimpleOidList table_exclude_oids = {NULL, NULL};
120
120
static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
121
121
static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
122
+ static SimpleStringList foreign_servers_include_patterns = {NULL, NULL};
123
+ static SimpleOidList foreign_servers_include_oids = {NULL, NULL};
122
124
123
125
124
126
/* placeholders for the delimiters for comments */
@@ -153,6 +155,9 @@ static void expand_schema_name_patterns(Archive *fout,
153
155
SimpleStringList *patterns,
154
156
SimpleOidList *oids,
155
157
bool strict_names);
158
+ static void expand_foreign_server_name_patterns(Archive *fout,
159
+ SimpleStringList *patterns,
160
+ SimpleOidList *oids);
156
161
static void expand_table_name_patterns(Archive *fout,
157
162
SimpleStringList *patterns,
158
163
SimpleOidList *oids,
@@ -385,6 +390,7 @@ main(int argc, char **argv)
385
390
{"no-sync", no_argument, NULL, 7},
386
391
{"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
387
392
{"rows-per-insert", required_argument, NULL, 10},
393
+ {"include-foreign-data", required_argument, NULL, 11},
388
394
389
395
{NULL, 0, NULL, 0}
390
396
};
@@ -600,6 +606,11 @@ main(int argc, char **argv)
600
606
dopt.dump_inserts = (int) rowsPerInsert;
601
607
break;
602
608
609
+ case 11: /* include foreign data */
610
+ simple_string_list_append(&foreign_servers_include_patterns,
611
+ optarg);
612
+ break;
613
+
603
614
default:
604
615
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
605
616
exit_nicely(1);
@@ -641,6 +652,12 @@ main(int argc, char **argv)
641
652
exit_nicely(1);
642
653
}
643
654
655
+ if (dopt.schemaOnly && foreign_servers_include_patterns.head != NULL)
656
+ fatal("options -s/--schema-only and --include-foreign-data cannot be used together");
657
+
658
+ if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
659
+ fatal("option --include-foreign-data is not supported with parallel backup");
660
+
644
661
if (dopt.dataOnly && dopt.outputClean)
645
662
{
646
663
pg_log_error("options -c/--clean and -a/--data-only cannot be used together");
@@ -808,6 +825,9 @@ main(int argc, char **argv)
808
825
&tabledata_exclude_oids,
809
826
false);
810
827
828
+ expand_foreign_server_name_patterns(fout, &foreign_servers_include_patterns,
829
+ &foreign_servers_include_oids);
830
+
811
831
/* non-matching exclusion patterns aren't an error */
812
832
813
833
/*
@@ -1011,6 +1031,9 @@ help(const char *progname)
1011
1031
printf(_(" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
1012
1032
printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n"));
1013
1033
printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
1034
+ printf(_(" --include-foreign-data=PATTERN\n"
1035
+ " include data of foreign tables in\n"
1036
+ " foreign servers matching PATTERN\n"));
1014
1037
printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
1015
1038
printf(_(" --load-via-partition-root load partitions via the root table\n"));
1016
1039
printf(_(" --no-comments do not dump comments\n"));
@@ -1330,6 +1353,51 @@ expand_schema_name_patterns(Archive *fout,
1330
1353
destroyPQExpBuffer(query);
1331
1354
}
1332
1355
1356
+ /*
1357
+ * Find the OIDs of all foreign servers matching the given list of patterns,
1358
+ * and append them to the given OID list.
1359
+ */
1360
+ static void
1361
+ expand_foreign_server_name_patterns(Archive *fout,
1362
+ SimpleStringList *patterns,
1363
+ SimpleOidList *oids)
1364
+ {
1365
+ PQExpBuffer query;
1366
+ PGresult *res;
1367
+ SimpleStringListCell *cell;
1368
+ int i;
1369
+
1370
+ if (patterns->head == NULL)
1371
+ return; /* nothing to do */
1372
+
1373
+ query = createPQExpBuffer();
1374
+
1375
+ /*
1376
+ * The loop below runs multiple SELECTs might sometimes result in
1377
+ * duplicate entries in the OID list, but we don't care.
1378
+ */
1379
+
1380
+ for (cell = patterns->head; cell; cell = cell->next)
1381
+ {
1382
+ appendPQExpBuffer(query,
1383
+ "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
1384
+ processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1385
+ false, NULL, "s.srvname", NULL, NULL);
1386
+
1387
+ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1388
+ if (PQntuples(res) == 0)
1389
+ fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
1390
+
1391
+ for (i = 0; i < PQntuples(res); i++)
1392
+ simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1393
+
1394
+ PQclear(res);
1395
+ resetPQExpBuffer(query);
1396
+ }
1397
+
1398
+ destroyPQExpBuffer(query);
1399
+ }
1400
+
1333
1401
/*
1334
1402
* Find the OIDs of all tables matching the given list of patterns,
1335
1403
* and append them to the given OID list. See also expand_dbname_patterns()
@@ -1775,7 +1843,6 @@ selectDumpableObject(DumpableObject *dobj, Archive *fout)
1775
1843
* - this routine is called by the Archiver when it wants the table
1776
1844
* to be dumped.
1777
1845
*/
1778
-
1779
1846
static int
1780
1847
dumpTableData_copy(Archive *fout, void *dcontext)
1781
1848
{
@@ -1806,7 +1873,12 @@ dumpTableData_copy(Archive *fout, void *dcontext)
1806
1873
*/
1807
1874
column_list = fmtCopyColumnList(tbinfo, clistBuf);
1808
1875
1809
- if (tdinfo->filtercond)
1876
+ /*
1877
+ * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
1878
+ * a filter condition was specified. For other cases a simple COPY
1879
+ * suffices.
1880
+ */
1881
+ if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
1810
1882
{
1811
1883
/* Note: this syntax is only supported in 8.2 and up */
1812
1884
appendPQExpBufferStr(q, "COPY (SELECT ");
@@ -1818,9 +1890,10 @@ dumpTableData_copy(Archive *fout, void *dcontext)
1818
1890
}
1819
1891
else
1820
1892
appendPQExpBufferStr(q, "* ");
1893
+
1821
1894
appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1822
1895
fmtQualifiedDumpable(tbinfo),
1823
- tdinfo->filtercond);
1896
+ tdinfo->filtercond ? tdinfo->filtercond : "" );
1824
1897
}
1825
1898
else
1826
1899
{
@@ -2336,8 +2409,11 @@ makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
2336
2409
/* Skip VIEWs (no data to dump) */
2337
2410
if (tbinfo->relkind == RELKIND_VIEW)
2338
2411
return;
2339
- /* Skip FOREIGN TABLEs (no data to dump) */
2340
- if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2412
+ /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
2413
+ if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
2414
+ (foreign_servers_include_oids.head == NULL ||
2415
+ !simple_oid_list_member(&foreign_servers_include_oids,
2416
+ tbinfo->foreign_server)))
2341
2417
return;
2342
2418
/* Skip partitioned tables (data in partitions) */
2343
2419
if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
@@ -5999,6 +6075,7 @@ getTables(Archive *fout, int *numTables)
5999
6075
int i_toastreloptions;
6000
6076
int i_reloftype;
6001
6077
int i_relpages;
6078
+ int i_foreignserver;
6002
6079
int i_is_identity_sequence;
6003
6080
int i_changed_acl;
6004
6081
int i_partkeydef;
@@ -6095,6 +6172,9 @@ getTables(Archive *fout, int *numTables)
6095
6172
"tc.relminmxid AS tminmxid, "
6096
6173
"c.relpersistence, c.relispopulated, "
6097
6174
"c.relreplident, c.relpages, am.amname, "
6175
+ "CASE WHEN c.relkind = 'f' THEN "
6176
+ "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
6177
+ "ELSE 0 END AS foreignserver, "
6098
6178
"CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6099
6179
"d.refobjid AS owning_tab, "
6100
6180
"d.refobjsubid AS owning_col, "
@@ -6185,6 +6265,9 @@ getTables(Archive *fout, int *numTables)
6185
6265
"c.relpersistence, c.relispopulated, "
6186
6266
"c.relreplident, c.relpages, "
6187
6267
"NULL AS amname, "
6268
+ "CASE WHEN c.relkind = 'f' THEN "
6269
+ "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
6270
+ "ELSE 0 END AS foreignserver, "
6188
6271
"CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6189
6272
"d.refobjid AS owning_tab, "
6190
6273
"d.refobjsubid AS owning_col, "
@@ -6235,6 +6318,9 @@ getTables(Archive *fout, int *numTables)
6235
6318
"c.relpersistence, c.relispopulated, "
6236
6319
"c.relreplident, c.relpages, "
6237
6320
"NULL AS amname, "
6321
+ "CASE WHEN c.relkind = 'f' THEN "
6322
+ "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
6323
+ "ELSE 0 END AS foreignserver, "
6238
6324
"CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6239
6325
"d.refobjid AS owning_tab, "
6240
6326
"d.refobjsubid AS owning_col, "
@@ -6285,6 +6371,9 @@ getTables(Archive *fout, int *numTables)
6285
6371
"c.relpersistence, c.relispopulated, "
6286
6372
"'d' AS relreplident, c.relpages, "
6287
6373
"NULL AS amname, "
6374
+ "CASE WHEN c.relkind = 'f' THEN "
6375
+ "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
6376
+ "ELSE 0 END AS foreignserver, "
6288
6377
"CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6289
6378
"d.refobjid AS owning_tab, "
6290
6379
"d.refobjsubid AS owning_col, "
@@ -6335,6 +6424,9 @@ getTables(Archive *fout, int *numTables)
6335
6424
"c.relpersistence, 't' as relispopulated, "
6336
6425
"'d' AS relreplident, c.relpages, "
6337
6426
"NULL AS amname, "
6427
+ "CASE WHEN c.relkind = 'f' THEN "
6428
+ "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
6429
+ "ELSE 0 END AS foreignserver, "
6338
6430
"CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6339
6431
"d.refobjid AS owning_tab, "
6340
6432
"d.refobjsubid AS owning_col, "
@@ -6383,6 +6475,7 @@ getTables(Archive *fout, int *numTables)
6383
6475
"'p' AS relpersistence, 't' as relispopulated, "
6384
6476
"'d' AS relreplident, c.relpages, "
6385
6477
"NULL AS amname, "
6478
+ "NULL AS foreignserver, "
6386
6479
"CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6387
6480
"d.refobjid AS owning_tab, "
6388
6481
"d.refobjsubid AS owning_col, "
@@ -6430,6 +6523,7 @@ getTables(Archive *fout, int *numTables)
6430
6523
"'p' AS relpersistence, 't' as relispopulated, "
6431
6524
"'d' AS relreplident, c.relpages, "
6432
6525
"NULL AS amname, "
6526
+ "NULL AS foreignserver, "
6433
6527
"NULL AS reloftype, "
6434
6528
"d.refobjid AS owning_tab, "
6435
6529
"d.refobjsubid AS owning_col, "
@@ -6477,6 +6571,7 @@ getTables(Archive *fout, int *numTables)
6477
6571
"'p' AS relpersistence, 't' as relispopulated, "
6478
6572
"'d' AS relreplident, c.relpages, "
6479
6573
"NULL AS amname, "
6574
+ "NULL AS foreignserver, "
6480
6575
"NULL AS reloftype, "
6481
6576
"d.refobjid AS owning_tab, "
6482
6577
"d.refobjsubid AS owning_col, "
@@ -6523,6 +6618,7 @@ getTables(Archive *fout, int *numTables)
6523
6618
"'p' AS relpersistence, 't' as relispopulated, "
6524
6619
"'d' AS relreplident, relpages, "
6525
6620
"NULL AS amname, "
6621
+ "NULL AS foreignserver, "
6526
6622
"NULL AS reloftype, "
6527
6623
"d.refobjid AS owning_tab, "
6528
6624
"d.refobjsubid AS owning_col, "
@@ -6590,6 +6686,7 @@ getTables(Archive *fout, int *numTables)
6590
6686
i_relispopulated = PQfnumber(res, "relispopulated");
6591
6687
i_relreplident = PQfnumber(res, "relreplident");
6592
6688
i_relpages = PQfnumber(res, "relpages");
6689
+ i_foreignserver = PQfnumber(res, "foreignserver");
6593
6690
i_owning_tab = PQfnumber(res, "owning_tab");
6594
6691
i_owning_col = PQfnumber(res, "owning_col");
6595
6692
i_reltablespace = PQfnumber(res, "reltablespace");
@@ -6714,6 +6811,9 @@ getTables(Archive *fout, int *numTables)
6714
6811
tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
6715
6812
tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
6716
6813
6814
+ /* foreign server */
6815
+ tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
6816
+
6717
6817
/*
6718
6818
* Read-lock target tables to make sure they aren't DROPPED or altered
6719
6819
* in schema before we get around to dumping them.
0 commit comments