From 5d36ef7c3814e60268e3d0dba36856f207bd1704 Mon Sep 17 00:00:00 2001 From: Daniel Gustafsson Date: Wed, 7 Sep 2022 15:22:05 +0200 Subject: [PATCH v4] Add include/exclude filtering via file in pg_dump Author: Pavel Stehule Discussion: https://postgr.es/m/CAFj8pRB10wvW0CC9Xq=1XDs=zCQxer3cbLcNZa+qiX4cUH-G_A@mail.gmail.com --- doc/src/sgml/ref/pg_dump.sgml | 88 +++++++++++++++++++ doc/src/sgml/ref/pg_dumpall.sgml | 22 +++++ doc/src/sgml/ref/pg_restore.sgml | 25 ++++++ src/bin/pg_dump/.gitignore | 4 + src/bin/pg_dump/Makefile | 17 +++- src/bin/pg_dump/filter.h | 44 ++++++++++ src/bin/pg_dump/filterparse.y | 64 ++++++++++++++ src/bin/pg_dump/filterscan.l | 139 ++++++++++++++++++++++++++++++ src/bin/pg_dump/pg_backup_utils.c | 33 +++++++ src/bin/pg_dump/pg_backup_utils.h | 1 + src/bin/pg_dump/pg_dump.c | 56 ++++++++++++ src/bin/pg_dump/pg_dumpall.c | 65 +++++++++++++- src/bin/pg_dump/pg_restore.c | 58 +++++++++++++ src/tools/msvc/Mkvcbuild.pm | 4 +- 14 files changed, 616 insertions(+), 4 deletions(-) create mode 100644 src/bin/pg_dump/filter.h create mode 100644 src/bin/pg_dump/filterparse.y create mode 100644 src/bin/pg_dump/filterscan.l diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml index c08276bc0a..b64bae6987 100644 --- a/doc/src/sgml/ref/pg_dump.sgml +++ b/doc/src/sgml/ref/pg_dump.sgml @@ -779,6 +779,80 @@ PostgreSQL documentation + + + + + Specify a filename from which to read patterns for objects to include + or exclude from the dump. The patterns are interpreted according to the + same rules as the corresponding options: + / for tables, + / for schemas, + for data on foreign servers and + for table data. + To read from STDIN, use - as the + filename. The option can be specified in + conjunction with the above listed options for including or excluding + objects, and can also be specified more than once for multiple filter + files. + + + + The file lists one object pattern per row, with the following format: + +{ include | exclude } { table | schema | foreign_data | data } PATTERN + + + + + The first keyword specifies whether the objects matched by the pattern + are to be included or excluded. The second keyword specifies the type + of object to be filtered using the pattern: + + + + table: tables, works like + / + + + + + schema: schemas, works like + / + + + + + foreign_data: data on foreign servers, works like + . This keyword can only be + used with the include keyword. + + + + + data: table data, works like + . This keyword can only be + used with the exclude keyword. + + + + + + + Lines starting with # are considered comments and + ignored. Comments can be placed after filter as well. Blank lines + are also ignored. See for how to + perform quoting in patterns. + + + + Example files are listed below in the + section. + + + + + @@ -1119,6 +1193,7 @@ PostgreSQL documentation schema (/) and table (/) qualifier match at least one extension/schema/table in the database to be dumped. + This also applies to filters used with . Note that if none of the extension/schema/table qualifiers find matches, pg_dump will generate an error even without . @@ -1528,6 +1603,19 @@ CREATE DATABASE foo WITH TEMPLATE template0; $ pg_dump -t "\"MixedCaseName\"" mydb > mytab.sql + + + + To dump all tables with names starting with mytable, except for table + mytable2, specify a filter file + filter.txt like: + +include table mytable* +exclude table mytable2 + + + +$ pg_dump --filter=filter.txt mydb > db.sql diff --git a/doc/src/sgml/ref/pg_dumpall.sgml b/doc/src/sgml/ref/pg_dumpall.sgml index 5d54074e01..46a667c17a 100644 --- a/doc/src/sgml/ref/pg_dumpall.sgml +++ b/doc/src/sgml/ref/pg_dumpall.sgml @@ -122,6 +122,28 @@ PostgreSQL documentation + + + + + Specify a filename from which to read patterns for databases excluded + from dump. The patterns are interpreted according to the same rules + as . + To read from STDIN, use - as the + filename. The option can be specified in + conjunction with the above listed options for excluding databases, + and can also be specified more than once for multiple filter files. + + + + The file lists one database pattern per row, with the following format: + +exclude database PATTERN + + + + + diff --git a/doc/src/sgml/ref/pg_restore.sgml b/doc/src/sgml/ref/pg_restore.sgml index 47bd7dbda0..ffeb564c52 100644 --- a/doc/src/sgml/ref/pg_restore.sgml +++ b/doc/src/sgml/ref/pg_restore.sgml @@ -188,6 +188,31 @@ PostgreSQL documentation + + + + + Specify a filename from which to read patterns for objects excluded + or included from restore. The patterns are interpretted according to the + same rules as , , + , , + or . + To read from STDIN, use - as the + filename. The option can be specified in + conjunction with the above listed options for including or excluding + objects, and can also be specified more than once for multiple filter + files. + + + + The file lists one database pattern per row, with the following format: + +{ include | exclude } { function | index | schema | table | trigger } PATTERN + + + + + diff --git a/src/bin/pg_dump/.gitignore b/src/bin/pg_dump/.gitignore index e6d7812779..11f2d68bea 100644 --- a/src/bin/pg_dump/.gitignore +++ b/src/bin/pg_dump/.gitignore @@ -2,4 +2,8 @@ /pg_dumpall /pg_restore +# Local generated source files +/filterparse.c +/filterscan.c + /tmp_check/ diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile index 9dc5a784dd..e3befdc9b1 100644 --- a/src/bin/pg_dump/Makefile +++ b/src/bin/pg_dump/Makefile @@ -26,6 +26,8 @@ OBJS = \ $(WIN32RES) \ compress_io.o \ dumputils.o \ + filterparse.o \ + filterscan.o \ parallel.o \ pg_backup_archiver.o \ pg_backup_custom.o \ @@ -37,14 +39,23 @@ OBJS = \ all: pg_dump pg_restore pg_dumpall +# See notes in src/backend/parser/Makefile about the following two rules +filterparse.h: filterparse.c + touch $@ + +filterparse.c: BISONFLAGS += -d + +# Force these dependencies to be known even without dependency info built: +filterparse.o filterscan.o: filterparse.h + pg_dump: pg_dump.o common.o pg_dump_sort.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils $(CC) $(CFLAGS) pg_dump.o common.o pg_dump_sort.o $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) pg_restore: pg_restore.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils $(CC) $(CFLAGS) pg_restore.o $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) -pg_dumpall: pg_dumpall.o dumputils.o $(WIN32RES) | submake-libpq submake-libpgport submake-libpgfeutils - $(CC) $(CFLAGS) pg_dumpall.o dumputils.o $(WIN32RES) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) +pg_dumpall: pg_dumpall.o dumputils.o filterparse.o filterscan.o $(WIN32RES) | submake-libpq submake-libpgport submake-libpgfeutils + $(CC) $(CFLAGS) pg_dumpall.o dumputils.o filterparse.o filterscan.o $(WIN32RES) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) install: all installdirs $(INSTALL_PROGRAM) pg_dump$(X) '$(DESTDIR)$(bindir)'/pg_dump$(X) @@ -63,6 +74,8 @@ installcheck: uninstall: rm -f $(addprefix '$(DESTDIR)$(bindir)'/, pg_dump$(X) pg_restore$(X) pg_dumpall$(X)) +distprep: filterparse.c filterscan.c + clean distclean maintainer-clean: rm -f pg_dump$(X) pg_restore$(X) pg_dumpall$(X) $(OBJS) pg_dump.o common.o pg_dump_sort.o pg_restore.o pg_dumpall.o rm -rf tmp_check diff --git a/src/bin/pg_dump/filter.h b/src/bin/pg_dump/filter.h new file mode 100644 index 0000000000..5dff4161f0 --- /dev/null +++ b/src/bin/pg_dump/filter.h @@ -0,0 +1,44 @@ +/*------------------------------------------------------------------------- + * + * filter.h + * Common header file for the parser of filter file + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/bin/pg_dump/filter.h + * + *------------------------------------------------------------------------- + */ +#ifndef FILTER_H +#define FILTER_H +#include "c.h" + +/* + * List of objects that can be specified in filter file + */ +typedef enum +{ + FILTER_OBJECT_TYPE_NONE, + FILTER_OBJECT_TYPE_DATA, + FILTER_OBJECT_TYPE_DATABASE, + FILTER_OBJECT_TYPE_FOREIGN_DATA, + FILTER_OBJECT_TYPE_FUNCTION, + FILTER_OBJECT_TYPE_INDEX, + FILTER_OBJECT_TYPE_SCHEMA, + FILTER_OBJECT_TYPE_TABLE, + FILTER_OBJECT_TYPE_TRIGGER, +} FilterObjectType; + +extern FILE *filter_yyin; + +extern int filter_yylex(void); +extern void filter_yyerror(void *priv, const char *msg); +extern void filter_scanner_init(void); +extern void filter_scanner_finish(void); +extern int filter_yyparse(void *priv); + +extern void include_item(void *priv, FilterObjectType objtype, const char *objname); +extern void exclude_item(void *priv, FilterObjectType objtype, const char *objname); + +#endif diff --git a/src/bin/pg_dump/filterparse.y b/src/bin/pg_dump/filterparse.y new file mode 100644 index 0000000000..c7f06f788d --- /dev/null +++ b/src/bin/pg_dump/filterparse.y @@ -0,0 +1,64 @@ +%{ +/*------------------------------------------------------------------------- + * + * filterparse.y + * bison grammar for the pg_dump object filter files + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/bin/pg_dump/filterparse.y + *------------------------------------------------------------------------- + */ + +#include "postgres_fe.h" + +#include "filter.h" + +%} + +%name-prefix="filter_yy" +%parse-param {void *priv} + +%union +{ + char *str; + int integer; +} + +%type include_object exclude_object +%token pattern +%token C_INCLUDE C_EXCLUDE +%token OBJ_DATA OBJ_DATABASE OBJ_FOREIGN_DATA OBJ_FUNCTION OBJ_INDEX +%token OBJ_SCHEMA OBJ_TABLE OBJ_TRIGGER +%start Filters + +%% + +Filters: + /* EMPTY */ + | Filters Filter + ; + +Filter: + C_INCLUDE include_object pattern { include_item(priv, $2, $3); } + | C_EXCLUDE exclude_object pattern { exclude_item(priv, $2, $3); } + ; + +include_object: + OBJ_FOREIGN_DATA { $$ = FILTER_OBJECT_TYPE_FOREIGN_DATA; } + | OBJ_FUNCTION { $$ = FILTER_OBJECT_TYPE_FUNCTION; } + | OBJ_INDEX { $$ = FILTER_OBJECT_TYPE_INDEX; } + | OBJ_SCHEMA { $$ = FILTER_OBJECT_TYPE_SCHEMA; } + | OBJ_TABLE { $$ = FILTER_OBJECT_TYPE_TABLE; } + | OBJ_TRIGGER { $$ = FILTER_OBJECT_TYPE_TRIGGER; } + ; + +exclude_object: + OBJ_DATA { $$ = FILTER_OBJECT_TYPE_DATA; } + | OBJ_DATABASE { $$ = FILTER_OBJECT_TYPE_DATABASE; } + | OBJ_SCHEMA { $$ = FILTER_OBJECT_TYPE_SCHEMA; } + | OBJ_TABLE { $$ = FILTER_OBJECT_TYPE_TABLE; } + ; + +%% diff --git a/src/bin/pg_dump/filterscan.l b/src/bin/pg_dump/filterscan.l new file mode 100644 index 0000000000..0d7341086b --- /dev/null +++ b/src/bin/pg_dump/filterscan.l @@ -0,0 +1,139 @@ +%top{ +/*------------------------------------------------------------------------- + * + * filterscan.l + * a lexical scanner for pg_dump object filter files + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/bin/pg_dump/filterscan.l + *------------------------------------------------------------------------- + */ +#include "postgres_fe.h" +#include "filterparse.h" +#include "filter.h" +} + +%{ + +static int yyline = 1; + +static void add_pattern_char(char c); + +#define PATTERNBUF_INIT 128 + +static char *patternbuf = NULL; +static size_t patternbufsize = PATTERNBUF_INIT; +static size_t patternbufpos = 0; + +%} + +%option never-interactive +%option noinput +%option nounput +%option noyywrap +%option warn +%option prefix="filter_yy" + +%x command +%x type +%x qident + +space [ \t\r\f\v] +newline [\n] +non_newline [^\n\r] + +comment ("#"{non_newline}*) +pattern ([^"\n# \t\r\f\v]+) + +%% + + /* Commands */ +include { BEGIN(command); return C_INCLUDE; } +exclude { BEGIN(command); return C_EXCLUDE; } + +[\n] yyline++; +{comment} { /* ignore */ } +{space} { /* ignore */ } + + /* Object types */ +({space}*)data { BEGIN(type); return OBJ_DATA; } +({space}*)database { BEGIN(type); return OBJ_DATABASE; } +({space}*)foreign_data { BEGIN(type); return OBJ_FOREIGN_DATA; } +({space}*)function { BEGIN(type); return OBJ_FUNCTION; } +({space}*)index { BEGIN(type); return OBJ_INDEX; } +({space}*)schema { BEGIN(type); return OBJ_SCHEMA; } +({space}*)table { BEGIN(type); return OBJ_TABLE; } +({space}*)trigger { BEGIN(type); return OBJ_TRIGGER; } +{pattern} { filter_yyerror(NULL, "unsupported filter object type"); } +<> { filter_yyerror(NULL, "missing type name"); } + + /* Patterns */ +<> { filter_yyerror(NULL, "missing object name"); } +{space} { /* ignore */ } +{pattern} { + filter_yylval.str = pg_strdup(yytext); + BEGIN(INITIAL); + return(pattern); + } +\" { + patternbufpos = 0; + memset(patternbuf, 0, patternbufsize); + BEGIN(qident); + } +\\\" { add_pattern_char(yytext[1]); } +\" { + filter_yylval.str = pg_strdup(patternbuf); + BEGIN(INITIAL); + return(pattern); + } +{newline} { add_pattern_char('\n'); } +. { add_pattern_char(yytext[0]); } +<> { + fprintf(stderr, "syntax error at line %i; unterminated quoted pattern: %s\n", + yyline, patternbuf); + exit(1); + } + /* Anything else is a syntax error */ +. { filter_yyerror(NULL, "unexpected character"); } +%% + +static void +add_pattern_char(char c) +{ + /* Leave room for trailing zero */ + if (patternbufpos >= patternbufsize - 1) + { + /* Ensure that we don't overflow */ + if (patternbufsize > (SIZE_MAX / 2)) + { + fprintf(stderr, "out of memory\n"); + exit(1); + } + + /* Double the size of patternbuf if it gets full */ + patternbufsize += patternbufsize; + patternbuf = pg_realloc(patternbuf, patternbufsize); + } + patternbuf[patternbufpos++] = c; +} + +void +filter_scanner_init(void) +{ + patternbuf = pg_malloc(patternbufsize); +} + +void +filter_scanner_finish(void) +{ + pfree(patternbuf); +} + +void +filter_yyerror(void *priv, const char *msg) +{ + fprintf(stderr, "syntax error at line %i: %s: \"%s\"\n", yyline, msg, yytext); + exit(1); +} diff --git a/src/bin/pg_dump/pg_backup_utils.c b/src/bin/pg_dump/pg_backup_utils.c index e40890cb26..d6db156bae 100644 --- a/src/bin/pg_dump/pg_backup_utils.c +++ b/src/bin/pg_dump/pg_backup_utils.c @@ -13,6 +13,7 @@ */ #include "postgres_fe.h" +#include "filter.h" #include "parallel.h" #include "pg_backup_utils.h" @@ -102,3 +103,35 @@ exit_nicely(int code) exit(code); } + +/* + * Retrieve object identifier patterns from file + * + * Parse the specified filter file for include and exclude patterns, and add + * them to the relevant lists. If the filename is "-" then filters will be + * read from STDIN rather than a file. + */ +void +parse_filters_from_file(const char *filename, void *priv) +{ + bool need_close = true; + + if (strlen(filename) == 1 && filename[0] == '-') + { + filter_yyin = stdin; + need_close = false; + } + else + { + filter_yyin = fopen(filename, "r"); + if (!filter_yyin) + pg_fatal("unable to open filterfile \"%s\": %m", filename); + } + + filter_scanner_init(); + filter_yyparse(priv); + filter_scanner_finish(); + + if (need_close) + fclose(filter_yyin); +} diff --git a/src/bin/pg_dump/pg_backup_utils.h b/src/bin/pg_dump/pg_backup_utils.h index 8173bb93cf..74b942e712 100644 --- a/src/bin/pg_dump/pg_backup_utils.h +++ b/src/bin/pg_dump/pg_backup_utils.h @@ -30,6 +30,7 @@ extern const char *progname; extern void set_dump_section(const char *arg, int *dumpSections); extern void on_exit_nicely(on_exit_nicely_callback function, void *arg); extern void exit_nicely(int code) pg_attribute_noreturn(); +extern void parse_filters_from_file(const char *filename, void *priv); /* In pg_dump, we modify pg_fatal to call exit_nicely instead of exit */ #undef pg_fatal diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 67b6d9079e..d88adfe59a 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -58,6 +58,7 @@ #include "dumputils.h" #include "fe_utils/option_utils.h" #include "fe_utils/string_utils.h" +#include "filter.h" #include "getopt_long.h" #include "libpq/libpq-fs.h" #include "parallel.h" @@ -389,6 +390,7 @@ main(int argc, char **argv) {"enable-row-security", no_argument, &dopt.enable_row_security, 1}, {"exclude-table-data", required_argument, NULL, 4}, {"extra-float-digits", required_argument, NULL, 8}, + {"filter", required_argument, NULL, 12}, {"if-exists", no_argument, &dopt.if_exists, 1}, {"inserts", no_argument, NULL, 9}, {"lock-wait-timeout", required_argument, NULL, 2}, @@ -622,6 +624,10 @@ main(int argc, char **argv) optarg); break; + case 12: /* object filters from file */ + parse_filters_from_file(optarg, (void *) &dopt); + break; + default: /* getopt_long already emitted a complaint */ pg_log_error_hint("Try \"%s --help\" for more information.", progname); @@ -1027,6 +1033,8 @@ help(const char *progname) " access to)\n")); printf(_(" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n")); printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n")); + printf(_(" --filter=FILENAME dump objects and data based on the filter expressions\n" + " in specified file\n")); printf(_(" --if-exists use IF EXISTS when dropping objects\n")); printf(_(" --include-foreign-data=PATTERN\n" " include data of foreign tables on foreign\n" @@ -18197,3 +18205,51 @@ appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions, if (!res) pg_log_warning("could not parse %s array", "reloptions"); } + +void +exclude_item(void *priv, FilterObjectType objtype, const char *objname) +{ + (void) priv; + + switch (objtype) + { + case FILTER_OBJECT_TYPE_DATA: + simple_string_list_append(&tabledata_exclude_patterns, objname); + break; + case FILTER_OBJECT_TYPE_SCHEMA: + simple_string_list_append(&schema_exclude_patterns, objname); + break; + case FILTER_OBJECT_TYPE_TABLE: + simple_string_list_append(&table_exclude_patterns, objname); + break; + default: + pg_log_error("Unsupported exclude object"); + exit_nicely(1); + break; + } +} + +void +include_item(void *priv, FilterObjectType objtype, const char *objname) +{ + DumpOptions *dopt = (DumpOptions *) priv; + + switch (objtype) + { + case FILTER_OBJECT_TYPE_FOREIGN_DATA: + simple_string_list_append(&foreign_servers_include_patterns, objname); + break; + case FILTER_OBJECT_TYPE_SCHEMA: + simple_string_list_append(&schema_include_patterns, objname); + dopt->include_everything = false; + break; + case FILTER_OBJECT_TYPE_TABLE: + simple_string_list_append(&table_include_patterns, objname); + dopt->include_everything = false; + break; + default: + pg_log_error("Unsupported include object"); + exit_nicely(1); + break; + } +} diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 69ae027bd3..4e9d898387 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -26,6 +26,7 @@ #include "common/string.h" #include "dumputils.h" #include "fe_utils/string_utils.h" +#include "filter.h" #include "getopt_long.h" #include "pg_backup.h" @@ -79,6 +80,7 @@ static PGresult *executeQuery(PGconn *conn, const char *query); static void executeCommand(PGconn *conn, const char *query); static void expand_dbname_patterns(PGconn *conn, SimpleStringList *patterns, SimpleStringList *names); +static void getDatabaseExcludeFiltersFromFile(const char *filename, SimpleStringList *patterns); static char pg_dump_bin[MAXPGPATH]; static const char *progname; @@ -156,6 +158,7 @@ main(int argc, char *argv[]) {"disable-triggers", no_argument, &disable_triggers, 1}, {"exclude-database", required_argument, NULL, 6}, {"extra-float-digits", required_argument, NULL, 5}, + {"filter", required_argument, NULL, 8}, {"if-exists", no_argument, &if_exists, 1}, {"inserts", no_argument, &inserts, 1}, {"lock-wait-timeout", required_argument, NULL, 2}, @@ -358,6 +361,11 @@ main(int argc, char *argv[]) appendShellString(pgdumpopts, optarg); break; + case 8: + getDatabaseExcludeFiltersFromFile(optarg, + &database_exclude_patterns); + break; + default: /* getopt_long already emitted a complaint */ pg_log_error_hint("Try \"%s --help\" for more information.", progname); @@ -651,6 +659,7 @@ help(void) printf(_(" --disable-triggers disable triggers during data-only restore\n")); printf(_(" --exclude-database=PATTERN exclude databases whose name matches PATTERN\n")); printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n")); + printf(_(" --filter=FILENAME exclude databases specified in filter file\n")); printf(_(" --if-exists use IF EXISTS when dropping objects\n")); printf(_(" --inserts dump data as INSERT commands, rather than COPY\n")); printf(_(" --load-via-partition-root load partitions via the root table\n")); @@ -1888,7 +1897,6 @@ executeCommand(PGconn *conn, const char *query) PQclear(res); } - /* * dumpTimestamp */ @@ -1912,3 +1920,58 @@ hash_string_pointer(char *s) return hash_bytes(ss, strlen(s)); } + +/* + * getDatabaseFiltersFromFile - retrieve database identifier patterns from file + * + * Parse the specified filter file for include and exclude patterns, and add + * them to the relevant lists. If the filename is "-" then filters will be + * read from STDIN rather than a file. + */ +static void +getDatabaseExcludeFiltersFromFile(const char *filename, SimpleStringList *pattern) +{ + bool need_close = true; + + if (strlen(filename) == 1 && filename[0] == '-') + { + filter_yyin = stdin; + need_close = false; + } + else + { + filter_yyin = fopen(filename, "r"); + if (!filter_yyin) + pg_fatal("unable to open filterfile \"%s\": %m", filename); + } + + filter_scanner_init(); + filter_yyparse((void *) pattern); + filter_scanner_finish(); + + if (need_close) + fclose(filter_yyin); +} + +void +exclude_item(void *priv, FilterObjectType objtype, const char *objname) +{ + SimpleStringList *pattern = (SimpleStringList *) priv; + + if (objtype != FILTER_OBJECT_TYPE_DATABASE) + { + pg_log_error("Unsupported exclude object"); + exit_nicely(1); + } + + simple_string_list_append(pattern, objname); +} + +void +include_item(void *priv, FilterObjectType objtype, const char *objname) +{ + (void) priv; + + pg_log_error("Unsupported include object"); + exit_nicely(1); +} diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c index 049a100634..70897d9056 100644 --- a/src/bin/pg_dump/pg_restore.c +++ b/src/bin/pg_dump/pg_restore.c @@ -47,6 +47,7 @@ #include "dumputils.h" #include "fe_utils/option_utils.h" +#include "filter.h" #include "getopt_long.h" #include "parallel.h" #include "pg_backup_utils.h" @@ -123,6 +124,7 @@ main(int argc, char **argv) {"no-publications", no_argument, &no_publications, 1}, {"no-security-labels", no_argument, &no_security_labels, 1}, {"no-subscriptions", no_argument, &no_subscriptions, 1}, + {"filter", required_argument, NULL, 4}, {NULL, 0, NULL, 0} }; @@ -286,6 +288,10 @@ main(int argc, char **argv) set_dump_section(optarg, &(opts->dumpSections)); break; + case 4: + parse_filters_from_file(optarg, (void *) opts); + break; + default: /* getopt_long already emitted a complaint */ pg_log_error_hint("Try \"%s --help\" for more information.", progname); @@ -463,6 +469,7 @@ usage(const char *progname) printf(_(" -1, --single-transaction restore as a single transaction\n")); printf(_(" --disable-triggers disable triggers during data-only restore\n")); printf(_(" --enable-row-security enable row security\n")); + printf(_(" --filter=FILE restore objects based on filter expressions\n")); printf(_(" --if-exists use IF EXISTS when dropping objects\n")); printf(_(" --no-comments do not restore comments\n")); printf(_(" --no-data-for-failed-tables do not restore data of tables that could not be\n" @@ -494,3 +501,54 @@ usage(const char *progname) printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT); printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL); } + +void +exclude_item(void *priv, FilterObjectType objtype, const char *objname) +{ + RestoreOptions *opts = (RestoreOptions *) priv; + + if (objtype != FILTER_OBJECT_TYPE_SCHEMA) + { + pg_log_error("Unsupported exclude object"); + exit_nicely(1); + } + + simple_string_list_append(&opts->schemaExcludeNames, objname); +} + +void +include_item(void *priv, FilterObjectType objtype, const char *objname) +{ + RestoreOptions *opts = (RestoreOptions *) priv; + + switch (objtype) + { + case FILTER_OBJECT_TYPE_FUNCTION: + opts->selTypes = 1; + opts->selFunction = 1; + simple_string_list_append(&opts->functionNames, objname); + break; + case FILTER_OBJECT_TYPE_INDEX: + opts->selTypes = 1; + opts->selIndex = 1; + simple_string_list_append(&opts->indexNames, objname); + break; + case FILTER_OBJECT_TYPE_SCHEMA: + simple_string_list_append(&opts->schemaNames, objname); + break; + case FILTER_OBJECT_TYPE_TABLE: + opts->selTypes = 1; + opts->selTable = 1; + simple_string_list_append(&opts->tableNames, objname); + break; + case FILTER_OBJECT_TYPE_TRIGGER: + opts->selTypes = 1; + opts->selTrigger = 1; + simple_string_list_append(&opts->triggerNames, optarg); + break; + default: + pg_log_error("Unsupported include object"); + exit_nicely(1); + break; + } +} diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 098bc3f1b0..6418db9261 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -78,7 +78,9 @@ my $frontend_extraincludes = { my $frontend_extrasource = { 'psql' => ['src/bin/psql/psqlscanslash.l'], 'pgbench' => - [ 'src/bin/pgbench/exprscan.l', 'src/bin/pgbench/exprparse.y' ] + [ 'src/bin/pgbench/exprscan.l', 'src/bin/pgbench/exprparse.y' ], + 'pg_dump' => + ['src/bin/pg_dump/filterscan.l', 'src/bin/pg_dump/filterparse.y'] }; my @frontend_excludes = ( 'pgevent', 'pg_basebackup', 'pg_rewind', 'pg_dump', -- 2.32.1 (Apple Git-133)