From 9093babdd79c5d86e6eb8087de4a8dfe8cf4f56b Mon Sep 17 00:00:00 2001 From: alessandro Date: Sun, 23 Aug 2020 23:07:40 -0300 Subject: [PATCH 1/2] added filters include-table exclude-table exclude-column exclude-table-column --- README.md | 8 ++++ src/common.h | 8 ++++ src/quarrel.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++- src/table.c | 37 +++++++++++------- 4 files changed, 142 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 716b386..8d9d0ba 100644 --- a/README.md +++ b/README.md @@ -363,6 +363,10 @@ The following command-line options are provided (all are optional): * `view`: view comparison (default: true). * `include-schema`: include schemas that match pattern (default: all schemas). * `exclude-schema`: exclude schemas that match pattern (default: none). +* `include-table`: include tables that match pattern (default: all schemas). +* `exclude-table`: exclude tables that match pattern (default: none). +* `exclude-column`: exclude columns that match pattern (default: none). +* `exclude-table-column`: exclude table.columns that match pattern (default: none) Only for PostgreSQL 9.4+. You can use a configuration file to store the desired options. The _general_ section specifies which kind of objects will be output. The _target_ and _source_ section options specifies connection options to both servers. Have in mind that any command-line option can override the configuration file option. The configuration file contains the following structure: @@ -411,6 +415,10 @@ view = true include-schema = ^(hr|finance|account|crm|sales)$ exclude-schema = ^public$ +include-table = ^(table_a|table_b)$ +exclude-table = ^(table_c|table_d)$ +exclude-column = ^(column_c|column_d)$ +exclude-table-column = ^(table_g.column_g|table_h.column_h)$ [target] host = 10.27.0.8 diff --git a/src/common.h b/src/common.h index 693e98a..f1a13d2 100644 --- a/src/common.h +++ b/src/common.h @@ -98,6 +98,10 @@ typedef struct QuarrelGeneralOptions /* filter options */ char *include_schema; char *exclude_schema; + char *include_table; + char *exclude_table; + char *exclude_column; + char *exclude_table_column; } QuarrelGeneralOptions; typedef struct QuarrelDatabaseOptions @@ -183,6 +187,10 @@ extern QuarrelGeneralOptions options; extern char *include_schema_str; extern char *exclude_schema_str; +extern char *include_table_str; +extern char *exclude_table_str; +extern char *exclude_column_str; +extern char *exclude_table_column_str; typedef struct stringListCell { diff --git a/src/quarrel.c b/src/quarrel.c index 738a76e..081624f 100644 --- a/src/quarrel.c +++ b/src/quarrel.c @@ -111,6 +111,10 @@ QuarrelGeneralOptions options; /* general options */ /* filter by schema */ char *include_schema_str; char *exclude_schema_str; +char *include_table_str; +char *exclude_table_str; +char *exclude_column_str; +char *exclude_table_column_str; PQLStatistic qstat = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -300,8 +304,12 @@ help(void) printf(" --view=BOOL view (default: %s)\n", (opts.general.view) ? "true" : "false"); printf("\nFilter options:\n"); - printf(" --include-schema=PATTERN include schemas that match PATTERN (default: all schemas)\n"); - printf(" --exclude-schema=PATTERN exclude schemas that match PATTERN (default: none)\n"); + printf(" --include-schema=PATTERN include schemas that match PATTERN (default: all schemas)\n"); + printf(" --exclude-schema=PATTERN exclude schemas that match PATTERN (default: none)\n"); + printf(" --include-table=PATTERN include tables that match PATTERN (default: none)\n"); + printf(" --exclude-table=PATTERN exclude tables that match PATTERN (default: none)\n"); + printf(" --exclude-column=PATTERN exclude columns that match PATTERN (default: none)\n"); + printf(" --exclude-table-column=PATTERN exclude table.columns that match PATTERN (default: none) Only for PostgreSQL 9.4+\n"); printf("\nSource options:\n"); printf(" --source-dbname=DBNAME database name or connection string\n"); printf(" --source-host=HOSTNAME server host or socket directory\n"); @@ -373,6 +381,10 @@ loadConfig(const char *cf, QuarrelOptions *options) options->general.include_schema = NULL; /* general - include schemas that match pattern */ options->general.exclude_schema = NULL; /* general - exclude schemas that match pattern */ + options->general.include_table = NULL; /* general - include tables that match pattern */ + options->general.exclude_table = NULL; /* general - exclude tables that match pattern */ + options->general.exclude_column = NULL; /* general - exclude columns that match pattern */ + options->general.exclude_table_column = NULL; /* general - exclude table.columns that match pattern */ options->source.host = NULL; /* source - host */ options->source.port = NULL; /* source - port */ @@ -623,6 +635,22 @@ loadConfig(const char *cf, QuarrelOptions *options) if (tmp != NULL) options->general.exclude_schema = strdup(tmp); + tmp = mini_file_get_value(config, "general", "include-table"); + if (tmp != NULL) + options->general.include_table = strdup(tmp); + + tmp = mini_file_get_value(config, "general", "exclude-table"); + if (tmp != NULL) + options->general.exclude_table = strdup(tmp); + + tmp = mini_file_get_value(config, "general", "exclude-column"); + if (tmp != NULL) + options->general.exclude_column = strdup(tmp); + + tmp = mini_file_get_value(config, "general", "exclude-table-column"); + if (tmp != NULL) + options->general.exclude_table_column = strdup(tmp); + /* source options */ tmp = mini_file_get_value(config, "source", "host"); if (tmp != NULL) @@ -4671,6 +4699,10 @@ int main(int argc, char *argv[]) {"temp-directory", required_argument, NULL, 37}, {"include-schema", required_argument, NULL, 45}, {"exclude-schema", required_argument, NULL, 46}, + {"include-table", required_argument, NULL, 47}, + {"exclude-table", required_argument, NULL, 48}, + {"exclude-column", required_argument, NULL, 49}, + {"exclude-table-column", required_argument, NULL, 50}, {NULL, 0, NULL, 0} }; @@ -4685,6 +4717,10 @@ int main(int argc, char *argv[]) bool target_prompt_given = false; bool include_schema_given = false; bool exclude_schema_given = false; + bool include_table_given = false; + bool exclude_table_given = false; + bool exclude_column_given = false; + bool exclude_table_column_given = false; /* general and connection options */ QuarrelOptions opts; @@ -4922,6 +4958,22 @@ int main(int argc, char *argv[]) gopts.exclude_schema = strdup(optarg); exclude_schema_given = true; break; + case 47: + gopts.include_table = strdup(optarg); + include_table_given = true; + break; + case 48: + gopts.exclude_table = strdup(optarg); + exclude_table_given = true; + break; + case 49: + gopts.exclude_column = strdup(optarg); + exclude_column_given = true; + break; + case 50: + gopts.exclude_table_column = strdup(optarg); + exclude_table_column_given = true; + break; default: fprintf(stderr, "Try \"%s --help\" for more information.\n", PGQ_NAME); exit(EXIT_FAILURE); @@ -5022,6 +5074,14 @@ int main(int argc, char *argv[]) options.include_schema = gopts.include_schema; if (exclude_schema_given) options.exclude_schema = gopts.exclude_schema; + if (include_table_given) + options.include_table = gopts.include_table; + if (exclude_table_given) + options.exclude_table = gopts.exclude_table; + if (exclude_column_given) + options.exclude_column = gopts.exclude_column; + if (exclude_table_column_given) + options.exclude_table_column = gopts.exclude_table_column; if (sopts.dbname) opts.source.dbname = sopts.dbname; @@ -5155,6 +5215,46 @@ int main(int argc, char *argv[]) { exclude_schema_str = ""; } + if (options.include_table != NULL) + { + include_table_str = psprintf(" AND c.relname ~ '%s'", options.include_table); + + logNoise("filter include table: %s", include_table_str); + } + else + { + include_table_str = ""; + } + if (options.exclude_table != NULL) + { + exclude_table_str = psprintf(" AND c.relname !~ '%s'", options.exclude_table); + + logNoise("filter exclude table: %s", exclude_table_str); + } + else + { + exclude_table_str = ""; + } + if (options.exclude_column != NULL) + { + exclude_column_str = psprintf(" AND a.attname !~ '%s'", options.exclude_column); + + logNoise("filter exclude column: %s", exclude_column_str); + } + else + { + exclude_column_str = ""; + } + if (options.exclude_table_column != NULL) + { + exclude_table_column_str = psprintf("%s", options.exclude_table_column); + + logNoise("filter exclude table-column: %s", exclude_table_column_str); + } + else + { + exclude_table_column_str = ""; + } /* * We cannot start sending everything to stdout here because we will have diff --git a/src/table.c b/src/table.c index f98395d..0646b18 100644 --- a/src/table.c +++ b/src/table.c @@ -112,11 +112,11 @@ getTables(PGconn *c, int *n, char k) { if (PGQ_IS_REGULAR_OR_PARTITIONED_TABLE(k)) { - query = psprintf("SELECT c.oid, n.nspname, c.relname, c.relkind, t.spcname AS tablespacename, c.relpersistence, array_to_string(c.reloptions, ', ') AS reloptions, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl, relreplident, reloftype, o.nspname AS typnspname, y.typname, c.relispartition, pg_get_partkeydef(c.oid) AS partitionkeydef, pg_get_expr(c.relpartbound, c.oid) AS partitionbound, c.relhassubclass FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) LEFT JOIN pg_tablespace t ON (c.reltablespace = t.oid) LEFT JOIN (pg_type y INNER JOIN pg_namespace o ON (y.typnamespace = o.oid)) ON (c.reloftype = y.oid) WHERE relkind IN ('r', 'p') AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema' %s%s AND NOT EXISTS(SELECT 1 FROM pg_depend d WHERE t.oid = d.objid AND d.deptype = 'e') ORDER BY n.nspname, relname", include_schema_str, exclude_schema_str); + query = psprintf("SELECT c.oid, n.nspname, c.relname, c.relkind, t.spcname AS tablespacename, c.relpersistence, array_to_string(c.reloptions, ', ') AS reloptions, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl, relreplident, reloftype, o.nspname AS typnspname, y.typname, c.relispartition, pg_get_partkeydef(c.oid) AS partitionkeydef, pg_get_expr(c.relpartbound, c.oid) AS partitionbound, c.relhassubclass FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) LEFT JOIN pg_tablespace t ON (c.reltablespace = t.oid) LEFT JOIN (pg_type y INNER JOIN pg_namespace o ON (y.typnamespace = o.oid)) ON (c.reloftype = y.oid) WHERE relkind IN ('r', 'p') AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema' %s%s %s%s AND NOT EXISTS(SELECT 1 FROM pg_depend d WHERE t.oid = d.objid AND d.deptype = 'e') ORDER BY n.nspname, relname", include_schema_str, exclude_schema_str, include_table_str, exclude_table_str); } else if (PGQ_IS_FOREIGN_TABLE(k)) { - query = psprintf("SELECT c.oid, n.nspname, c.relname, c.relkind, t.spcname AS tablespacename, c.relpersistence, array_to_string(c.reloptions, ', ') AS reloptions, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl, relreplident, reloftype, o.nspname AS typnspname, y.typname, c.relispartition, pg_get_partkeydef(c.oid) AS partitionkeydef, pg_get_expr(c.relpartbound, c.oid) AS partitionbound, c.relhassubclass FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) LEFT JOIN pg_tablespace t ON (c.reltablespace = t.oid) LEFT JOIN (pg_type y INNER JOIN pg_namespace o ON (y.typnamespace = o.oid)) ON (c.reloftype = y.oid) WHERE relkind = 'f' AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema' %s%s AND NOT EXISTS(SELECT 1 FROM pg_depend d WHERE t.oid = d.objid AND d.deptype = 'e') ORDER BY n.nspname, relname", include_schema_str, exclude_schema_str); + query = psprintf("SELECT c.oid, n.nspname, c.relname, c.relkind, t.spcname AS tablespacename, c.relpersistence, array_to_string(c.reloptions, ', ') AS reloptions, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl, relreplident, reloftype, o.nspname AS typnspname, y.typname, c.relispartition, pg_get_partkeydef(c.oid) AS partitionkeydef, pg_get_expr(c.relpartbound, c.oid) AS partitionbound, c.relhassubclass FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) LEFT JOIN pg_tablespace t ON (c.reltablespace = t.oid) LEFT JOIN (pg_type y INNER JOIN pg_namespace o ON (y.typnamespace = o.oid)) ON (c.reloftype = y.oid) WHERE relkind = 'f' AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema' %s%s %s%s AND NOT EXISTS(SELECT 1 FROM pg_depend d WHERE t.oid = d.objid AND d.deptype = 'e') ORDER BY n.nspname, relname", include_schema_str, exclude_schema_str, include_table_str, exclude_table_str); } else { @@ -128,11 +128,11 @@ getTables(PGconn *c, int *n, char k) { if (PGQ_IS_REGULAR_TABLE(k)) { - query = psprintf("SELECT c.oid, n.nspname, c.relname, c.relkind, t.spcname AS tablespacename, c.relpersistence, array_to_string(c.reloptions, ', ') AS reloptions, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl, relreplident, reloftype, o.nspname AS typnspname, y.typname, false AS relispartition, NULL AS partitionkeydef, NULL AS partitionbound, c.relhassubclass FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) LEFT JOIN pg_tablespace t ON (c.reltablespace = t.oid) LEFT JOIN (pg_type y INNER JOIN pg_namespace o ON (y.typnamespace = o.oid)) ON (c.reloftype = y.oid) WHERE relkind = 'r' AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema' %s%s AND NOT EXISTS(SELECT 1 FROM pg_depend d WHERE t.oid = d.objid AND d.deptype = 'e') ORDER BY n.nspname, relname", include_schema_str, exclude_schema_str); + query = psprintf("SELECT c.oid, n.nspname, c.relname, c.relkind, t.spcname AS tablespacename, c.relpersistence, array_to_string(c.reloptions, ', ') AS reloptions, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl, relreplident, reloftype, o.nspname AS typnspname, y.typname, false AS relispartition, NULL AS partitionkeydef, NULL AS partitionbound, c.relhassubclass FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) LEFT JOIN pg_tablespace t ON (c.reltablespace = t.oid) LEFT JOIN (pg_type y INNER JOIN pg_namespace o ON (y.typnamespace = o.oid)) ON (c.reloftype = y.oid) WHERE relkind = 'r' AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema' %s%s %s%s AND NOT EXISTS(SELECT 1 FROM pg_depend d WHERE t.oid = d.objid AND d.deptype = 'e') ORDER BY n.nspname, relname", include_schema_str, exclude_schema_str, include_table_str, exclude_table_str); } else if (PGQ_IS_FOREIGN_TABLE(k)) { - query = psprintf("SELECT c.oid, n.nspname, c.relname, c.relkind, t.spcname AS tablespacename, c.relpersistence, array_to_string(c.reloptions, ', ') AS reloptions, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl, relreplident, reloftype, o.nspname AS typnspname, y.typname, false AS relispartition, NULL AS partitionkeydef, NULL AS partitionbound, c.relhassubclass FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) LEFT JOIN pg_tablespace t ON (c.reltablespace = t.oid) LEFT JOIN (pg_type y INNER JOIN pg_namespace o ON (y.typnamespace = o.oid)) ON (c.reloftype = y.oid) WHERE relkind = 'f' AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema' %s%s AND NOT EXISTS(SELECT 1 FROM pg_depend d WHERE t.oid = d.objid AND d.deptype = 'e') ORDER BY n.nspname, relname", include_schema_str, exclude_schema_str); + query = psprintf("SELECT c.oid, n.nspname, c.relname, c.relkind, t.spcname AS tablespacename, c.relpersistence, array_to_string(c.reloptions, ', ') AS reloptions, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl, relreplident, reloftype, o.nspname AS typnspname, y.typname, false AS relispartition, NULL AS partitionkeydef, NULL AS partitionbound, c.relhassubclass FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) LEFT JOIN pg_tablespace t ON (c.reltablespace = t.oid) LEFT JOIN (pg_type y INNER JOIN pg_namespace o ON (y.typnamespace = o.oid)) ON (c.reloftype = y.oid) WHERE relkind = 'f' AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema' %s%s %s%s AND NOT EXISTS(SELECT 1 FROM pg_depend d WHERE t.oid = d.objid AND d.deptype = 'e') ORDER BY n.nspname, relname", include_schema_str, exclude_schema_str, include_table_str, exclude_table_str); } else { @@ -144,11 +144,11 @@ getTables(PGconn *c, int *n, char k) { if (PGQ_IS_REGULAR_TABLE(k)) { - query = psprintf("SELECT c.oid, n.nspname, c.relname, c.relkind, t.spcname AS tablespacename, c.relpersistence, array_to_string(c.reloptions, ', ') AS reloptions, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl, 'v' AS relreplident, reloftype, o.nspname AS typnspname, y.typname, false AS relispartition, NULL AS partitionkeydef, NULL AS partitionbound, c.relhassubclass FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) LEFT JOIN pg_tablespace t ON (c.reltablespace = t.oid) LEFT JOIN (pg_type y INNER JOIN pg_namespace o ON (y.typnamespace = o.oid)) ON (c.reloftype = y.oid) WHERE relkind = 'r' AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema' %s%s AND NOT EXISTS(SELECT 1 FROM pg_depend d WHERE t.oid = d.objid AND d.deptype = 'e') ORDER BY n.nspname, relname", include_schema_str, exclude_schema_str); + query = psprintf("SELECT c.oid, n.nspname, c.relname, c.relkind, t.spcname AS tablespacename, c.relpersistence, array_to_string(c.reloptions, ', ') AS reloptions, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl, 'v' AS relreplident, reloftype, o.nspname AS typnspname, y.typname, false AS relispartition, NULL AS partitionkeydef, NULL AS partitionbound, c.relhassubclass FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) LEFT JOIN pg_tablespace t ON (c.reltablespace = t.oid) LEFT JOIN (pg_type y INNER JOIN pg_namespace o ON (y.typnamespace = o.oid)) ON (c.reloftype = y.oid) WHERE relkind = 'r' AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema' %s%s %s%s AND NOT EXISTS(SELECT 1 FROM pg_depend d WHERE t.oid = d.objid AND d.deptype = 'e') ORDER BY n.nspname, relname", include_schema_str, exclude_schema_str, include_table_str, exclude_table_str); } else if (PGQ_IS_FOREIGN_TABLE(k)) { - query = psprintf("SELECT c.oid, n.nspname, c.relname, c.relkind, t.spcname AS tablespacename, c.relpersistence, array_to_string(c.reloptions, ', ') AS reloptions, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl, 'v' AS relreplident, reloftype, o.nspname AS typnspname, y.typname, false AS relispartition, NULL AS partitionkeydef, NULL AS partitionbound, c.relhassubclass FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) LEFT JOIN pg_tablespace t ON (c.reltablespace = t.oid) LEFT JOIN (pg_type y INNER JOIN pg_namespace o ON (y.typnamespace = o.oid)) ON (c.reloftype = y.oid) WHERE relkind = 'f' AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema' %s%s AND NOT EXISTS(SELECT 1 FROM pg_depend d WHERE t.oid = d.objid AND d.deptype = 'e') ORDER BY n.nspname, relname", include_schema_str, exclude_schema_str); + query = psprintf("SELECT c.oid, n.nspname, c.relname, c.relkind, t.spcname AS tablespacename, c.relpersistence, array_to_string(c.reloptions, ', ') AS reloptions, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl, 'v' AS relreplident, reloftype, o.nspname AS typnspname, y.typname, false AS relispartition, NULL AS partitionkeydef, NULL AS partitionbound, c.relhassubclass FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) LEFT JOIN pg_tablespace t ON (c.reltablespace = t.oid) LEFT JOIN (pg_type y INNER JOIN pg_namespace o ON (y.typnamespace = o.oid)) ON (c.reloftype = y.oid) WHERE relkind = 'f' AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema' %s%s %s%s AND NOT EXISTS(SELECT 1 FROM pg_depend d WHERE t.oid = d.objid AND d.deptype = 'e') ORDER BY n.nspname, relname", include_schema_str, exclude_schema_str, include_table_str, exclude_table_str); } else { @@ -160,7 +160,7 @@ getTables(PGconn *c, int *n, char k) { if (PGQ_IS_REGULAR_TABLE(k)) { - query = psprintf("SELECT c.oid, n.nspname, c.relname, c.relkind, t.spcname AS tablespacename, 'p' AS relpersistence, array_to_string(c.reloptions, ', ') AS reloptions, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl, 'v' AS relreplident, 0 AS reloftype, NULL AS typnspname, NULL AS typname, false AS relispartition, NULL AS partitionkeydef, NULL AS partitionbound, c.relhassubclass FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) LEFT JOIN pg_tablespace t ON (c.reltablespace = t.oid) WHERE relkind = 'r' AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema' %s%s ORDER BY n.nspname, relname", include_schema_str, exclude_schema_str); + query = psprintf("SELECT c.oid, n.nspname, c.relname, c.relkind, t.spcname AS tablespacename, 'p' AS relpersistence, array_to_string(c.reloptions, ', ') AS reloptions, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl, 'v' AS relreplident, 0 AS reloftype, NULL AS typnspname, NULL AS typname, false AS relispartition, NULL AS partitionkeydef, NULL AS partitionbound, c.relhassubclass FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) LEFT JOIN pg_tablespace t ON (c.reltablespace = t.oid) WHERE relkind = 'r' AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema' %s%s %s%s ORDER BY n.nspname, relname", include_schema_str, exclude_schema_str, include_table_str, exclude_table_str); } else { @@ -629,24 +629,35 @@ getTableAttributes(PGconn *c, PQLTable *t) exit(EXIT_FAILURE); } + char *and_exclude_table_column_str = ""; + char *left_exclude_table_column_str = ""; + if (strlen(exclude_table_column_str) > 0) + { + if (PQserverVersion(c) >= 90400) + { + left_exclude_table_column_str = psprintf(" LEFT JOIN (SELECT * FROM json_to_recordset('%s') as x(t text, c text)) f ON f.t = a.attrelid::regclass::text AND f.c = a.attname", exclude_table_column_str); + and_exclude_table_column_str = " AND (f.t IS NULL OR a.attrelid::regclass::text <> f.t OR a.attname <> f.c)"; + } + } + if (PQserverVersion(c) >= 90200) /* support for foreign table attribute options */ { query = psprintf( - "SELECT a.attnum, a.attname, a.attnotnull, pg_catalog.format_type(t.oid, a.atttypmod) as atttypname, pg_get_expr(d.adbin, a.attrelid) as attdefexpr, CASE WHEN a.attcollation <> t.typcollation THEN c.collname ELSE NULL END AS attcollation, col_description(a.attrelid, a.attnum) AS description, a.attstattarget, a.attstorage, CASE WHEN t.typstorage <> a.attstorage THEN FALSE ELSE TRUE END AS defstorage, array_to_string(attoptions, ', ') AS attoptions, array_to_string(attfdwoptions, ', ') AS attfdwoptions, attacl FROM pg_attribute a LEFT JOIN pg_type t ON (a.atttypid = t.oid) LEFT JOIN pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum) LEFT JOIN pg_collation c ON (a.attcollation = c.oid) WHERE a.attrelid = %u AND a.attnum > 0 AND attisdropped IS FALSE ORDER BY a.attname", - t->obj.oid); + "SELECT a.attnum, a.attname, a.attnotnull, pg_catalog.format_type(t.oid, a.atttypmod) as atttypname, pg_get_expr(d.adbin, a.attrelid) as attdefexpr, CASE WHEN a.attcollation <> t.typcollation THEN c.collname ELSE NULL END AS attcollation, col_description(a.attrelid, a.attnum) AS description, a.attstattarget, a.attstorage, CASE WHEN t.typstorage <> a.attstorage THEN FALSE ELSE TRUE END AS defstorage, array_to_string(attoptions, ', ') AS attoptions, array_to_string(attfdwoptions, ', ') AS attfdwoptions, attacl FROM pg_attribute a LEFT JOIN pg_type t ON (a.atttypid = t.oid) LEFT JOIN pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum) LEFT JOIN pg_collation c ON (a.attcollation = c.oid) %s WHERE a.attrelid = %u %s%s AND a.attnum > 0 AND attisdropped IS FALSE ORDER BY a.attname", + left_exclude_table_column_str, t->obj.oid, exclude_column_str, and_exclude_table_column_str); } else if (PQserverVersion(c) >= 90100) /* support for collation */ { query = psprintf( - "SELECT a.attnum, a.attname, a.attnotnull, pg_catalog.format_type(t.oid, a.atttypmod) as atttypname, pg_get_expr(d.adbin, a.attrelid) as attdefexpr, CASE WHEN a.attcollation <> t.typcollation THEN c.collname ELSE NULL END AS attcollation, col_description(a.attrelid, a.attnum) AS description, a.attstattarget, a.attstorage, CASE WHEN t.typstorage <> a.attstorage THEN FALSE ELSE TRUE END AS defstorage, array_to_string(attoptions, ', ') AS attoptions, NULL AS attfdwoptions, attacl FROM pg_attribute a LEFT JOIN pg_type t ON (a.atttypid = t.oid) LEFT JOIN pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum) LEFT JOIN pg_collation c ON (a.attcollation = c.oid) WHERE a.attrelid = %u AND a.attnum > 0 AND attisdropped IS FALSE ORDER BY a.attname", - t->obj.oid); + "SELECT a.attnum, a.attname, a.attnotnull, pg_catalog.format_type(t.oid, a.atttypmod) as atttypname, pg_get_expr(d.adbin, a.attrelid) as attdefexpr, CASE WHEN a.attcollation <> t.typcollation THEN c.collname ELSE NULL END AS attcollation, col_description(a.attrelid, a.attnum) AS description, a.attstattarget, a.attstorage, CASE WHEN t.typstorage <> a.attstorage THEN FALSE ELSE TRUE END AS defstorage, array_to_string(attoptions, ', ') AS attoptions, NULL AS attfdwoptions, attacl FROM pg_attribute a LEFT JOIN pg_type t ON (a.atttypid = t.oid) LEFT JOIN pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum) LEFT JOIN pg_collation c ON (a.attcollation = c.oid) %s WHERE a.attrelid = %u %s%s AND a.attnum > 0 AND attisdropped IS FALSE ORDER BY a.attname", + left_exclude_table_column_str, t->obj.oid, exclude_column_str, and_exclude_table_column_str); } else { query = psprintf( - "SELECT a.attnum, a.attname, a.attnotnull, pg_catalog.format_type(t.oid, a.atttypmod) as atttypname, pg_get_expr(d.adbin, a.attrelid) as attdefexpr, NULL AS attcollation, col_description(a.attrelid, a.attnum) AS description, a.attstattarget, a.attstorage, CASE WHEN t.typstorage <> a.attstorage THEN FALSE ELSE TRUE END AS defstorage, array_to_string(attoptions, ', ') AS attoptions, NULL AS attfdwoptions, attacl FROM pg_attribute a LEFT JOIN pg_type t ON (a.atttypid = t.oid) LEFT JOIN pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum) WHERE a.attrelid = %u AND a.attnum > 0 AND attisdropped IS FALSE ORDER BY a.attname", - t->obj.oid); + "SELECT a.attnum, a.attname, a.attnotnull, pg_catalog.format_type(t.oid, a.atttypmod) as atttypname, pg_get_expr(d.adbin, a.attrelid) as attdefexpr, NULL AS attcollation, col_description(a.attrelid, a.attnum) AS description, a.attstattarget, a.attstorage, CASE WHEN t.typstorage <> a.attstorage THEN FALSE ELSE TRUE END AS defstorage, array_to_string(attoptions, ', ') AS attoptions, NULL AS attfdwoptions, attacl FROM pg_attribute a LEFT JOIN pg_type t ON (a.atttypid = t.oid) LEFT JOIN pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum) %s WHERE a.attrelid = %u %s%s AND a.attnum > 0 AND attisdropped IS FALSE ORDER BY a.attname", + left_exclude_table_column_str, t->obj.oid, exclude_column_str, and_exclude_table_column_str); } res = PQexec(c, query); From 25f7819e38fced4801b8b904a6ad3f075a3ce0ba Mon Sep 17 00:00:00 2001 From: alessandro Date: Sun, 23 Aug 2020 23:18:18 -0300 Subject: [PATCH 2/2] Changed exclude-table-column sintaxe to json --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d9d0ba..b2435d5 100644 --- a/README.md +++ b/README.md @@ -418,7 +418,7 @@ exclude-schema = ^public$ include-table = ^(table_a|table_b)$ exclude-table = ^(table_c|table_d)$ exclude-column = ^(column_c|column_d)$ -exclude-table-column = ^(table_g.column_g|table_h.column_h)$ +exclude-table-column = [{"t":"table_e","c":"column_e"}] [target] host = 10.27.0.8