Hi

2015-03-15 16:09 GMT+01:00 Tom Lane <t...@sss.pgh.pa.us>:

> Pavel Stehule <pavel.steh...@gmail.com> writes:
> > other variant, I hope better than previous. We can introduce new long
> > option "--strict". With this active option, every pattern specified by -t
> > option have to have identifies exactly only one table. It can be used for
> > any other "should to exists" patterns - schemas. Initial implementation
> in
> > attachment.
>
> I think this design is seriously broken.  If I have '-t foo*' the code
> should not prevent that from matching multiple tables.  What would the use
> case for such a restriction be?
>
> What would make sense to me is one or both of these ideas:
>
> * require a match for a wildcard-free -t switch
>
> * require at least one (not "exactly one") match for a wildcarded -t
>   switch.
>


attached initial implementation

Regards

Pavel


>
> Neither of those is what you wrote, though.
>
> If we implemented the second one of these, it would have to be controlled
> by a new switch, because there are plausible use cases for wildcards that
> sometimes don't match anything (not to mention backwards compatibility).
> There might be a reasonable argument for the first one being the
> default behavior, though; I'm not sure if we could get away with that
> from a compatibility perspective.
>
>                         regards, tom lane
>
commit c1c7d9671a751bda1918d479b81c38c538701ec1
Author: Pavel Stehule <pavel.steh...@gooddata.com>
Date:   Mon Mar 23 17:06:39 2015 +0100

    initial

diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index d7506e1..47ae6b8 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -983,7 +983,8 @@ bool
 processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern,
 					  bool have_where, bool force_escape,
 					  const char *schemavar, const char *namevar,
-					  const char *altnamevar, const char *visibilityrule)
+					  const char *altnamevar, const char *visibilityrule,
+					  bool *with_wildcards)
 {
 	PQExpBufferData schemabuf;
 	PQExpBufferData namebuf;
@@ -997,6 +998,10 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern,
 	(appendPQExpBufferStr(buf, have_where ? "  AND " : "WHERE "), \
 	 have_where = true, added_clause = true)
 
+#define SET_WITH_WILDCARDS(b)	if (with_wildcards) *with_wildcards = b;
+
+	SET_WITH_WILDCARDS(false);
+
 	if (pattern == NULL)
 	{
 		/* Default: select all visible objects */
@@ -1055,11 +1060,15 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern,
 		{
 			appendPQExpBufferStr(&namebuf, ".*");
 			cp++;
+
+			SET_WITH_WILDCARDS(true);
 		}
 		else if (!inquotes && ch == '?')
 		{
 			appendPQExpBufferChar(&namebuf, '.');
 			cp++;
+
+			SET_WITH_WILDCARDS(true);
 		}
 		else if (!inquotes && ch == '.')
 		{
diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h
index b176746..7fb7b62 100644
--- a/src/bin/pg_dump/dumputils.h
+++ b/src/bin/pg_dump/dumputils.h
@@ -94,7 +94,8 @@ extern bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf,
 					  const char *pattern,
 					  bool have_where, bool force_escape,
 					  const char *schemavar, const char *namevar,
-					  const char *altnamevar, const char *visibilityrule);
+					  const char *altnamevar, const char *visibilityrule,
+					  bool *with_wildcards);
 extern void buildShSecLabelQuery(PGconn *conn, const char *catalog_name,
 					 uint32 objectId, PQExpBuffer sql);
 extern void emitShSecLabels(PGconn *conn, PGresult *res,
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index f24fefa..dd1d813 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -114,6 +114,7 @@ static SimpleStringList table_exclude_patterns = {NULL, NULL};
 static SimpleOidList table_exclude_oids = {NULL, NULL};
 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
+static SimpleStringList optional_tables = {NULL, NULL};
 
 
 char		g_opaque_type[10];	/* name for the opaque type */
@@ -132,7 +133,7 @@ static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
 static void expand_schema_name_patterns(Archive *fout,
 							SimpleStringList *patterns,
 							SimpleOidList *oids);
-static void expand_table_name_patterns(Archive *fout,
+static void expand_table_name_patterns(Archive *fout, bool check_patterns,
 						   SimpleStringList *patterns,
 						   SimpleOidList *oids);
 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid, Oid objoid);
@@ -332,6 +333,7 @@ main(int argc, char **argv)
 		{"section", required_argument, NULL, 5},
 		{"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
 		{"snapshot", required_argument, NULL, 6},
+		{"table-if-exists", required_argument, NULL, 7},
 		{"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
 		{"no-security-labels", no_argument, &dopt.no_security_labels, 1},
 		{"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
@@ -515,6 +517,10 @@ main(int argc, char **argv)
 				dumpsnapshot = pg_strdup(optarg);
 				break;
 
+			case 7:				/* optional table dump */
+				simple_string_list_append(&optional_tables, optarg);
+				break;
+
 			default:
 				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 				exit_nicely(1);
@@ -697,17 +703,24 @@ main(int argc, char **argv)
 	/* non-matching exclusion patterns aren't an error */
 
 	/* Expand table selection patterns into OID lists */
-	if (table_include_patterns.head != NULL)
+	if (table_include_patterns.head != NULL || optional_tables.head != NULL)
 	{
-		expand_table_name_patterns(fout, &table_include_patterns,
+		expand_table_name_patterns(fout, true, &table_include_patterns,
+								   &table_include_oids);
+
+		expand_table_name_patterns(fout, true, &table_include_patterns,
+								   &table_include_oids);
+
+		expand_table_name_patterns(fout, false, &optional_tables,
 								   &table_include_oids);
+
 		if (table_include_oids.head == NULL)
 			exit_horribly(NULL, "No matching tables were found\n");
 	}
-	expand_table_name_patterns(fout, &table_exclude_patterns,
+	expand_table_name_patterns(fout, false, &table_exclude_patterns,
 							   &table_exclude_oids);
 
-	expand_table_name_patterns(fout, &tabledata_exclude_patterns,
+	expand_table_name_patterns(fout, false, &tabledata_exclude_patterns,
 							   &tabledata_exclude_oids);
 
 	/* non-matching exclusion patterns aren't an error */
@@ -903,6 +916,7 @@ help(const char *progname)
 	printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
 	printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
 	printf(_("  --snapshot=SNAPSHOT          use given synchronous snapshot for the dump\n"));
+	printf(_("  --table-if-exists=TABLE      optional dump table\n"));
 	printf(_("  --use-set-session-authorization\n"
 			 "                               use SET SESSION AUTHORIZATION commands instead of\n"
 			 "                               ALTER OWNER commands to set ownership\n"));
@@ -1159,7 +1173,7 @@ expand_schema_name_patterns(Archive *fout,
 		appendPQExpBuffer(query,
 						  "SELECT oid FROM pg_catalog.pg_namespace n\n");
 		processSQLNamePattern(GetConnection(fout), query, cell->val, false,
-							  false, NULL, "n.nspname", NULL, NULL);
+							  false, NULL, "n.nspname", NULL, NULL, NULL);
 	}
 
 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
@@ -1176,20 +1190,36 @@ expand_schema_name_patterns(Archive *fout,
 /*
  * Find the OIDs of all tables matching the given list of patterns,
  * and append them to the given OID list.
+ *
+ * When check_patterns is true, then ensure any pattern without wildcards has to specify one or
+ * more tables.
  */
 static void
-expand_table_name_patterns(Archive *fout,
+expand_table_name_patterns(Archive *fout, bool	check_patterns,
 						   SimpleStringList *patterns, SimpleOidList *oids)
 {
 	PQExpBuffer query;
+	PQExpBuffer query_nonempty_check;
+	PQExpBuffer filter;
 	PGresult   *res;
 	SimpleStringListCell *cell;
 	int			i;
 
+#define SEARCH_TABLE_OID_QUERY_WITH_FILTER	\
+    "SELECT c.oid" \
+	"\nFROM pg_catalog.pg_class c" \
+	"\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace" \
+	"\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c')\n" \
+	"%s", \
+	RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW, \
+	RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE
+
 	if (patterns->head == NULL)
 		return;					/* nothing to do */
 
 	query = createPQExpBuffer();
+	query_nonempty_check = createPQExpBuffer();
+	filter = createPQExpBuffer();
 
 	/*
 	 * We use UNION ALL rather than UNION; this might sometimes result in
@@ -1198,28 +1228,56 @@ expand_table_name_patterns(Archive *fout,
 
 	for (cell = patterns->head; cell; cell = cell->next)
 	{
-		if (cell != patterns->head)
-			appendPQExpBufferStr(query, "UNION ALL\n");
-		appendPQExpBuffer(query,
-						  "SELECT c.oid"
-						  "\nFROM pg_catalog.pg_class c"
-		"\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
-					 "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c')\n",
-						  RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
-						  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
-		processSQLNamePattern(GetConnection(fout), query, cell->val, true,
+		bool	with_wildcards;
+
+		processSQLNamePattern(GetConnection(fout), filter, cell->val, true,
 							  false, "n.nspname", "c.relname", NULL,
-							  "pg_catalog.pg_table_is_visible(c.oid)");
-	}
+							  "pg_catalog.pg_table_is_visible(c.oid)",
+							  &with_wildcards);
 
-	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+		if (check_patterns && !with_wildcards)
+		{
+			appendPQExpBuffer(query_nonempty_check,
+						  SEARCH_TABLE_OID_QUERY_WITH_FILTER,
+						  filter->data);
 
-	for (i = 0; i < PQntuples(res); i++)
+			res = ExecuteSqlQuery(fout, query_nonempty_check->data, PGRES_TUPLES_OK);
+			if (PQntuples(res) == 0)
+				exit_horribly(NULL, "No matching table were found for \"%s\"\n", cell->val);
+
+			for (i = 0; i < PQntuples(res); i++)
+			{
+				simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
+			}
+
+			PQclear(res);
+			resetPQExpBuffer(query_nonempty_check);
+		}
+		else
+		{
+			if (cell != patterns->head)
+				appendPQExpBufferStr(query, "UNION ALL\n");
+			appendPQExpBuffer(query,
+							  SEARCH_TABLE_OID_QUERY_WITH_FILTER,
+							  filter->data);
+		}
+
+		resetPQExpBuffer(filter);
+	}
+
+	if (*query->data != '\0')
 	{
-		simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
+		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+
+		for (i = 0; i < PQntuples(res); i++)
+		{
+			simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
+		}
+
+		PQclear(res);
 	}
 
-	PQclear(res);
+	destroyPQExpBuffer(filter);
 	destroyPQExpBuffer(query);
 }
 
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to