Skip to content

Commit d024260

Browse files
committed
Check existency of table/schema for -t/-n option (pg_dump/pg_restore)
Patch provides command line option --strict-names which requires that at least one table/schema should present for each -t/-n option. Pavel Stehule <pavel.stehule@gmail.com>
1 parent b5217d6 commit d024260

File tree

8 files changed

+157
-30
lines changed

8 files changed

+157
-30
lines changed

doc/src/sgml/ref/pg_dump.sgml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,23 @@ PostgreSQL documentation
544544
</listitem>
545545
</varlistentry>
546546

547+
<varlistentry>
548+
<term><option>--strict-names</></term>
549+
<listitem>
550+
<para>
551+
Require that each schema (-n / --schema) and table (-t / --table)
552+
qualifier match at least one schema/table in the database to be dumped.
553+
Note that if none of the schema/table qualifiers find matches pg_dump
554+
will generate an error even without --strict-names.
555+
</para>
556+
<para>
557+
This option has no effect on -N/--exclude-schema, -T/--exclude_table
558+
or --exclude-table-date. An exclude pattern failing to match
559+
any objects is not considered an error.
560+
</para>
561+
</listitem>
562+
</varlistentry>
563+
547564
<varlistentry>
548565
<term><option>-T <replaceable class="parameter">table</replaceable></option></term>
549566
<term><option>--exclude-table=<replaceable class="parameter">table</replaceable></option></term>

doc/src/sgml/ref/pg_restore.sgml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,16 @@
431431
</listitem>
432432
</varlistentry>
433433

434+
<varlistentry>
435+
<term><option>--strict-names</></term>
436+
<listitem>
437+
<para>
438+
Require that each schema (-n / --schema) and table (-t / --table)
439+
qualifier match at least one schema/table in the backup file.
440+
</para>
441+
</listitem>
442+
</varlistentry>
443+
434444
<varlistentry>
435445
<term><option>-T <replaceable class="parameter">trigger</replaceable></option></term>
436446
<term><option>--trigger=<replaceable class="parameter">trigger</replaceable></option></term>

src/bin/pg_dump/dumputils.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,7 @@ simple_string_list_append(SimpleStringList *list, const char *val)
12201220
pg_malloc(offsetof(SimpleStringListCell, val) +strlen(val) + 1);
12211221

12221222
cell->next = NULL;
1223+
cell->touched = false;
12231224
strcpy(cell->val, val);
12241225

12251226
if (list->tail)
@@ -1237,7 +1238,23 @@ simple_string_list_member(SimpleStringList *list, const char *val)
12371238
for (cell = list->head; cell; cell = cell->next)
12381239
{
12391240
if (strcmp(cell->val, val) == 0)
1241+
{
1242+
cell->touched = true;
12401243
return true;
1244+
}
12411245
}
12421246
return false;
12431247
}
1248+
1249+
const char *
1250+
simple_string_list_not_touched(SimpleStringList *list)
1251+
{
1252+
SimpleStringListCell *cell;
1253+
1254+
for (cell = list->head; cell; cell = cell->next)
1255+
{
1256+
if (!cell->touched)
1257+
return cell->val;
1258+
}
1259+
return NULL;
1260+
}

src/bin/pg_dump/dumputils.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ typedef struct SimpleOidList
3838
typedef struct SimpleStringListCell
3939
{
4040
struct SimpleStringListCell *next;
41+
bool touched; /* true, when this string was searched
42+
and touched */
4143
char val[FLEXIBLE_ARRAY_MEMBER]; /* null-terminated string here */
4244
} SimpleStringListCell;
4345

@@ -103,5 +105,7 @@ extern void set_dump_section(const char *arg, int *dumpSections);
103105

104106
extern void simple_string_list_append(SimpleStringList *list, const char *val);
105107
extern bool simple_string_list_member(SimpleStringList *list, const char *val);
108+
extern const char *simple_string_list_not_touched(SimpleStringList *list);
109+
106110

107111
#endif /* DUMPUTILS_H */

src/bin/pg_dump/pg_backup.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ typedef struct _restoreOptions
104104
int column_inserts;
105105
int if_exists;
106106
int no_security_labels; /* Skip security label entries */
107+
int strict_names;
107108

108109
const char *filename;
109110
int dataOnly;

src/bin/pg_dump/pg_backup_archiver.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ static void reduce_dependencies(ArchiveHandle *AH, TocEntry *te,
108108
static void mark_create_done(ArchiveHandle *AH, TocEntry *te);
109109
static void inhibit_data_for_failed_table(ArchiveHandle *AH, TocEntry *te);
110110

111+
static void StrictNamesCheck(RestoreOptions *ropt);
112+
113+
111114
/*
112115
* Allocate a new DumpOptions block containing all default values.
113116
*/
@@ -284,6 +287,10 @@ SetArchiveRestoreOptions(Archive *AHX, RestoreOptions *ropt)
284287

285288
te->reqs = _tocEntryRequired(te, curSection, ropt);
286289
}
290+
291+
/* Enforce strict names checking */
292+
if (ropt->strict_names)
293+
StrictNamesCheck(ropt);
287294
}
288295

289296
/* Public */
@@ -1104,6 +1111,10 @@ PrintTOCSummary(Archive *AHX, RestoreOptions *ropt)
11041111
}
11051112
}
11061113

1114+
/* Enforce strict names checking */
1115+
if (ropt->strict_names)
1116+
StrictNamesCheck(ropt);
1117+
11071118
if (ropt->filename)
11081119
RestoreOutput(AH, sav);
11091120
}
@@ -2612,6 +2623,49 @@ processStdStringsEntry(ArchiveHandle *AH, TocEntry *te)
26122623
te->defn);
26132624
}
26142625

2626+
static void
2627+
StrictNamesCheck(RestoreOptions *ropt)
2628+
{
2629+
const char *missing_name;
2630+
2631+
Assert(ropt->strict_names);
2632+
2633+
if (ropt->schemaNames.head != NULL)
2634+
{
2635+
missing_name = simple_string_list_not_touched(&ropt->schemaNames);
2636+
if (missing_name != NULL)
2637+
exit_horribly(modulename, "Schema \"%s\" not found.\n", missing_name);
2638+
}
2639+
2640+
if (ropt->tableNames.head != NULL)
2641+
{
2642+
missing_name = simple_string_list_not_touched(&ropt->tableNames);
2643+
if (missing_name != NULL)
2644+
exit_horribly(modulename, "Table \"%s\" not found.\n", missing_name);
2645+
}
2646+
2647+
if (ropt->indexNames.head != NULL)
2648+
{
2649+
missing_name = simple_string_list_not_touched(&ropt->indexNames);
2650+
if (missing_name != NULL)
2651+
exit_horribly(modulename, "Index \"%s\" not found.\n", missing_name);
2652+
}
2653+
2654+
if (ropt->functionNames.head != NULL)
2655+
{
2656+
missing_name = simple_string_list_not_touched(&ropt->functionNames);
2657+
if (missing_name != NULL)
2658+
exit_horribly(modulename, "Function \"%s\" not found.\n", missing_name);
2659+
}
2660+
2661+
if (ropt->triggerNames.head != NULL)
2662+
{
2663+
missing_name = simple_string_list_not_touched(&ropt->triggerNames);
2664+
if (missing_name != NULL)
2665+
exit_horribly(modulename, "Trigger \"%s\" not found.\n", missing_name);
2666+
}
2667+
}
2668+
26152669
static teReqs
26162670
_tocEntryRequired(TocEntry *te, teSection curSection, RestoreOptions *ropt)
26172671
{

src/bin/pg_dump/pg_dump.c

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ static const char *username_subquery;
9797
/* obsolete as of 7.3: */
9898
static Oid g_last_builtin_oid; /* value of the last builtin oid */
9999

100+
/* The specified names/patterns should to match at least one entity */
101+
static int strict_names = 0;
102+
100103
/*
101104
* Object inclusion/exclusion lists
102105
*
@@ -131,10 +134,12 @@ static void setup_connection(Archive *AH, DumpOptions *dopt,
131134
static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
132135
static void expand_schema_name_patterns(Archive *fout,
133136
SimpleStringList *patterns,
134-
SimpleOidList *oids);
137+
SimpleOidList *oids,
138+
bool strict_names);
135139
static void expand_table_name_patterns(Archive *fout,
136140
SimpleStringList *patterns,
137-
SimpleOidList *oids);
141+
SimpleOidList *oids,
142+
bool strict_names);
138143
static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid, Oid objoid);
139144
static void dumpTableData(Archive *fout, DumpOptions *dopt, TableDataInfo *tdinfo);
140145
static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
@@ -333,6 +338,7 @@ main(int argc, char **argv)
333338
{"section", required_argument, NULL, 5},
334339
{"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
335340
{"snapshot", required_argument, NULL, 6},
341+
{"strict-names", no_argument, &strict_names, 1},
336342
{"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
337343
{"no-security-labels", no_argument, &dopt.no_security_labels, 1},
338344
{"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
@@ -690,27 +696,32 @@ main(int argc, char **argv)
690696
if (schema_include_patterns.head != NULL)
691697
{
692698
expand_schema_name_patterns(fout, &schema_include_patterns,
693-
&schema_include_oids);
699+
&schema_include_oids,
700+
strict_names);
694701
if (schema_include_oids.head == NULL)
695702
exit_horribly(NULL, "No matching schemas were found\n");
696703
}
697704
expand_schema_name_patterns(fout, &schema_exclude_patterns,
698-
&schema_exclude_oids);
705+
&schema_exclude_oids,
706+
false);
699707
/* non-matching exclusion patterns aren't an error */
700708

701709
/* Expand table selection patterns into OID lists */
702710
if (table_include_patterns.head != NULL)
703711
{
704712
expand_table_name_patterns(fout, &table_include_patterns,
705-
&table_include_oids);
713+
&table_include_oids,
714+
strict_names);
706715
if (table_include_oids.head == NULL)
707716
exit_horribly(NULL, "No matching tables were found\n");
708717
}
709718
expand_table_name_patterns(fout, &table_exclude_patterns,
710-
&table_exclude_oids);
719+
&table_exclude_oids,
720+
false);
711721

712722
expand_table_name_patterns(fout, &tabledata_exclude_patterns,
713-
&tabledata_exclude_oids);
723+
&tabledata_exclude_oids,
724+
false);
714725

715726
/* non-matching exclusion patterns aren't an error */
716727

@@ -905,6 +916,8 @@ help(const char *progname)
905916
printf(_(" --section=SECTION dump named section (pre-data, data, or post-data)\n"));
906917
printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
907918
printf(_(" --snapshot=SNAPSHOT use given synchronous snapshot for the dump\n"));
919+
printf(_(" --strict-names require table and/or schema include patterns to\n"
920+
" match at least one entity each\n"));
908921
printf(_(" --use-set-session-authorization\n"
909922
" use SET SESSION AUTHORIZATION commands instead of\n"
910923
" ALTER OWNER commands to set ownership\n"));
@@ -1135,7 +1148,8 @@ parseArchiveFormat(const char *format, ArchiveMode *mode)
11351148
static void
11361149
expand_schema_name_patterns(Archive *fout,
11371150
SimpleStringList *patterns,
1138-
SimpleOidList *oids)
1151+
SimpleOidList *oids,
1152+
bool strict_names)
11391153
{
11401154
PQExpBuffer query;
11411155
PGresult *res;
@@ -1151,38 +1165,41 @@ expand_schema_name_patterns(Archive *fout,
11511165
query = createPQExpBuffer();
11521166

11531167
/*
1154-
* We use UNION ALL rather than UNION; this might sometimes result in
1155-
* duplicate entries in the OID list, but we don't care.
1168+
* This might sometimes result in duplicate entries in the OID list,
1169+
* but we don't care.
11561170
*/
11571171

11581172
for (cell = patterns->head; cell; cell = cell->next)
11591173
{
1160-
if (cell != patterns->head)
1161-
appendPQExpBufferStr(query, "UNION ALL\n");
11621174
appendPQExpBuffer(query,
11631175
"SELECT oid FROM pg_catalog.pg_namespace n\n");
11641176
processSQLNamePattern(GetConnection(fout), query, cell->val, false,
11651177
false, NULL, "n.nspname", NULL, NULL);
1166-
}
11671178

1168-
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1179+
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1180+
if (strict_names && PQntuples(res) == 0)
1181+
exit_horribly(NULL, "No matching table(s) were found for pattern \"%s\"\n", cell->val);
11691182

1170-
for (i = 0; i < PQntuples(res); i++)
1171-
{
1172-
simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1183+
for (i = 0; i < PQntuples(res); i++)
1184+
{
1185+
simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1186+
}
1187+
1188+
PQclear(res);
1189+
resetPQExpBuffer(query);
11731190
}
11741191

1175-
PQclear(res);
11761192
destroyPQExpBuffer(query);
11771193
}
11781194

11791195
/*
11801196
* Find the OIDs of all tables matching the given list of patterns,
1181-
* and append them to the given OID list.
1197+
* and append them to the given OID list.
11821198
*/
11831199
static void
11841200
expand_table_name_patterns(Archive *fout,
1185-
SimpleStringList *patterns, SimpleOidList *oids)
1201+
SimpleStringList *patterns, SimpleOidList *oids,
1202+
bool strict_names)
11861203
{
11871204
PQExpBuffer query;
11881205
PGresult *res;
@@ -1195,14 +1212,12 @@ expand_table_name_patterns(Archive *fout,
11951212
query = createPQExpBuffer();
11961213

11971214
/*
1198-
* We use UNION ALL rather than UNION; this might sometimes result in
1199-
* duplicate entries in the OID list, but we don't care.
1215+
* this might sometimes result in duplicate entries in the OID list,
1216+
* but we don't care.
12001217
*/
12011218

12021219
for (cell = patterns->head; cell; cell = cell->next)
12031220
{
1204-
if (cell != patterns->head)
1205-
appendPQExpBufferStr(query, "UNION ALL\n");
12061221
appendPQExpBuffer(query,
12071222
"SELECT c.oid"
12081223
"\nFROM pg_catalog.pg_class c"
@@ -1213,16 +1228,20 @@ expand_table_name_patterns(Archive *fout,
12131228
processSQLNamePattern(GetConnection(fout), query, cell->val, true,
12141229
false, "n.nspname", "c.relname", NULL,
12151230
"pg_catalog.pg_table_is_visible(c.oid)");
1216-
}
12171231

1218-
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1232+
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1233+
if (strict_names && PQntuples(res) == 0)
1234+
exit_horribly(NULL, "No matching table(s) were found for pattern \"%s\"\n", cell->val);
12191235

1220-
for (i = 0; i < PQntuples(res); i++)
1221-
{
1222-
simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1236+
for (i = 0; i < PQntuples(res); i++)
1237+
{
1238+
simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1239+
}
1240+
1241+
PQclear(res);
1242+
resetPQExpBuffer(query);
12231243
}
12241244

1225-
PQclear(res);
12261245
destroyPQExpBuffer(query);
12271246
}
12281247

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy