Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+17
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

+10
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

+17
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

+4
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

+1
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

+54
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

+49-30
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)