diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bin/pg_amcheck/pg_amcheck.c | 27 | ||||
-rw-r--r-- | src/bin/pg_amcheck/t/002_nonesuch.pl | 99 | ||||
-rw-r--r-- | src/bin/pg_dump/pg_dump.c | 65 | ||||
-rw-r--r-- | src/bin/pg_dump/pg_dumpall.c | 13 | ||||
-rw-r--r-- | src/bin/pg_dump/t/002_pg_dump.pl | 107 | ||||
-rw-r--r-- | src/bin/psql/describe.c | 504 | ||||
-rw-r--r-- | src/fe_utils/string_utils.c | 129 | ||||
-rw-r--r-- | src/include/fe_utils/string_utils.h | 6 | ||||
-rw-r--r-- | src/test/regress/expected/psql.out | 804 | ||||
-rw-r--r-- | src/test/regress/sql/psql.sql | 242 |
10 files changed, 1781 insertions, 215 deletions
diff --git a/src/bin/pg_amcheck/pg_amcheck.c b/src/bin/pg_amcheck/pg_amcheck.c index 90471e096d2..48cee8c1c4e 100644 --- a/src/bin/pg_amcheck/pg_amcheck.c +++ b/src/bin/pg_amcheck/pg_amcheck.c @@ -1308,10 +1308,17 @@ static void append_database_pattern(PatternInfoArray *pia, const char *pattern, int encoding) { PQExpBufferData buf; + int dotcnt; PatternInfo *info = extend_pattern_info_array(pia); initPQExpBuffer(&buf); - patternToSQLRegex(encoding, NULL, NULL, &buf, pattern, false); + patternToSQLRegex(encoding, NULL, NULL, &buf, pattern, false, false, + &dotcnt); + if (dotcnt > 0) + { + pg_log_error("improper qualified name (too many dotted names): %s", pattern); + exit(2); + } info->pattern = pattern; info->db_regex = pstrdup(buf.data); @@ -1332,12 +1339,19 @@ append_schema_pattern(PatternInfoArray *pia, const char *pattern, int encoding) { PQExpBufferData dbbuf; PQExpBufferData nspbuf; + int dotcnt; PatternInfo *info = extend_pattern_info_array(pia); initPQExpBuffer(&dbbuf); initPQExpBuffer(&nspbuf); - patternToSQLRegex(encoding, NULL, &dbbuf, &nspbuf, pattern, false); + patternToSQLRegex(encoding, NULL, &dbbuf, &nspbuf, pattern, false, false, + &dotcnt); + if (dotcnt > 1) + { + pg_log_error("improper qualified name (too many dotted names): %s", pattern); + exit(2); + } info->pattern = pattern; if (dbbuf.data[0]) { @@ -1369,13 +1383,20 @@ append_relation_pattern_helper(PatternInfoArray *pia, const char *pattern, PQExpBufferData dbbuf; PQExpBufferData nspbuf; PQExpBufferData relbuf; + int dotcnt; PatternInfo *info = extend_pattern_info_array(pia); initPQExpBuffer(&dbbuf); initPQExpBuffer(&nspbuf); initPQExpBuffer(&relbuf); - patternToSQLRegex(encoding, &dbbuf, &nspbuf, &relbuf, pattern, false); + patternToSQLRegex(encoding, &dbbuf, &nspbuf, &relbuf, pattern, false, + false, &dotcnt); + if (dotcnt > 2) + { + pg_log_error("improper relation name (too many dotted names): %s", pattern); + exit(2); + } info->pattern = pattern; if (dbbuf.data[0]) { diff --git a/src/bin/pg_amcheck/t/002_nonesuch.pl b/src/bin/pg_amcheck/t/002_nonesuch.pl index 56d55199f84..6c0f97027dd 100644 --- a/src/bin/pg_amcheck/t/002_nonesuch.pl +++ b/src/bin/pg_amcheck/t/002_nonesuch.pl @@ -147,6 +147,100 @@ $node->command_checks_all( [qr/pg_amcheck: error: no heap tables to check matching "\."/], 'checking table pattern "."'); +# Check that a multipart database name is rejected +$node->command_checks_all( + [ 'pg_amcheck', '-d', 'localhost.postgres' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper qualified name \(too many dotted names\): localhost\.postgres/ + ], + 'multipart database patterns are rejected' +); + +# Check that a three-part schema name is rejected +$node->command_checks_all( + [ 'pg_amcheck', '-s', 'localhost.postgres.pg_catalog' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper qualified name \(too many dotted names\): localhost\.postgres\.pg_catalog/ + ], + 'three part schema patterns are rejected' +); + +# Check that a four-part table name is rejected +$node->command_checks_all( + [ 'pg_amcheck', '-t', 'localhost.postgres.pg_catalog.pg_class' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper relation name \(too many dotted names\): localhost\.postgres\.pg_catalog\.pg_class/ + ], + 'four part table patterns are rejected' +); + +# Check that too many dotted names still draws an error under --no-strict-names +# That flag means that it is ok for the object to be missing, not that it is ok +# for the object name to be ungrammatical +$node->command_checks_all( + [ 'pg_amcheck', '--no-strict-names', '-t', 'this.is.a.really.long.dotted.string' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper relation name \(too many dotted names\): this\.is\.a\.really\.long\.dotted\.string/ + ], + 'ungrammatical table names still draw errors under --no-strict-names' +); +$node->command_checks_all( + [ 'pg_amcheck', '--no-strict-names', '-s', 'postgres.long.dotted.string' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper qualified name \(too many dotted names\): postgres\.long\.dotted\.string/ + ], + 'ungrammatical schema names still draw errors under --no-strict-names' +); +$node->command_checks_all( + [ 'pg_amcheck', '--no-strict-names', '-d', 'postgres.long.dotted.string' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper qualified name \(too many dotted names\): postgres\.long\.dotted\.string/ + ], + 'ungrammatical database names still draw errors under --no-strict-names' +); + +# Likewise for exclusion patterns +$node->command_checks_all( + [ 'pg_amcheck', '--no-strict-names', '-T', 'a.b.c.d' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper relation name \(too many dotted names\): a\.b\.c\.d/ + ], + 'ungrammatical table exclusions still draw errors under --no-strict-names' +); +$node->command_checks_all( + [ 'pg_amcheck', '--no-strict-names', '-S', 'a.b.c' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper qualified name \(too many dotted names\): a\.b\.c/ + ], + 'ungrammatical schema exclusions still draw errors under --no-strict-names' +); +$node->command_checks_all( + [ 'pg_amcheck', '--no-strict-names', '-D', 'a.b' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper qualified name \(too many dotted names\): a\.b/ + ], + 'ungrammatical database exclusions still draw errors under --no-strict-names' +); + + ######################################### # Test checking non-existent databases, schemas, tables, and indexes @@ -165,9 +259,7 @@ $node->command_checks_all( '-d', 'no*such*database', '-r', 'none.none', '-r', 'none.none.none', - '-r', 'this.is.a.really.long.dotted.string', '-r', 'postgres.none.none', - '-r', 'postgres.long.dotted.string', '-r', 'postgres.pg_catalog.none', '-r', 'postgres.none.pg_class', '-t', 'postgres.pg_catalog.pg_class', # This exists @@ -186,15 +278,12 @@ $node->command_checks_all( qr/pg_amcheck: warning: no connectable databases to check matching "no\*such\*database"/, qr/pg_amcheck: warning: no relations to check matching "none\.none"/, qr/pg_amcheck: warning: no connectable databases to check matching "none\.none\.none"/, - qr/pg_amcheck: warning: no connectable databases to check matching "this\.is\.a\.really\.long\.dotted\.string"/, qr/pg_amcheck: warning: no relations to check matching "postgres\.none\.none"/, - qr/pg_amcheck: warning: no relations to check matching "postgres\.long\.dotted\.string"/, qr/pg_amcheck: warning: no relations to check matching "postgres\.pg_catalog\.none"/, qr/pg_amcheck: warning: no relations to check matching "postgres\.none\.pg_class"/, qr/pg_amcheck: warning: no connectable databases to check matching "no_such_database"/, qr/pg_amcheck: warning: no connectable databases to check matching "no\*such\*database"/, qr/pg_amcheck: warning: no connectable databases to check matching "none\.none\.none"/, - qr/pg_amcheck: warning: no connectable databases to check matching "this\.is\.a\.really\.long\.dotted\.string"/, ], 'many unmatched patterns and one matched pattern under --no-strict-names' ); diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 969e2a7a462..d3588607e74 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -178,6 +178,9 @@ static void expand_table_name_patterns(Archive *fout, SimpleStringList *patterns, SimpleOidList *oids, bool strict_names); +static void prohibit_crossdb_refs(PGconn *conn, const char *dbname, + const char *pattern); + static NamespaceInfo *findNamespace(Oid nsoid); static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo); static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo); @@ -1315,10 +1318,21 @@ expand_schema_name_patterns(Archive *fout, for (cell = patterns->head; cell; cell = cell->next) { + PQExpBufferData dbbuf; + int dotcnt; + appendPQExpBufferStr(query, "SELECT oid FROM pg_catalog.pg_namespace n\n"); + initPQExpBuffer(&dbbuf); processSQLNamePattern(GetConnection(fout), query, cell->val, false, - false, NULL, "n.nspname", NULL, NULL); + false, NULL, "n.nspname", NULL, NULL, &dbbuf, + &dotcnt); + if (dotcnt > 1) + pg_fatal("improper qualified name (too many dotted names): %s", + cell->val); + else if (dotcnt == 1) + prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val); + termPQExpBuffer(&dbbuf); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); if (strict_names && PQntuples(res) == 0) @@ -1362,10 +1376,16 @@ expand_extension_name_patterns(Archive *fout, */ for (cell = patterns->head; cell; cell = cell->next) { + int dotcnt; + appendPQExpBufferStr(query, "SELECT oid FROM pg_catalog.pg_extension e\n"); processSQLNamePattern(GetConnection(fout), query, cell->val, false, - false, NULL, "e.extname", NULL, NULL); + false, NULL, "e.extname", NULL, NULL, NULL, + &dotcnt); + if (dotcnt > 0) + pg_fatal("improper qualified name (too many dotted names): %s", + cell->val); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); if (strict_names && PQntuples(res) == 0) @@ -1409,10 +1429,16 @@ expand_foreign_server_name_patterns(Archive *fout, for (cell = patterns->head; cell; cell = cell->next) { + int dotcnt; + appendPQExpBufferStr(query, "SELECT oid FROM pg_catalog.pg_foreign_server s\n"); processSQLNamePattern(GetConnection(fout), query, cell->val, false, - false, NULL, "s.srvname", NULL, NULL); + false, NULL, "s.srvname", NULL, NULL, NULL, + &dotcnt); + if (dotcnt > 0) + pg_fatal("improper qualified name (too many dotted names): %s", + cell->val); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); if (PQntuples(res) == 0) @@ -1455,6 +1481,9 @@ expand_table_name_patterns(Archive *fout, for (cell = patterns->head; cell; cell = cell->next) { + PQExpBufferData dbbuf; + int dotcnt; + /* * Query must remain ABSOLUTELY devoid of unqualified names. This * would be unnecessary given a pg_table_is_visible() variant taking a @@ -1470,9 +1499,17 @@ expand_table_name_patterns(Archive *fout, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW, RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE, RELKIND_PARTITIONED_TABLE); + initPQExpBuffer(&dbbuf); processSQLNamePattern(GetConnection(fout), query, 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)", &dbbuf, + &dotcnt); + if (dotcnt > 2) + pg_fatal("improper relation name (too many dotted names): %s", + cell->val); + else if (dotcnt == 2) + prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val); + termPQExpBuffer(&dbbuf); ExecuteSqlStatement(fout, "RESET search_path"); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -1494,6 +1531,26 @@ expand_table_name_patterns(Archive *fout, } /* + * Verifies that the connected database name matches the given database name, + * and if not, dies with an error about the given pattern. + * + * The 'dbname' argument should be a literal name parsed from 'pattern'. + */ +static void +prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern) +{ + const char *db; + + db = PQdb(conn); + if (db == NULL) + pg_fatal("You are currently not connected to a database."); + + if (strcmp(db, dbname) != 0) + pg_fatal("cross-database references are not implemented: %s", + pattern); +} + +/* * checkExtensionMembership * Determine whether object is an extension member, and if so, * record an appropriate dependency and set the object's dump flag. diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 79a723885ed..52f9f7c4d66 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -1269,10 +1269,21 @@ expand_dbname_patterns(PGconn *conn, for (SimpleStringListCell *cell = patterns->head; cell; cell = cell->next) { + int dotcnt; + appendPQExpBufferStr(query, "SELECT datname FROM pg_catalog.pg_database n\n"); processSQLNamePattern(conn, query, cell->val, false, - false, NULL, "datname", NULL, NULL); + false, NULL, "datname", NULL, NULL, NULL, + &dotcnt); + + if (dotcnt > 0) + { + pg_log_error("improper qualified name (too many dotted names): %s", + cell->val); + PQfinish(conn); + exit_nicely(1); + } res = executeQuery(conn, query->data); for (int i = 0; i < PQntuples(res); i++) diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index c65c92bfb0e..1ecfd7ae235 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -3974,6 +3974,113 @@ command_fails_like( 'no matching tables'); ######################################### +# Test invalid multipart database names + +$node->command_fails_like( + [ 'pg_dumpall', '--exclude-database', '.' ], + qr/pg_dumpall: error: improper qualified name \(too many dotted names\): \./, + 'pg_dumpall: option --exclude-database rejects multipart pattern "."' +); + +$node->command_fails_like( + [ 'pg_dumpall', '--exclude-database', '.*' ], + qr/pg_dumpall: error: improper qualified name \(too many dotted names\): \.\*/, + 'pg_dumpall: option --exclude-database rejects multipart pattern ".*"' +); + +$node->command_fails_like( + [ 'pg_dumpall', '--exclude-database', '*.*' ], + qr/pg_dumpall: error: improper qualified name \(too many dotted names\): \*\.\*/, + 'pg_dumpall: option --exclude-database rejects multipart pattern "*.*"' +); + +$node->command_fails_like( + [ 'pg_dumpall', '--exclude-database', 'myhost.mydb' ], + qr/pg_dumpall: error: improper qualified name \(too many dotted names\): myhost\.mydb/, + 'pg_dumpall: option --exclude-database rejects multipart database names' +); + +######################################### +# Test valid database exclusion patterns + +$node->command_ok( + [ 'pg_dumpall', '-p', "$port", '--exclude-database', '"myhost.mydb"' ], + 'pg_dumpall: option --exclude-database handles database names with embedded dots' +); + +$node->command_ok( + [ 'pg_dumpall', '--exclude-database', '??*' ], + 'pg_dumpall: option --exclude-database handles database name patterns' +); + + +######################################### +# Test invalid multipart schema names + +$node->command_fails_like( + [ 'pg_dump', '--schema', 'myhost.mydb.myschema' ], + qr/pg_dump: error: improper qualified name \(too many dotted names\): myhost\.mydb\.myschema/, + 'pg_dump: option --schema rejects three-part schema names' +); + +$node->command_fails_like( + [ 'pg_dump', '--schema', 'otherdb.myschema' ], + qr/pg_dump: error: cross-database references are not implemented: otherdb\.myschema/, + 'pg_dump: option --schema rejects cross-database multipart schema names' +); + +$node->command_fails_like( + [ 'pg_dump', '--schema', '.' ], + qr/pg_dump: error: cross-database references are not implemented: \./, + 'pg_dump: option --schema rejects degenerate two-part schema name: "."' +); + +$node->command_fails_like( + [ 'pg_dump', '--schema', '"some.other.db".myschema' ], + qr/pg_dump: error: cross-database references are not implemented: "some\.other\.db"\.myschema/, + 'pg_dump: option --schema rejects cross-database multipart schema names with embedded dots' +); + +$node->command_fails_like( + [ 'pg_dump', '--schema', '.*' ], + qr/pg_dump: error: cross-database references are not implemented: \.\*/, + 'pg_dump: option --schema rejects degenerate two-part schema name: ".*"' +); + +$node->command_fails_like( + [ 'pg_dump', '--schema', '..' ], + qr/pg_dump: error: improper qualified name \(too many dotted names\): \.\./, + 'pg_dump: option --schema rejects degenerate three-part schema name: ".."' +); + +$node->command_fails_like( + [ 'pg_dump', '--schema', '.*.*' ], + qr/pg_dump: error: improper qualified name \(too many dotted names\): \.\*\.\*/, + 'pg_dump: option --schema rejects degenerate three-part schema pattern: ".*.*"' +); + +######################################### +# Test invalid multipart relation names + +$node->command_fails_like( + [ 'pg_dump', '--table', 'myhost.mydb.myschema.mytable' ], + qr/pg_dump: error: improper relation name \(too many dotted names\): myhost\.mydb\.myschema\.mytable/, + 'pg_dump: option --table rejects four-part table names' +); + +$node->command_fails_like( + [ 'pg_dump', '--table', 'otherdb.pg_catalog.pg_class' ], + qr/pg_dump: error: cross-database references are not implemented: otherdb\.pg_catalog\.pg_class/, + 'pg_dump: option --table rejects cross-database three part table names' +); + +command_fails_like( + [ 'pg_dump', '-p', "$port", '--table', '"some.other.db".pg_catalog.pg_class' ], + qr/pg_dump: error: cross-database references are not implemented: "some\.other\.db"\.pg_catalog\.pg_class/, + 'pg_dump: option --table rejects cross-database three part table names with embedded dots' +); + +######################################### # Run all runs foreach my $run (sort keys %pgdump_runs) diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 583817b0cc6..4369f2235b4 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -46,6 +46,12 @@ static bool describeOneTSConfig(const char *oid, const char *nspname, const char *pnspname, const char *prsname); static void printACLColumn(PQExpBuffer buf, const char *colname); static bool listOneExtensionContents(const char *extname, const char *oid); +static bool validateSQLNamePattern(PQExpBuffer buf, const char *pattern, + bool have_where, bool force_escape, + const char *schemavar, const char *namevar, + const char *altnamevar, + const char *visibilityrule, + bool *added_clause, int maxparts); /*---------------- @@ -102,9 +108,11 @@ describeAggregates(const char *pattern, bool verbose, bool showSystem) appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n" " AND n.nspname <> 'information_schema'\n"); - processSQLNamePattern(pset.db, &buf, pattern, true, false, - "n.nspname", "p.proname", NULL, - "pg_catalog.pg_function_is_visible(p.oid)"); + if (!validateSQLNamePattern(&buf, pattern, true, false, + "n.nspname", "p.proname", NULL, + "pg_catalog.pg_function_is_visible(p.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;"); @@ -170,9 +178,11 @@ describeAccessMethods(const char *pattern, bool verbose) appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_am\n"); - processSQLNamePattern(pset.db, &buf, pattern, false, false, - NULL, "amname", NULL, - NULL); + if (!validateSQLNamePattern(&buf, pattern, false, false, + NULL, "amname", NULL, + NULL, + NULL, 1)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1;"); @@ -230,9 +240,11 @@ describeTablespaces(const char *pattern, bool verbose) appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_tablespace\n"); - processSQLNamePattern(pset.db, &buf, pattern, false, false, - NULL, "spcname", NULL, - NULL); + if (!validateSQLNamePattern(&buf, pattern, false, false, + NULL, "spcname", NULL, + NULL, + NULL, 1)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1;"); @@ -518,9 +530,11 @@ describeFunctions(const char *functypes, const char *func_pattern, appendPQExpBufferStr(&buf, " )\n"); } - processSQLNamePattern(pset.db, &buf, func_pattern, have_where, false, - "n.nspname", "p.proname", NULL, - "pg_catalog.pg_function_is_visible(p.oid)"); + if (!validateSQLNamePattern(&buf, func_pattern, have_where, false, + "n.nspname", "p.proname", NULL, + "pg_catalog.pg_function_is_visible(p.oid)", + NULL, 3)) + return false; for (int i = 0; i < num_arg_patterns; i++) { @@ -542,10 +556,12 @@ describeFunctions(const char *functypes, const char *func_pattern, "pg_catalog.format_type(t%d.oid, NULL)", i); snprintf(tiv, sizeof(tiv), "pg_catalog.pg_type_is_visible(t%d.oid)", i); - processSQLNamePattern(pset.db, &buf, - map_typename_pattern(arg_patterns[i]), - true, false, - nspname, typname, ft, tiv); + if (!validateSQLNamePattern(&buf, + map_typename_pattern(arg_patterns[i]), + true, false, + nspname, typname, ft, tiv, + NULL, 3)) + return false; } else { @@ -660,11 +676,13 @@ describeTypes(const char *pattern, bool verbose, bool showSystem) " AND n.nspname <> 'information_schema'\n"); /* Match name pattern against either internal or external name */ - processSQLNamePattern(pset.db, &buf, map_typename_pattern(pattern), - true, false, - "n.nspname", "t.typname", - "pg_catalog.format_type(t.oid, NULL)", - "pg_catalog.pg_type_is_visible(t.oid)"); + if (!validateSQLNamePattern(&buf, map_typename_pattern(pattern), + true, false, + "n.nspname", "t.typname", + "pg_catalog.format_type(t.oid, NULL)", + "pg_catalog.pg_type_is_visible(t.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); @@ -813,10 +831,12 @@ describeOperators(const char *oper_pattern, appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n" " AND n.nspname <> 'information_schema'\n"); - processSQLNamePattern(pset.db, &buf, oper_pattern, - !showSystem && !oper_pattern, true, - "n.nspname", "o.oprname", NULL, - "pg_catalog.pg_operator_is_visible(o.oid)"); + if (!validateSQLNamePattern(&buf, oper_pattern, + !showSystem && !oper_pattern, true, + "n.nspname", "o.oprname", NULL, + "pg_catalog.pg_operator_is_visible(o.oid)", + NULL, 3)) + return false; if (num_arg_patterns == 1) appendPQExpBufferStr(&buf, " AND o.oprleft = 0\n"); @@ -841,10 +861,12 @@ describeOperators(const char *oper_pattern, "pg_catalog.format_type(t%d.oid, NULL)", i); snprintf(tiv, sizeof(tiv), "pg_catalog.pg_type_is_visible(t%d.oid)", i); - processSQLNamePattern(pset.db, &buf, - map_typename_pattern(arg_patterns[i]), - true, false, - nspname, typname, ft, tiv); + if (!validateSQLNamePattern(&buf, + map_typename_pattern(arg_patterns[i]), + true, false, + nspname, typname, ft, tiv, + NULL, 3)) + return false; } else { @@ -928,8 +950,10 @@ listAllDbs(const char *pattern, bool verbose) " JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid\n"); if (pattern) - processSQLNamePattern(pset.db, &buf, pattern, false, false, - NULL, "d.datname", NULL, NULL); + if (!validateSQLNamePattern(&buf, pattern, false, false, + NULL, "d.datname", NULL, NULL, + NULL, 1)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1;"); res = PSQLexec(buf.data); @@ -1078,9 +1102,11 @@ permissionsList(const char *pattern) * point of view. You can see 'em by explicit request though, eg with \z * pg_catalog.* */ - processSQLNamePattern(pset.db, &buf, pattern, true, false, - "n.nspname", "c.relname", NULL, - "n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid)"); + if (!validateSQLNamePattern(&buf, pattern, true, false, + "n.nspname", "c.relname", NULL, + "n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); @@ -1145,11 +1171,13 @@ listDefaultACLs(const char *pattern) appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_default_acl d\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace\n"); - processSQLNamePattern(pset.db, &buf, pattern, false, false, - NULL, - "n.nspname", - "pg_catalog.pg_get_userbyid(d.defaclrole)", - NULL); + if (!validateSQLNamePattern(&buf, pattern, false, false, + NULL, + "n.nspname", + "pg_catalog.pg_get_userbyid(d.defaclrole)", + NULL, + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3;"); @@ -1221,9 +1249,11 @@ objectDescription(const char *pattern, bool showSystem) appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n" " AND n.nspname <> 'information_schema'\n"); - processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, - false, "n.nspname", "pgc.conname", NULL, - "pg_catalog.pg_table_is_visible(c.oid)"); + if (!validateSQLNamePattern(&buf, pattern, !showSystem && !pattern, + false, "n.nspname", "pgc.conname", NULL, + "pg_catalog.pg_table_is_visible(c.oid)", + NULL, 3)) + return false; /* Domain constraint descriptions */ appendPQExpBuffer(&buf, @@ -1243,9 +1273,11 @@ objectDescription(const char *pattern, bool showSystem) appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n" " AND n.nspname <> 'information_schema'\n"); - processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, - false, "n.nspname", "pgc.conname", NULL, - "pg_catalog.pg_type_is_visible(t.oid)"); + if (!validateSQLNamePattern(&buf, pattern, !showSystem && !pattern, + false, "n.nspname", "pgc.conname", NULL, + "pg_catalog.pg_type_is_visible(t.oid)", + NULL, 3)) + return false; /* Operator class descriptions */ appendPQExpBuffer(&buf, @@ -1265,9 +1297,11 @@ objectDescription(const char *pattern, bool showSystem) appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n" " AND n.nspname <> 'information_schema'\n"); - processSQLNamePattern(pset.db, &buf, pattern, true, false, - "n.nspname", "o.opcname", NULL, - "pg_catalog.pg_opclass_is_visible(o.oid)"); + if (!validateSQLNamePattern(&buf, pattern, true, false, + "n.nspname", "o.opcname", NULL, + "pg_catalog.pg_opclass_is_visible(o.oid)", + NULL, 3)) + return false; /* Operator family descriptions */ appendPQExpBuffer(&buf, @@ -1287,9 +1321,11 @@ objectDescription(const char *pattern, bool showSystem) appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n" " AND n.nspname <> 'information_schema'\n"); - processSQLNamePattern(pset.db, &buf, pattern, true, false, - "n.nspname", "opf.opfname", NULL, - "pg_catalog.pg_opfamily_is_visible(opf.oid)"); + if (!validateSQLNamePattern(&buf, pattern, true, false, + "n.nspname", "opf.opfname", NULL, + "pg_catalog.pg_opfamily_is_visible(opf.oid)", + NULL, 3)) + return false; /* Rule descriptions (ignore rules for views) */ appendPQExpBuffer(&buf, @@ -1308,9 +1344,11 @@ objectDescription(const char *pattern, bool showSystem) appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n" " AND n.nspname <> 'information_schema'\n"); - processSQLNamePattern(pset.db, &buf, pattern, true, false, - "n.nspname", "r.rulename", NULL, - "pg_catalog.pg_table_is_visible(c.oid)"); + if (!validateSQLNamePattern(&buf, pattern, true, false, + "n.nspname", "r.rulename", NULL, + "pg_catalog.pg_table_is_visible(c.oid)", + NULL, 3)) + return false; /* Trigger descriptions */ appendPQExpBuffer(&buf, @@ -1328,9 +1366,11 @@ objectDescription(const char *pattern, bool showSystem) appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n" " AND n.nspname <> 'information_schema'\n"); - processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false, - "n.nspname", "t.tgname", NULL, - "pg_catalog.pg_table_is_visible(c.oid)"); + if (!validateSQLNamePattern(&buf, pattern, !showSystem && !pattern, false, + "n.nspname", "t.tgname", NULL, + "pg_catalog.pg_table_is_visible(c.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, ") AS tt\n" @@ -1384,9 +1424,11 @@ describeTableDetails(const char *pattern, bool verbose, bool showSystem) appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n" " AND n.nspname <> 'information_schema'\n"); - processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false, - "n.nspname", "c.relname", NULL, - "pg_catalog.pg_table_is_visible(c.oid)"); + if (!validateSQLNamePattern(&buf, pattern, !showSystem && !pattern, false, + "n.nspname", "c.relname", NULL, + "pg_catalog.pg_table_is_visible(c.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 2, 3;"); @@ -3572,8 +3614,10 @@ describeRoles(const char *pattern, bool verbose, bool showSystem) if (!showSystem && !pattern) appendPQExpBufferStr(&buf, "WHERE r.rolname !~ '^pg_'\n"); - processSQLNamePattern(pset.db, &buf, pattern, false, false, - NULL, "r.rolname", NULL, NULL); + if (!validateSQLNamePattern(&buf, pattern, false, false, + NULL, "r.rolname", NULL, NULL, + NULL, 1)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1;"); @@ -3696,10 +3740,13 @@ listDbRoleSettings(const char *pattern, const char *pattern2) gettext_noop("Role"), gettext_noop("Database"), gettext_noop("Settings")); - havewhere = processSQLNamePattern(pset.db, &buf, pattern, false, false, - NULL, "r.rolname", NULL, NULL); - processSQLNamePattern(pset.db, &buf, pattern2, havewhere, false, - NULL, "d.datname", NULL, NULL); + if (!validateSQLNamePattern(&buf, pattern, false, false, + NULL, "r.rolname", NULL, NULL, &havewhere, 1)) + return false; + if (!validateSQLNamePattern(&buf, pattern2, havewhere, false, + NULL, "d.datname", NULL, NULL, + NULL, 1)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); res = PSQLexec(buf.data); @@ -3892,9 +3939,11 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys " AND n.nspname !~ '^pg_toast'\n" " AND n.nspname <> 'information_schema'\n"); - processSQLNamePattern(pset.db, &buf, pattern, true, false, - "n.nspname", "c.relname", NULL, - "pg_catalog.pg_table_is_visible(c.oid)"); + if (!validateSQLNamePattern(&buf, pattern, true, false, + "n.nspname", "c.relname", NULL, + "pg_catalog.pg_table_is_visible(c.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1,2;"); @@ -4107,9 +4156,11 @@ listPartitionedTables(const char *reltypes, const char *pattern, bool verbose) " AND n.nspname !~ '^pg_toast'\n" " AND n.nspname <> 'information_schema'\n"); - processSQLNamePattern(pset.db, &buf, pattern, true, false, - "n.nspname", "c.relname", NULL, - "pg_catalog.pg_table_is_visible(c.oid)"); + if (!validateSQLNamePattern(&buf, pattern, true, false, + "n.nspname", "c.relname", NULL, + "pg_catalog.pg_table_is_visible(c.oid)", + NULL, 3)) + return false; appendPQExpBuffer(&buf, "ORDER BY \"Schema\", %s%s\"Name\";", mixed_output ? "\"Type\" DESC, " : "", @@ -4182,8 +4233,10 @@ listLanguages(const char *pattern, bool verbose, bool showSystem) gettext_noop("Description")); if (pattern) - processSQLNamePattern(pset.db, &buf, pattern, false, false, - NULL, "l.lanname", NULL, NULL); + if (!validateSQLNamePattern(&buf, pattern, false, false, + NULL, "l.lanname", NULL, NULL, + NULL, 2)) + return false; if (!showSystem && !pattern) appendPQExpBufferStr(&buf, "WHERE l.lanplcallfoid != 0\n"); @@ -4265,9 +4318,11 @@ listDomains(const char *pattern, bool verbose, bool showSystem) appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n" " AND n.nspname <> 'information_schema'\n"); - processSQLNamePattern(pset.db, &buf, pattern, true, false, - "n.nspname", "t.typname", NULL, - "pg_catalog.pg_type_is_visible(t.oid)"); + if (!validateSQLNamePattern(&buf, pattern, true, false, + "n.nspname", "t.typname", NULL, + "pg_catalog.pg_type_is_visible(t.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); @@ -4339,9 +4394,11 @@ listConversions(const char *pattern, bool verbose, bool showSystem) appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n" " AND n.nspname <> 'information_schema'\n"); - processSQLNamePattern(pset.db, &buf, pattern, true, false, - "n.nspname", "c.conname", NULL, - "pg_catalog.pg_conversion_is_visible(c.oid)"); + if (!validateSQLNamePattern(&buf, pattern, true, false, + "n.nspname", "c.conname", NULL, + "pg_catalog.pg_conversion_is_visible(c.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); @@ -4406,7 +4463,7 @@ describeConfigurationParameters(const char *pattern, bool verbose, processSQLNamePattern(pset.db, &buf, pattern, false, false, NULL, "pg_catalog.lower(s.name)", NULL, - NULL); + NULL, NULL, NULL); else appendPQExpBufferStr(&buf, "WHERE s.source <> 'default' AND\n" " s.setting IS DISTINCT FROM s.boot_val\n"); @@ -4485,8 +4542,10 @@ listEventTriggers(const char *pattern, bool verbose) appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_event_trigger e "); - processSQLNamePattern(pset.db, &buf, pattern, false, false, - NULL, "evtname", NULL, NULL); + if (!validateSQLNamePattern(&buf, pattern, false, false, + NULL, "evtname", NULL, NULL, + NULL, 1)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1"); @@ -4577,10 +4636,12 @@ listExtendedStats(const char *pattern) appendPQExpBufferStr(&buf, " \nFROM pg_catalog.pg_statistic_ext es \n"); - processSQLNamePattern(pset.db, &buf, pattern, - false, false, - "es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text", "es.stxname", - NULL, "pg_catalog.pg_statistics_obj_is_visible(es.oid)"); + if (!validateSQLNamePattern(&buf, pattern, + false, false, + "es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text", "es.stxname", + NULL, "pg_catalog.pg_statistics_obj_is_visible(es.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); @@ -4679,17 +4740,21 @@ listCasts(const char *pattern, bool verbose) * Match name pattern against either internal or external name of either * castsource or casttarget */ - processSQLNamePattern(pset.db, &buf, pattern, true, false, - "ns.nspname", "ts.typname", - "pg_catalog.format_type(ts.oid, NULL)", - "pg_catalog.pg_type_is_visible(ts.oid)"); + if (!validateSQLNamePattern(&buf, pattern, true, false, + "ns.nspname", "ts.typname", + "pg_catalog.format_type(ts.oid, NULL)", + "pg_catalog.pg_type_is_visible(ts.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, ") OR (true"); - processSQLNamePattern(pset.db, &buf, pattern, true, false, - "nt.nspname", "tt.typname", - "pg_catalog.format_type(tt.oid, NULL)", - "pg_catalog.pg_type_is_visible(tt.oid)"); + if (!validateSQLNamePattern(&buf, pattern, true, false, + "nt.nspname", "tt.typname", + "pg_catalog.format_type(tt.oid, NULL)", + "pg_catalog.pg_type_is_visible(tt.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, ") )\nORDER BY 1, 2;"); @@ -4785,9 +4850,11 @@ listCollations(const char *pattern, bool verbose, bool showSystem) */ appendPQExpBufferStr(&buf, " AND c.collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding()))\n"); - processSQLNamePattern(pset.db, &buf, pattern, true, false, - "n.nspname", "c.collname", NULL, - "pg_catalog.pg_collation_is_visible(c.oid)"); + if (!validateSQLNamePattern(&buf, pattern, true, false, + "n.nspname", "c.collname", NULL, + "pg_catalog.pg_collation_is_visible(c.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); @@ -4845,10 +4912,12 @@ listSchemas(const char *pattern, bool verbose, bool showSystem) appendPQExpBufferStr(&buf, "WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'\n"); - processSQLNamePattern(pset.db, &buf, pattern, - !showSystem && !pattern, false, - NULL, "n.nspname", NULL, - NULL); + if (!validateSQLNamePattern(&buf, pattern, + !showSystem && !pattern, false, + NULL, "n.nspname", NULL, + NULL, + NULL, 2)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1;"); @@ -4959,9 +5028,11 @@ listTSParsers(const char *pattern, bool verbose) gettext_noop("Description") ); - processSQLNamePattern(pset.db, &buf, pattern, false, false, - "n.nspname", "p.prsname", NULL, - "pg_catalog.pg_ts_parser_is_visible(p.oid)"); + if (!validateSQLNamePattern(&buf, pattern, false, false, + "n.nspname", "p.prsname", NULL, + "pg_catalog.pg_ts_parser_is_visible(p.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); @@ -5000,9 +5071,11 @@ listTSParsersVerbose(const char *pattern) "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n" ); - processSQLNamePattern(pset.db, &buf, pattern, false, false, - "n.nspname", "p.prsname", NULL, - "pg_catalog.pg_ts_parser_is_visible(p.oid)"); + if (!validateSQLNamePattern(&buf, pattern, false, false, + "n.nspname", "p.prsname", NULL, + "pg_catalog.pg_ts_parser_is_visible(p.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); @@ -5207,9 +5280,11 @@ listTSDictionaries(const char *pattern, bool verbose) appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_ts_dict d\n" "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace\n"); - processSQLNamePattern(pset.db, &buf, pattern, false, false, - "n.nspname", "d.dictname", NULL, - "pg_catalog.pg_ts_dict_is_visible(d.oid)"); + if (!validateSQLNamePattern(&buf, pattern, false, false, + "n.nspname", "d.dictname", NULL, + "pg_catalog.pg_ts_dict_is_visible(d.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); @@ -5268,9 +5343,11 @@ listTSTemplates(const char *pattern, bool verbose) appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_ts_template t\n" "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace\n"); - processSQLNamePattern(pset.db, &buf, pattern, false, false, - "n.nspname", "t.tmplname", NULL, - "pg_catalog.pg_ts_template_is_visible(t.oid)"); + if (!validateSQLNamePattern(&buf, pattern, false, false, + "n.nspname", "t.tmplname", NULL, + "pg_catalog.pg_ts_template_is_visible(t.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); @@ -5318,9 +5395,11 @@ listTSConfigs(const char *pattern, bool verbose) gettext_noop("Description") ); - processSQLNamePattern(pset.db, &buf, pattern, false, false, - "n.nspname", "c.cfgname", NULL, - "pg_catalog.pg_ts_config_is_visible(c.oid)"); + if (!validateSQLNamePattern(&buf, pattern, false, false, + "n.nspname", "c.cfgname", NULL, + "pg_catalog.pg_ts_config_is_visible(c.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); @@ -5360,9 +5439,11 @@ listTSConfigsVerbose(const char *pattern) "WHERE p.oid = c.cfgparser\n" ); - processSQLNamePattern(pset.db, &buf, pattern, true, false, - "n.nspname", "c.cfgname", NULL, - "pg_catalog.pg_ts_config_is_visible(c.oid)"); + if (!validateSQLNamePattern(&buf, pattern, true, false, + "n.nspname", "c.cfgname", NULL, + "pg_catalog.pg_ts_config_is_visible(c.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 3, 2;"); @@ -5532,8 +5613,10 @@ listForeignDataWrappers(const char *pattern, bool verbose) " ON d.classoid = fdw.tableoid " "AND d.objoid = fdw.oid AND d.objsubid = 0\n"); - processSQLNamePattern(pset.db, &buf, pattern, false, false, - NULL, "fdwname", NULL, NULL); + if (!validateSQLNamePattern(&buf, pattern, false, false, + NULL, "fdwname", NULL, NULL, + NULL, 1)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1;"); @@ -5604,8 +5687,10 @@ listForeignServers(const char *pattern, bool verbose) "ON d.classoid = s.tableoid AND d.objoid = s.oid " "AND d.objsubid = 0\n"); - processSQLNamePattern(pset.db, &buf, pattern, false, false, - NULL, "s.srvname", NULL, NULL); + if (!validateSQLNamePattern(&buf, pattern, false, false, + NULL, "s.srvname", NULL, NULL, + NULL, 1)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1;"); @@ -5655,8 +5740,10 @@ listUserMappings(const char *pattern, bool verbose) appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_user_mappings um\n"); - processSQLNamePattern(pset.db, &buf, pattern, false, false, - NULL, "um.srvname", "um.usename", NULL); + if (!validateSQLNamePattern(&buf, pattern, false, false, + NULL, "um.srvname", "um.usename", NULL, + NULL, 1)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); @@ -5722,9 +5809,11 @@ listForeignTables(const char *pattern, bool verbose) " ON d.classoid = c.tableoid AND " "d.objoid = c.oid AND d.objsubid = 0\n"); - processSQLNamePattern(pset.db, &buf, pattern, false, false, - "n.nspname", "c.relname", NULL, - "pg_catalog.pg_table_is_visible(c.oid)"); + if (!validateSQLNamePattern(&buf, pattern, false, false, + "n.nspname", "c.relname", NULL, + "pg_catalog.pg_table_is_visible(c.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); @@ -5768,10 +5857,12 @@ listExtensions(const char *pattern) gettext_noop("Schema"), gettext_noop("Description")); - processSQLNamePattern(pset.db, &buf, pattern, - false, false, - NULL, "e.extname", NULL, - NULL); + if (!validateSQLNamePattern(&buf, pattern, + false, false, + NULL, "e.extname", NULL, + NULL, + NULL, 1)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1;"); @@ -5807,10 +5898,12 @@ listExtensionContents(const char *pattern) "SELECT e.extname, e.oid\n" "FROM pg_catalog.pg_extension e\n"); - processSQLNamePattern(pset.db, &buf, pattern, - false, false, - NULL, "e.extname", NULL, - NULL); + if (!validateSQLNamePattern(&buf, pattern, + false, false, + NULL, "e.extname", NULL, + NULL, + NULL, 1)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1;"); @@ -5893,6 +5986,59 @@ listOneExtensionContents(const char *extname, const char *oid) } /* + * validateSQLNamePattern + * + * Wrapper around string_utils's processSQLNamePattern which also checks the + * pattern's validity. In addition to that function's parameters, takes a + * 'maxparts' parameter specifying the maximum number of dotted names the + * pattern is allowed to have, and a 'added_clause' parameter that returns by + * reference whether a clause was added to 'buf'. Returns whether the pattern + * passed validation, after logging any errors. + */ +static bool +validateSQLNamePattern(PQExpBuffer buf, const char *pattern, bool have_where, + bool force_escape, const char *schemavar, + const char *namevar, const char *altnamevar, + const char *visibilityrule, bool *added_clause, + int maxparts) +{ + PQExpBufferData dbbuf; + int dotcnt; + bool added; + + initPQExpBuffer(&dbbuf); + added = processSQLNamePattern(pset.db, buf, pattern, have_where, force_escape, + schemavar, namevar, altnamevar, + visibilityrule, &dbbuf, &dotcnt); + if (added_clause != NULL) + *added_clause = added; + + if (dotcnt >= maxparts) + { + pg_log_error("improper qualified name (too many dotted names): %s", + pattern); + termPQExpBuffer(&dbbuf); + return false; + } + + if (maxparts > 1 && dotcnt == maxparts-1) + { + if (PQdb(pset.db) == NULL) + { + pg_log_error("You are currently not connected to a database."); + return false; + } + if (strcmp(PQdb(pset.db), dbbuf.data) != 0) + { + pg_log_error("cross-database references are not implemented: %s", + pattern); + return false; + } + } + return true; +} + +/* * \dRp * Lists publications. * @@ -5943,9 +6089,11 @@ listPublications(const char *pattern) appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_publication\n"); - processSQLNamePattern(pset.db, &buf, pattern, false, false, - NULL, "pubname", NULL, - NULL); + if (!validateSQLNamePattern(&buf, pattern, false, false, + NULL, "pubname", NULL, + NULL, + NULL, 1)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1;"); @@ -6056,9 +6204,11 @@ describePublications(const char *pattern) appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_publication\n"); - processSQLNamePattern(pset.db, &buf, pattern, false, false, - NULL, "pubname", NULL, - NULL); + if (!validateSQLNamePattern(&buf, pattern, false, false, + NULL, "pubname", NULL, + NULL, + NULL, 1)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 2;"); @@ -6266,9 +6416,11 @@ describeSubscriptions(const char *pattern, bool verbose) " FROM pg_catalog.pg_database\n" " WHERE datname = pg_catalog.current_database())"); - processSQLNamePattern(pset.db, &buf, pattern, true, false, - NULL, "subname", NULL, - NULL); + if (!validateSQLNamePattern(&buf, pattern, true, false, + NULL, "subname", NULL, + NULL, + NULL, 1)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1;"); @@ -6369,15 +6521,19 @@ listOperatorClasses(const char *access_method_pattern, " LEFT JOIN pg_catalog.pg_namespace ofn ON ofn.oid = of.opfnamespace\n"); if (access_method_pattern) - have_where = processSQLNamePattern(pset.db, &buf, access_method_pattern, - false, false, NULL, "am.amname", NULL, NULL); + if (!validateSQLNamePattern(&buf, access_method_pattern, + false, false, NULL, "am.amname", NULL, NULL, + &have_where, 1)) + return false; if (type_pattern) { /* Match type name pattern against either internal or external name */ - processSQLNamePattern(pset.db, &buf, type_pattern, have_where, false, - "tn.nspname", "t.typname", - "pg_catalog.format_type(t.oid, NULL)", - "pg_catalog.pg_type_is_visible(t.oid)"); + if (!validateSQLNamePattern(&buf, type_pattern, have_where, false, + "tn.nspname", "t.typname", + "pg_catalog.format_type(t.oid, NULL)", + "pg_catalog.pg_type_is_visible(t.oid)", + NULL, 3)) + return false; } appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;"); @@ -6441,8 +6597,10 @@ listOperatorFamilies(const char *access_method_pattern, " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = f.opfnamespace\n"); if (access_method_pattern) - have_where = processSQLNamePattern(pset.db, &buf, access_method_pattern, - false, false, NULL, "am.amname", NULL, NULL); + if (!validateSQLNamePattern(&buf, access_method_pattern, + false, false, NULL, "am.amname", NULL, NULL, + &have_where, 1)) + return false; if (type_pattern) { appendPQExpBuffer(&buf, @@ -6454,10 +6612,12 @@ listOperatorFamilies(const char *access_method_pattern, " WHERE oc.opcfamily = f.oid\n", have_where ? "AND" : "WHERE"); /* Match type name pattern against either internal or external name */ - processSQLNamePattern(pset.db, &buf, type_pattern, true, false, - "tn.nspname", "t.typname", - "pg_catalog.format_type(t.oid, NULL)", - "pg_catalog.pg_type_is_visible(t.oid)"); + if (!validateSQLNamePattern(&buf, type_pattern, true, false, + "tn.nspname", "t.typname", + "pg_catalog.format_type(t.oid, NULL)", + "pg_catalog.pg_type_is_visible(t.oid)", + NULL, 3)) + return false; appendPQExpBufferStr(&buf, " )\n"); } @@ -6535,13 +6695,17 @@ listOpFamilyOperators(const char *access_method_pattern, " LEFT JOIN pg_catalog.pg_opfamily ofs ON ofs.oid = o.amopsortfamily\n"); if (access_method_pattern) - have_where = processSQLNamePattern(pset.db, &buf, access_method_pattern, - false, false, NULL, "am.amname", - NULL, NULL); + if (!validateSQLNamePattern(&buf, access_method_pattern, + false, false, NULL, "am.amname", + NULL, NULL, + &have_where, 1)) + return false; if (family_pattern) - processSQLNamePattern(pset.db, &buf, family_pattern, have_where, false, - "nsf.nspname", "of.opfname", NULL, NULL); + if (!validateSQLNamePattern(&buf, family_pattern, have_where, false, + "nsf.nspname", "of.opfname", NULL, NULL, + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2,\n" " o.amoplefttype = o.amoprighttype DESC,\n" @@ -6619,12 +6783,16 @@ listOpFamilyFunctions(const char *access_method_pattern, " LEFT JOIN pg_catalog.pg_proc p ON ap.amproc = p.oid\n"); if (access_method_pattern) - have_where = processSQLNamePattern(pset.db, &buf, access_method_pattern, - false, false, NULL, "am.amname", - NULL, NULL); + if (!validateSQLNamePattern(&buf, access_method_pattern, + false, false, NULL, "am.amname", + NULL, NULL, + &have_where, 1)) + return false; if (family_pattern) - processSQLNamePattern(pset.db, &buf, family_pattern, have_where, false, - "ns.nspname", "of.opfname", NULL, NULL); + if (!validateSQLNamePattern(&buf, family_pattern, have_where, false, + "ns.nspname", "of.opfname", NULL, NULL, + NULL, 3)) + return false; appendPQExpBufferStr(&buf, "ORDER BY 1, 2,\n" " ap.amproclefttype = ap.amprocrighttype DESC,\n" diff --git a/src/fe_utils/string_utils.c b/src/fe_utils/string_utils.c index 1c618404627..c3ea4fc1860 100644 --- a/src/fe_utils/string_utils.c +++ b/src/fe_utils/string_utils.c @@ -882,6 +882,9 @@ appendReloptionsArray(PQExpBuffer buffer, const char *reloptions, * altnamevar: NULL, or name of an alternative variable to match against name. * visibilityrule: clause to use if we want to restrict to visible objects * (for example, "pg_catalog.pg_table_is_visible(p.oid)"). Can be NULL. + * dbnamebuf: output parameter receiving the database name portion of the + * pattern, if any. Can be NULL. + * dotcnt: how many separators were parsed from the pattern, by reference. * * Formatting note: the text already present in buf should end with a newline. * The appended text, if any, will end with one too. @@ -890,16 +893,21 @@ 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, + PQExpBuffer dbnamebuf, int *dotcnt) { PQExpBufferData schemabuf; PQExpBufferData namebuf; bool added_clause = false; + int dcnt; #define WHEREAND() \ (appendPQExpBufferStr(buf, have_where ? " AND " : "WHERE "), \ have_where = true, added_clause = true) + if (dotcnt == NULL) + dotcnt = &dcnt; + *dotcnt = 0; if (pattern == NULL) { /* Default: select all visible objects */ @@ -922,9 +930,11 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, * If the caller provided a schemavar, we want to split the pattern on * ".", otherwise not. */ - patternToSQLRegex(PQclientEncoding(conn), NULL, - (schemavar ? &schemabuf : NULL), &namebuf, - pattern, force_escape); + patternToSQLRegex(PQclientEncoding(conn), + (schemavar ? dbnamebuf : NULL), + (schemavar ? &schemabuf : NULL), + &namebuf, + pattern, force_escape, true, dotcnt); /* * Now decide what we need to emit. We may run under a hostile @@ -937,7 +947,7 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, * is >= v12 then we need to force it through explicit COLLATE clauses, * otherwise the "C" collation attached to "name" catalog columns wins. */ - if (namebuf.len > 2) + if (namevar && namebuf.len > 2) { /* We have a name pattern, so constrain the namevar(s) */ @@ -971,7 +981,7 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, } } - if (schemabuf.len > 2) + if (schemavar && schemabuf.len > 2) { /* We have a schema pattern, so constrain the schemavar */ @@ -1012,8 +1022,7 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, * If the dbnamebuf and schemabuf arguments are non-NULL, and the pattern * contains two or more dbname/schema/name separators, we parse the portions of * the pattern prior to the first and second separators into dbnamebuf and - * schemabuf, and the rest into namebuf. (Additional dots in the name portion - * are not treated as special.) + * schemabuf, and the rest into namebuf. * * If dbnamebuf is NULL and schemabuf is non-NULL, and the pattern contains at * least one separator, we parse the first portion into schemabuf and the rest @@ -1021,24 +1030,49 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, * * Otherwise, we parse all the pattern into namebuf. * + * If the pattern contains more dotted parts than buffers to parse into, the + * extra dots will be treated as literal characters and written into the + * namebuf, though they will be counted. Callers should always check the value + * returned by reference in dotcnt and handle this error case appropriately. + * * We surround the regexps with "^(...)$" to force them to match whole strings, * as per SQL practice. We have to have parens in case strings contain "|", * else the "^" and "$" will be bound into the first and last alternatives - * which is not what we want. + * which is not what we want. Whether this is done for dbnamebuf is controlled + * by the want_literal_dbname parameter. * * The regexps we parse into the buffers are appended to the data (if any) * already present. If we parse fewer fields than the number of buffers we * were given, the extra buffers are unaltered. + * + * encoding: the character encoding for the given pattern + * dbnamebuf: output parameter receiving the database name portion of the + * pattern, if any. Can be NULL. + * schemabuf: output parameter receiving the schema name portion of the + * pattern, if any. Can be NULL. + * namebuf: output parameter receiving the database name portion of the + * pattern, if any. Can be NULL. + * pattern: user-specified pattern option, or NULL if none ("*" is implied). + * force_escape: always quote regexp special characters, even outside + * double quotes (else they are quoted only between double quotes). + * want_literal_dbname: if true, regexp special characters within the database + * name portion of the pattern will not be escaped, nor will the dbname be + * converted into a regular expression. + * dotcnt: output parameter receiving the number of separators parsed from the + * pattern. */ void patternToSQLRegex(int encoding, PQExpBuffer dbnamebuf, PQExpBuffer schemabuf, - PQExpBuffer namebuf, const char *pattern, bool force_escape) + PQExpBuffer namebuf, const char *pattern, bool force_escape, + bool want_literal_dbname, int *dotcnt) { PQExpBufferData buf[3]; + PQExpBufferData left_literal; PQExpBuffer curbuf; PQExpBuffer maxbuf; int i; bool inquotes; + bool left; const char *cp; Assert(pattern != NULL); @@ -1046,7 +1080,9 @@ patternToSQLRegex(int encoding, PQExpBuffer dbnamebuf, PQExpBuffer schemabuf, /* callers should never expect "dbname.relname" format */ Assert(dbnamebuf == NULL || schemabuf != NULL); + Assert(dotcnt != NULL); + *dotcnt = 0; inquotes = false; cp = pattern; @@ -1058,6 +1094,13 @@ patternToSQLRegex(int encoding, PQExpBuffer dbnamebuf, PQExpBuffer schemabuf, maxbuf = &buf[0]; curbuf = &buf[0]; + if (want_literal_dbname) + { + left = true; + initPQExpBuffer(&left_literal); + } + else + left = false; initPQExpBuffer(curbuf); appendPQExpBufferStr(curbuf, "^("); while (*cp) @@ -1070,6 +1113,8 @@ patternToSQLRegex(int encoding, PQExpBuffer dbnamebuf, PQExpBuffer schemabuf, { /* emit one quote, stay in inquotes mode */ appendPQExpBufferChar(curbuf, '"'); + if (left) + appendPQExpBufferChar(&left_literal, '"'); cp++; } else @@ -1080,32 +1125,40 @@ patternToSQLRegex(int encoding, PQExpBuffer dbnamebuf, PQExpBuffer schemabuf, { appendPQExpBufferChar(curbuf, pg_tolower((unsigned char) ch)); + if (left) + appendPQExpBufferChar(&left_literal, + pg_tolower((unsigned char) ch)); cp++; } else if (!inquotes && ch == '*') { appendPQExpBufferStr(curbuf, ".*"); + if (left) + appendPQExpBufferChar(&left_literal, '*'); cp++; } else if (!inquotes && ch == '?') { appendPQExpBufferChar(curbuf, '.'); + if (left) + appendPQExpBufferChar(&left_literal, '?'); cp++; } - - /* - * When we find a dbname/schema/name separator, we treat it specially - * only if the caller requested more patterns to be parsed than we - * have already parsed from the pattern. Otherwise, dot characters - * are not special. - */ - else if (!inquotes && ch == '.' && curbuf < maxbuf) + else if (!inquotes && ch == '.') { - appendPQExpBufferStr(curbuf, ")$"); - curbuf++; - initPQExpBuffer(curbuf); - appendPQExpBufferStr(curbuf, "^("); - cp++; + left = false; + if (dotcnt) + (*dotcnt)++; + if (curbuf < maxbuf) + { + appendPQExpBufferStr(curbuf, ")$"); + curbuf++; + initPQExpBuffer(curbuf); + appendPQExpBufferStr(curbuf, "^("); + cp++; + } + else + appendPQExpBufferChar(curbuf, *cp++); } else if (ch == '$') { @@ -1117,6 +1170,8 @@ patternToSQLRegex(int encoding, PQExpBuffer dbnamebuf, PQExpBuffer schemabuf, * having it possess its regexp meaning. */ appendPQExpBufferStr(curbuf, "\\$"); + if (left) + appendPQExpBufferChar(&left_literal, '$'); cp++; } else @@ -1141,25 +1196,35 @@ patternToSQLRegex(int encoding, PQExpBuffer dbnamebuf, PQExpBuffer schemabuf, appendPQExpBufferChar(curbuf, '\\'); i = PQmblenBounded(cp, encoding); while (i--) + { + if (left) + appendPQExpBufferChar(&left_literal, *cp); appendPQExpBufferChar(curbuf, *cp++); + } } } appendPQExpBufferStr(curbuf, ")$"); - appendPQExpBufferStr(namebuf, curbuf->data); - termPQExpBuffer(curbuf); - - if (curbuf > buf) + if (namebuf) { + appendPQExpBufferStr(namebuf, curbuf->data); + termPQExpBuffer(curbuf); curbuf--; + } + + if (schemabuf && curbuf >= buf) + { appendPQExpBufferStr(schemabuf, curbuf->data); termPQExpBuffer(curbuf); + curbuf--; + } - if (curbuf > buf) - { - curbuf--; + if (dbnamebuf && curbuf >= buf) + { + if (want_literal_dbname) + appendPQExpBufferStr(dbnamebuf, left_literal.data); + else appendPQExpBufferStr(dbnamebuf, curbuf->data); - termPQExpBuffer(curbuf); - } + termPQExpBuffer(curbuf); } } diff --git a/src/include/fe_utils/string_utils.h b/src/include/fe_utils/string_utils.h index b9b8708dab7..fa4deb24978 100644 --- a/src/include/fe_utils/string_utils.h +++ b/src/include/fe_utils/string_utils.h @@ -55,10 +55,12 @@ 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, + PQExpBuffer dbnamebuf, int *dotcnt); extern void patternToSQLRegex(int encoding, PQExpBuffer dbnamebuf, PQExpBuffer schemabuf, PQExpBuffer namebuf, - const char *pattern, bool force_escape); + const char *pattern, bool force_escape, + bool want_literal_dbname, int *dotcnt); #endif /* STRING_UTILS_H */ diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out index 8e11ebbcaa4..1c5b5d2763d 100644 --- a/src/test/regress/expected/psql.out +++ b/src/test/regress/expected/psql.out @@ -5549,3 +5549,807 @@ SELECT * FROM bla ORDER BY 1; # final ON_ERROR_ROLLBACK: off DROP TABLE bla; DROP FUNCTION psql_error; +-- check describing invalid multipart names +\dA regression.heap +improper qualified name (too many dotted names): regression.heap +\dA nonesuch.heap +improper qualified name (too many dotted names): nonesuch.heap +\dt host.regression.pg_catalog.pg_class +improper qualified name (too many dotted names): host.regression.pg_catalog.pg_class +\dt |.pg_catalog.pg_class +cross-database references are not implemented: |.pg_catalog.pg_class +\dt nonesuch.pg_catalog.pg_class +cross-database references are not implemented: nonesuch.pg_catalog.pg_class +\da host.regression.pg_catalog.sum +improper qualified name (too many dotted names): host.regression.pg_catalog.sum +\da +.pg_catalog.sum +cross-database references are not implemented: +.pg_catalog.sum +\da nonesuch.pg_catalog.sum +cross-database references are not implemented: nonesuch.pg_catalog.sum +\dAc nonesuch.brin +improper qualified name (too many dotted names): nonesuch.brin +\dAc regression.brin +improper qualified name (too many dotted names): regression.brin +\dAf nonesuch.brin +improper qualified name (too many dotted names): nonesuch.brin +\dAf regression.brin +improper qualified name (too many dotted names): regression.brin +\dAo nonesuch.brin +improper qualified name (too many dotted names): nonesuch.brin +\dAo regression.brin +improper qualified name (too many dotted names): regression.brin +\dAp nonesuch.brin +improper qualified name (too many dotted names): nonesuch.brin +\dAp regression.brin +improper qualified name (too many dotted names): regression.brin +\db nonesuch.pg_default +improper qualified name (too many dotted names): nonesuch.pg_default +\db regression.pg_default +improper qualified name (too many dotted names): regression.pg_default +\dc host.regression.public.conversion +improper qualified name (too many dotted names): host.regression.public.conversion +\dc (.public.conversion +cross-database references are not implemented: (.public.conversion +\dc nonesuch.public.conversion +cross-database references are not implemented: nonesuch.public.conversion +\dC host.regression.pg_catalog.int8 +improper qualified name (too many dotted names): host.regression.pg_catalog.int8 +\dC ).pg_catalog.int8 +cross-database references are not implemented: ).pg_catalog.int8 +\dC nonesuch.pg_catalog.int8 +cross-database references are not implemented: nonesuch.pg_catalog.int8 +\dd host.regression.pg_catalog.pg_class +improper qualified name (too many dotted names): host.regression.pg_catalog.pg_class +\dd [.pg_catalog.pg_class +cross-database references are not implemented: [.pg_catalog.pg_class +\dd nonesuch.pg_catalog.pg_class +cross-database references are not implemented: nonesuch.pg_catalog.pg_class +\dD host.regression.public.gtestdomain1 +improper qualified name (too many dotted names): host.regression.public.gtestdomain1 +\dD ].public.gtestdomain1 +cross-database references are not implemented: ].public.gtestdomain1 +\dD nonesuch.public.gtestdomain1 +cross-database references are not implemented: nonesuch.public.gtestdomain1 +\ddp host.regression.pg_catalog.pg_class +improper qualified name (too many dotted names): host.regression.pg_catalog.pg_class +\ddp {.pg_catalog.pg_class +cross-database references are not implemented: {.pg_catalog.pg_class +\ddp nonesuch.pg_catalog.pg_class +cross-database references are not implemented: nonesuch.pg_catalog.pg_class +\dE host.regression.public.ft +improper qualified name (too many dotted names): host.regression.public.ft +\dE }.public.ft +cross-database references are not implemented: }.public.ft +\dE nonesuch.public.ft +cross-database references are not implemented: nonesuch.public.ft +\di host.regression.public.tenk1_hundred +improper qualified name (too many dotted names): host.regression.public.tenk1_hundred +\di ..public.tenk1_hundred +improper qualified name (too many dotted names): ..public.tenk1_hundred +\di nonesuch.public.tenk1_hundred +cross-database references are not implemented: nonesuch.public.tenk1_hundred +\dm host.regression.public.mvtest_bb +improper qualified name (too many dotted names): host.regression.public.mvtest_bb +\dm ^.public.mvtest_bb +cross-database references are not implemented: ^.public.mvtest_bb +\dm nonesuch.public.mvtest_bb +cross-database references are not implemented: nonesuch.public.mvtest_bb +\ds host.regression.public.check_seq +improper qualified name (too many dotted names): host.regression.public.check_seq +\ds regression|mydb.public.check_seq +cross-database references are not implemented: regression|mydb.public.check_seq +\ds nonesuch.public.check_seq +cross-database references are not implemented: nonesuch.public.check_seq +\dt host.regression.public.b_star +improper qualified name (too many dotted names): host.regression.public.b_star +\dt regres+ion.public.b_star +cross-database references are not implemented: regres+ion.public.b_star +\dt nonesuch.public.b_star +cross-database references are not implemented: nonesuch.public.b_star +\dv host.regression.public.shoe +improper qualified name (too many dotted names): host.regression.public.shoe +\dv regress(ion).public.shoe +cross-database references are not implemented: regress(ion).public.shoe +\dv nonesuch.public.shoe +cross-database references are not implemented: nonesuch.public.shoe +\des nonesuch.server +improper qualified name (too many dotted names): nonesuch.server +\des regression.server +improper qualified name (too many dotted names): regression.server +\des nonesuch.server +improper qualified name (too many dotted names): nonesuch.server +\des regression.server +improper qualified name (too many dotted names): regression.server +\des nonesuch.username +improper qualified name (too many dotted names): nonesuch.username +\des regression.username +improper qualified name (too many dotted names): regression.username +\dew nonesuch.fdw +improper qualified name (too many dotted names): nonesuch.fdw +\dew regression.fdw +improper qualified name (too many dotted names): regression.fdw +\df host.regression.public.namelen +improper qualified name (too many dotted names): host.regression.public.namelen +\df regres[qrstuv]ion.public.namelen +cross-database references are not implemented: regres[qrstuv]ion.public.namelen +\df nonesuch.public.namelen +cross-database references are not implemented: nonesuch.public.namelen +\dF host.regression.pg_catalog.arabic +improper qualified name (too many dotted names): host.regression.pg_catalog.arabic +\dF regres{1,2}ion.pg_catalog.arabic +cross-database references are not implemented: regres{1,2}ion.pg_catalog.arabic +\dF nonesuch.pg_catalog.arabic +cross-database references are not implemented: nonesuch.pg_catalog.arabic +\dFd host.regression.pg_catalog.arabic_stem +improper qualified name (too many dotted names): host.regression.pg_catalog.arabic_stem +\dFd regres?ion.pg_catalog.arabic_stem +cross-database references are not implemented: regres?ion.pg_catalog.arabic_stem +\dFd nonesuch.pg_catalog.arabic_stem +cross-database references are not implemented: nonesuch.pg_catalog.arabic_stem +\dFp host.regression.pg_catalog.default +improper qualified name (too many dotted names): host.regression.pg_catalog.default +\dFp ^regression.pg_catalog.default +cross-database references are not implemented: ^regression.pg_catalog.default +\dFp nonesuch.pg_catalog.default +cross-database references are not implemented: nonesuch.pg_catalog.default +\dFt host.regression.pg_catalog.ispell +improper qualified name (too many dotted names): host.regression.pg_catalog.ispell +\dFt regression$.pg_catalog.ispell +cross-database references are not implemented: regression$.pg_catalog.ispell +\dFt nonesuch.pg_catalog.ispell +cross-database references are not implemented: nonesuch.pg_catalog.ispell +\dg nonesuch.pg_database_owner +improper qualified name (too many dotted names): nonesuch.pg_database_owner +\dg regression.pg_database_owner +improper qualified name (too many dotted names): regression.pg_database_owner +\dL host.regression.plpgsql +improper qualified name (too many dotted names): host.regression.plpgsql +\dL *.plpgsql +cross-database references are not implemented: *.plpgsql +\dL nonesuch.plpgsql +cross-database references are not implemented: nonesuch.plpgsql +\dn host.regression.public +improper qualified name (too many dotted names): host.regression.public +\dn """".public +cross-database references are not implemented: """".public +\dn nonesuch.public +cross-database references are not implemented: nonesuch.public +\do host.regression.public.!=- +improper qualified name (too many dotted names): host.regression.public.!=- +\do "regression|mydb".public.!=- +cross-database references are not implemented: "regression|mydb".public.!=- +\do nonesuch.public.!=- +cross-database references are not implemented: nonesuch.public.!=- +\dO host.regression.pg_catalog.POSIX +improper qualified name (too many dotted names): host.regression.pg_catalog.POSIX +\dO .pg_catalog.POSIX +cross-database references are not implemented: .pg_catalog.POSIX +\dO nonesuch.pg_catalog.POSIX +cross-database references are not implemented: nonesuch.pg_catalog.POSIX +\dp host.regression.public.a_star +improper qualified name (too many dotted names): host.regression.public.a_star +\dp "regres+ion".public.a_star +cross-database references are not implemented: "regres+ion".public.a_star +\dp nonesuch.public.a_star +cross-database references are not implemented: nonesuch.public.a_star +\dP host.regression.public.mlparted +improper qualified name (too many dotted names): host.regression.public.mlparted +\dP "regres(sion)".public.mlparted +cross-database references are not implemented: "regres(sion)".public.mlparted +\dP nonesuch.public.mlparted +cross-database references are not implemented: nonesuch.public.mlparted +\drds nonesuch.lc_messages +improper qualified name (too many dotted names): nonesuch.lc_messages +\drds regression.lc_messages +improper qualified name (too many dotted names): regression.lc_messages +\dRp public.mypub +improper qualified name (too many dotted names): public.mypub +\dRp regression.mypub +improper qualified name (too many dotted names): regression.mypub +\dRs public.mysub +improper qualified name (too many dotted names): public.mysub +\dRs regression.mysub +improper qualified name (too many dotted names): regression.mysub +\dT host.regression.public.widget +improper qualified name (too many dotted names): host.regression.public.widget +\dT "regression{1,2}".public.widget +cross-database references are not implemented: "regression{1,2}".public.widget +\dT nonesuch.public.widget +cross-database references are not implemented: nonesuch.public.widget +\dx regression.plpgsql +improper qualified name (too many dotted names): regression.plpgsql +\dx nonesuch.plpgsql +improper qualified name (too many dotted names): nonesuch.plpgsql +\dX host.regression.public.func_deps_stat +improper qualified name (too many dotted names): host.regression.public.func_deps_stat +\dX "^regression$".public.func_deps_stat +cross-database references are not implemented: "^regression$".public.func_deps_stat +\dX nonesuch.public.func_deps_stat +cross-database references are not implemented: nonesuch.public.func_deps_stat +\dy regression.myevt +improper qualified name (too many dotted names): regression.myevt +\dy nonesuch.myevt +improper qualified name (too many dotted names): nonesuch.myevt +-- check that dots within quoted name segments are not counted +\dA "no.such.access.method" +List of access methods + Name | Type +------+------ +(0 rows) + +\dt "no.such.table.relation" + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\da "no.such.aggregate.function" + List of aggregate functions + Schema | Name | Result data type | Argument data types | Description +--------+------+------------------+---------------------+------------- +(0 rows) + +\dAc "no.such.operator.class" + List of operator classes + AM | Input type | Storage type | Operator class | Default? +----+------------+--------------+----------------+---------- +(0 rows) + +\dAf "no.such.operator.family" + List of operator families + AM | Operator family | Applicable types +----+-----------------+------------------ +(0 rows) + +\dAo "no.such.operator.of.operator.family" + List of operators of operator families + AM | Operator family | Operator | Strategy | Purpose +----+-----------------+----------+----------+--------- +(0 rows) + +\dAp "no.such.operator.support.function.of.operator.family" + List of support functions of operator families + AM | Operator family | Registered left type | Registered right type | Number | Function +----+-----------------+----------------------+-----------------------+--------+---------- +(0 rows) + +\db "no.such.tablespace" + List of tablespaces + Name | Owner | Location +------+-------+---------- +(0 rows) + +\dc "no.such.conversion" + List of conversions + Schema | Name | Source | Destination | Default? +--------+------+--------+-------------+---------- +(0 rows) + +\dC "no.such.cast" + List of casts + Source type | Target type | Function | Implicit? +-------------+-------------+----------+----------- +(0 rows) + +\dd "no.such.object.description" + Object descriptions + Schema | Name | Object | Description +--------+------+--------+------------- +(0 rows) + +\dD "no.such.domain" + List of domains + Schema | Name | Type | Collation | Nullable | Default | Check +--------+------+------+-----------+----------+---------+------- +(0 rows) + +\ddp "no.such.default.access.privilege" + Default access privileges + Owner | Schema | Type | Access privileges +-------+--------+------+------------------- +(0 rows) + +\di "no.such.index.relation" + List of relations + Schema | Name | Type | Owner | Table +--------+------+------+-------+------- +(0 rows) + +\dm "no.such.materialized.view" + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\ds "no.such.relation" + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\dt "no.such.relation" + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\dv "no.such.relation" + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\des "no.such.foreign.server" + List of foreign servers + Name | Owner | Foreign-data wrapper +------+-------+---------------------- +(0 rows) + +\dew "no.such.foreign.data.wrapper" + List of foreign-data wrappers + Name | Owner | Handler | Validator +------+-------+---------+----------- +(0 rows) + +\df "no.such.function" + List of functions + Schema | Name | Result data type | Argument data types | Type +--------+------+------------------+---------------------+------ +(0 rows) + +\dF "no.such.text.search.configuration" +List of text search configurations + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFd "no.such.text.search.dictionary" +List of text search dictionaries + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFp "no.such.text.search.parser" + List of text search parsers + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFt "no.such.text.search.template" +List of text search templates + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dg "no.such.role" + List of roles + Role name | Attributes | Member of +-----------+------------+----------- + +\dL "no.such.language" + List of languages + Name | Owner | Trusted | Description +------+-------+---------+------------- +(0 rows) + +\dn "no.such.schema" +List of schemas + Name | Owner +------+------- +(0 rows) + +\do "no.such.operator" + List of operators + Schema | Name | Left arg type | Right arg type | Result type | Description +--------+------+---------------+----------------+-------------+------------- +(0 rows) + +\dO "no.such.collation" + List of collations + Schema | Name | Collate | Ctype | ICU Locale | Provider | Deterministic? +--------+------+---------+-------+------------+----------+---------------- +(0 rows) + +\dp "no.such.access.privilege" + Access privileges + Schema | Name | Type | Access privileges | Column privileges | Policies +--------+------+------+-------------------+-------------------+---------- +(0 rows) + +\dP "no.such.partitioned.relation" + List of partitioned relations + Schema | Name | Owner | Type | Parent name | Table +--------+------+-------+------+-------------+------- +(0 rows) + +\drds "no.such.setting" + List of settings + Role | Database | Settings +------+----------+---------- +(0 rows) + +\dRp "no.such.publication" + List of publications + Name | Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root +------+-------+------------+---------+---------+---------+-----------+---------- +(0 rows) + +\dRs "no.such.subscription" + List of subscriptions + Name | Owner | Enabled | Publication +------+-------+---------+------------- +(0 rows) + +\dT "no.such.data.type" + List of data types + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dx "no.such.installed.extension" + List of installed extensions + Name | Version | Schema | Description +------+---------+--------+------------- +(0 rows) + +\dX "no.such.extended.statistics" + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV +--------+------+------------+-----------+--------------+----- +(0 rows) + +\dy "no.such.event.trigger" + List of event triggers + Name | Event | Owner | Enabled | Function | Tags +------+-------+-------+---------+----------+------ +(0 rows) + +-- again, but with dotted schema qualifications. +\dA "no.such.schema"."no.such.access.method" +improper qualified name (too many dotted names): "no.such.schema"."no.such.access.method" +\dt "no.such.schema"."no.such.table.relation" + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\da "no.such.schema"."no.such.aggregate.function" + List of aggregate functions + Schema | Name | Result data type | Argument data types | Description +--------+------+------------------+---------------------+------------- +(0 rows) + +\dAc "no.such.schema"."no.such.operator.class" +improper qualified name (too many dotted names): "no.such.schema"."no.such.operator.class" +\dAf "no.such.schema"."no.such.operator.family" +improper qualified name (too many dotted names): "no.such.schema"."no.such.operator.family" +\dAo "no.such.schema"."no.such.operator.of.operator.family" +improper qualified name (too many dotted names): "no.such.schema"."no.such.operator.of.operator.family" +\dAp "no.such.schema"."no.such.operator.support.function.of.operator.family" +improper qualified name (too many dotted names): "no.such.schema"."no.such.operator.support.function.of.operator.family" +\db "no.such.schema"."no.such.tablespace" +improper qualified name (too many dotted names): "no.such.schema"."no.such.tablespace" +\dc "no.such.schema"."no.such.conversion" + List of conversions + Schema | Name | Source | Destination | Default? +--------+------+--------+-------------+---------- +(0 rows) + +\dC "no.such.schema"."no.such.cast" + List of casts + Source type | Target type | Function | Implicit? +-------------+-------------+----------+----------- +(0 rows) + +\dd "no.such.schema"."no.such.object.description" + Object descriptions + Schema | Name | Object | Description +--------+------+--------+------------- +(0 rows) + +\dD "no.such.schema"."no.such.domain" + List of domains + Schema | Name | Type | Collation | Nullable | Default | Check +--------+------+------+-----------+----------+---------+------- +(0 rows) + +\ddp "no.such.schema"."no.such.default.access.privilege" + Default access privileges + Owner | Schema | Type | Access privileges +-------+--------+------+------------------- +(0 rows) + +\di "no.such.schema"."no.such.index.relation" + List of relations + Schema | Name | Type | Owner | Table +--------+------+------+-------+------- +(0 rows) + +\dm "no.such.schema"."no.such.materialized.view" + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\ds "no.such.schema"."no.such.relation" + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\dt "no.such.schema"."no.such.relation" + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\dv "no.such.schema"."no.such.relation" + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\des "no.such.schema"."no.such.foreign.server" +improper qualified name (too many dotted names): "no.such.schema"."no.such.foreign.server" +\dew "no.such.schema"."no.such.foreign.data.wrapper" +improper qualified name (too many dotted names): "no.such.schema"."no.such.foreign.data.wrapper" +\df "no.such.schema"."no.such.function" + List of functions + Schema | Name | Result data type | Argument data types | Type +--------+------+------------------+---------------------+------ +(0 rows) + +\dF "no.such.schema"."no.such.text.search.configuration" +List of text search configurations + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFd "no.such.schema"."no.such.text.search.dictionary" +List of text search dictionaries + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFp "no.such.schema"."no.such.text.search.parser" + List of text search parsers + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFt "no.such.schema"."no.such.text.search.template" +List of text search templates + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dg "no.such.schema"."no.such.role" +improper qualified name (too many dotted names): "no.such.schema"."no.such.role" +\dL "no.such.schema"."no.such.language" +cross-database references are not implemented: "no.such.schema"."no.such.language" +\do "no.such.schema"."no.such.operator" + List of operators + Schema | Name | Left arg type | Right arg type | Result type | Description +--------+------+---------------+----------------+-------------+------------- +(0 rows) + +\dO "no.such.schema"."no.such.collation" + List of collations + Schema | Name | Collate | Ctype | ICU Locale | Provider | Deterministic? +--------+------+---------+-------+------------+----------+---------------- +(0 rows) + +\dp "no.such.schema"."no.such.access.privilege" + Access privileges + Schema | Name | Type | Access privileges | Column privileges | Policies +--------+------+------+-------------------+-------------------+---------- +(0 rows) + +\dP "no.such.schema"."no.such.partitioned.relation" + List of partitioned relations + Schema | Name | Owner | Type | Parent name | Table +--------+------+-------+------+-------------+------- +(0 rows) + +\drds "no.such.schema"."no.such.setting" +improper qualified name (too many dotted names): "no.such.schema"."no.such.setting" +\dRp "no.such.schema"."no.such.publication" +improper qualified name (too many dotted names): "no.such.schema"."no.such.publication" +\dRs "no.such.schema"."no.such.subscription" +improper qualified name (too many dotted names): "no.such.schema"."no.such.subscription" +\dT "no.such.schema"."no.such.data.type" + List of data types + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dx "no.such.schema"."no.such.installed.extension" +improper qualified name (too many dotted names): "no.such.schema"."no.such.installed.extension" +\dX "no.such.schema"."no.such.extended.statistics" + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV +--------+------+------------+-----------+--------------+----- +(0 rows) + +\dy "no.such.schema"."no.such.event.trigger" +improper qualified name (too many dotted names): "no.such.schema"."no.such.event.trigger" +-- again, but with current database and dotted schema qualifications. +\dt regression."no.such.schema"."no.such.table.relation" + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\da regression."no.such.schema"."no.such.aggregate.function" + List of aggregate functions + Schema | Name | Result data type | Argument data types | Description +--------+------+------------------+---------------------+------------- +(0 rows) + +\dc regression."no.such.schema"."no.such.conversion" + List of conversions + Schema | Name | Source | Destination | Default? +--------+------+--------+-------------+---------- +(0 rows) + +\dC regression."no.such.schema"."no.such.cast" + List of casts + Source type | Target type | Function | Implicit? +-------------+-------------+----------+----------- +(0 rows) + +\dd regression."no.such.schema"."no.such.object.description" + Object descriptions + Schema | Name | Object | Description +--------+------+--------+------------- +(0 rows) + +\dD regression."no.such.schema"."no.such.domain" + List of domains + Schema | Name | Type | Collation | Nullable | Default | Check +--------+------+------+-----------+----------+---------+------- +(0 rows) + +\di regression."no.such.schema"."no.such.index.relation" + List of relations + Schema | Name | Type | Owner | Table +--------+------+------+-------+------- +(0 rows) + +\dm regression."no.such.schema"."no.such.materialized.view" + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\ds regression."no.such.schema"."no.such.relation" + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\dt regression."no.such.schema"."no.such.relation" + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\dv regression."no.such.schema"."no.such.relation" + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +\df regression."no.such.schema"."no.such.function" + List of functions + Schema | Name | Result data type | Argument data types | Type +--------+------+------------------+---------------------+------ +(0 rows) + +\dF regression."no.such.schema"."no.such.text.search.configuration" +List of text search configurations + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFd regression."no.such.schema"."no.such.text.search.dictionary" +List of text search dictionaries + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFp regression."no.such.schema"."no.such.text.search.parser" + List of text search parsers + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dFt regression."no.such.schema"."no.such.text.search.template" +List of text search templates + Schema | Name | Description +--------+------+------------- +(0 rows) + +\do regression."no.such.schema"."no.such.operator" + List of operators + Schema | Name | Left arg type | Right arg type | Result type | Description +--------+------+---------------+----------------+-------------+------------- +(0 rows) + +\dO regression."no.such.schema"."no.such.collation" + List of collations + Schema | Name | Collate | Ctype | ICU Locale | Provider | Deterministic? +--------+------+---------+-------+------------+----------+---------------- +(0 rows) + +\dp regression."no.such.schema"."no.such.access.privilege" + Access privileges + Schema | Name | Type | Access privileges | Column privileges | Policies +--------+------+------+-------------------+-------------------+---------- +(0 rows) + +\dP regression."no.such.schema"."no.such.partitioned.relation" + List of partitioned relations + Schema | Name | Owner | Type | Parent name | Table +--------+------+-------+------+-------------+------- +(0 rows) + +\dT regression."no.such.schema"."no.such.data.type" + List of data types + Schema | Name | Description +--------+------+------------- +(0 rows) + +\dX regression."no.such.schema"."no.such.extended.statistics" + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV +--------+------+------------+-----------+--------------+----- +(0 rows) + +-- again, but with dotted database and dotted schema qualifications. +\dt "no.such.database"."no.such.schema"."no.such.table.relation" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.table.relation" +\da "no.such.database"."no.such.schema"."no.such.aggregate.function" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.aggregate.function" +\dc "no.such.database"."no.such.schema"."no.such.conversion" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.conversion" +\dC "no.such.database"."no.such.schema"."no.such.cast" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.cast" +\dd "no.such.database"."no.such.schema"."no.such.object.description" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.object.description" +\dD "no.such.database"."no.such.schema"."no.such.domain" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.domain" +\ddp "no.such.database"."no.such.schema"."no.such.default.access.privilege" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.default.access.privilege" +\di "no.such.database"."no.such.schema"."no.such.index.relation" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.index.relation" +\dm "no.such.database"."no.such.schema"."no.such.materialized.view" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.materialized.view" +\ds "no.such.database"."no.such.schema"."no.such.relation" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.relation" +\dt "no.such.database"."no.such.schema"."no.such.relation" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.relation" +\dv "no.such.database"."no.such.schema"."no.such.relation" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.relation" +\df "no.such.database"."no.such.schema"."no.such.function" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.function" +\dF "no.such.database"."no.such.schema"."no.such.text.search.configuration" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.text.search.configuration" +\dFd "no.such.database"."no.such.schema"."no.such.text.search.dictionary" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.text.search.dictionary" +\dFp "no.such.database"."no.such.schema"."no.such.text.search.parser" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.text.search.parser" +\dFt "no.such.database"."no.such.schema"."no.such.text.search.template" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.text.search.template" +\do "no.such.database"."no.such.schema"."no.such.operator" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.operator" +\dO "no.such.database"."no.such.schema"."no.such.collation" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.collation" +\dp "no.such.database"."no.such.schema"."no.such.access.privilege" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.access.privilege" +\dP "no.such.database"."no.such.schema"."no.such.partitioned.relation" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.partitioned.relation" +\dT "no.such.database"."no.such.schema"."no.such.data.type" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.data.type" +\dX "no.such.database"."no.such.schema"."no.such.extended.statistics" +cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.extended.statistics" diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql index bf372c37a56..6fc0ac6bd17 100644 --- a/src/test/regress/sql/psql.sql +++ b/src/test/regress/sql/psql.sql @@ -1463,3 +1463,245 @@ SELECT * FROM bla ORDER BY 1; \echo '# final ON_ERROR_ROLLBACK:' :ON_ERROR_ROLLBACK DROP TABLE bla; DROP FUNCTION psql_error; + +-- check describing invalid multipart names +\dA regression.heap +\dA nonesuch.heap +\dt host.regression.pg_catalog.pg_class +\dt |.pg_catalog.pg_class +\dt nonesuch.pg_catalog.pg_class +\da host.regression.pg_catalog.sum +\da +.pg_catalog.sum +\da nonesuch.pg_catalog.sum +\dAc nonesuch.brin +\dAc regression.brin +\dAf nonesuch.brin +\dAf regression.brin +\dAo nonesuch.brin +\dAo regression.brin +\dAp nonesuch.brin +\dAp regression.brin +\db nonesuch.pg_default +\db regression.pg_default +\dc host.regression.public.conversion +\dc (.public.conversion +\dc nonesuch.public.conversion +\dC host.regression.pg_catalog.int8 +\dC ).pg_catalog.int8 +\dC nonesuch.pg_catalog.int8 +\dd host.regression.pg_catalog.pg_class +\dd [.pg_catalog.pg_class +\dd nonesuch.pg_catalog.pg_class +\dD host.regression.public.gtestdomain1 +\dD ].public.gtestdomain1 +\dD nonesuch.public.gtestdomain1 +\ddp host.regression.pg_catalog.pg_class +\ddp {.pg_catalog.pg_class +\ddp nonesuch.pg_catalog.pg_class +\dE host.regression.public.ft +\dE }.public.ft +\dE nonesuch.public.ft +\di host.regression.public.tenk1_hundred +\di ..public.tenk1_hundred +\di nonesuch.public.tenk1_hundred +\dm host.regression.public.mvtest_bb +\dm ^.public.mvtest_bb +\dm nonesuch.public.mvtest_bb +\ds host.regression.public.check_seq +\ds regression|mydb.public.check_seq +\ds nonesuch.public.check_seq +\dt host.regression.public.b_star +\dt regres+ion.public.b_star +\dt nonesuch.public.b_star +\dv host.regression.public.shoe +\dv regress(ion).public.shoe +\dv nonesuch.public.shoe +\des nonesuch.server +\des regression.server +\des nonesuch.server +\des regression.server +\des nonesuch.username +\des regression.username +\dew nonesuch.fdw +\dew regression.fdw +\df host.regression.public.namelen +\df regres[qrstuv]ion.public.namelen +\df nonesuch.public.namelen +\dF host.regression.pg_catalog.arabic +\dF regres{1,2}ion.pg_catalog.arabic +\dF nonesuch.pg_catalog.arabic +\dFd host.regression.pg_catalog.arabic_stem +\dFd regres?ion.pg_catalog.arabic_stem +\dFd nonesuch.pg_catalog.arabic_stem +\dFp host.regression.pg_catalog.default +\dFp ^regression.pg_catalog.default +\dFp nonesuch.pg_catalog.default +\dFt host.regression.pg_catalog.ispell +\dFt regression$.pg_catalog.ispell +\dFt nonesuch.pg_catalog.ispell +\dg nonesuch.pg_database_owner +\dg regression.pg_database_owner +\dL host.regression.plpgsql +\dL *.plpgsql +\dL nonesuch.plpgsql +\dn host.regression.public +\dn """".public +\dn nonesuch.public +\do host.regression.public.!=- +\do "regression|mydb".public.!=- +\do nonesuch.public.!=- +\dO host.regression.pg_catalog.POSIX +\dO .pg_catalog.POSIX +\dO nonesuch.pg_catalog.POSIX +\dp host.regression.public.a_star +\dp "regres+ion".public.a_star +\dp nonesuch.public.a_star +\dP host.regression.public.mlparted +\dP "regres(sion)".public.mlparted +\dP nonesuch.public.mlparted +\drds nonesuch.lc_messages +\drds regression.lc_messages +\dRp public.mypub +\dRp regression.mypub +\dRs public.mysub +\dRs regression.mysub +\dT host.regression.public.widget +\dT "regression{1,2}".public.widget +\dT nonesuch.public.widget +\dx regression.plpgsql +\dx nonesuch.plpgsql +\dX host.regression.public.func_deps_stat +\dX "^regression$".public.func_deps_stat +\dX nonesuch.public.func_deps_stat +\dy regression.myevt +\dy nonesuch.myevt + +-- check that dots within quoted name segments are not counted +\dA "no.such.access.method" +\dt "no.such.table.relation" +\da "no.such.aggregate.function" +\dAc "no.such.operator.class" +\dAf "no.such.operator.family" +\dAo "no.such.operator.of.operator.family" +\dAp "no.such.operator.support.function.of.operator.family" +\db "no.such.tablespace" +\dc "no.such.conversion" +\dC "no.such.cast" +\dd "no.such.object.description" +\dD "no.such.domain" +\ddp "no.such.default.access.privilege" +\di "no.such.index.relation" +\dm "no.such.materialized.view" +\ds "no.such.relation" +\dt "no.such.relation" +\dv "no.such.relation" +\des "no.such.foreign.server" +\dew "no.such.foreign.data.wrapper" +\df "no.such.function" +\dF "no.such.text.search.configuration" +\dFd "no.such.text.search.dictionary" +\dFp "no.such.text.search.parser" +\dFt "no.such.text.search.template" +\dg "no.such.role" +\dL "no.such.language" +\dn "no.such.schema" +\do "no.such.operator" +\dO "no.such.collation" +\dp "no.such.access.privilege" +\dP "no.such.partitioned.relation" +\drds "no.such.setting" +\dRp "no.such.publication" +\dRs "no.such.subscription" +\dT "no.such.data.type" +\dx "no.such.installed.extension" +\dX "no.such.extended.statistics" +\dy "no.such.event.trigger" + +-- again, but with dotted schema qualifications. +\dA "no.such.schema"."no.such.access.method" +\dt "no.such.schema"."no.such.table.relation" +\da "no.such.schema"."no.such.aggregate.function" +\dAc "no.such.schema"."no.such.operator.class" +\dAf "no.such.schema"."no.such.operator.family" +\dAo "no.such.schema"."no.such.operator.of.operator.family" +\dAp "no.such.schema"."no.such.operator.support.function.of.operator.family" +\db "no.such.schema"."no.such.tablespace" +\dc "no.such.schema"."no.such.conversion" +\dC "no.such.schema"."no.such.cast" +\dd "no.such.schema"."no.such.object.description" +\dD "no.such.schema"."no.such.domain" +\ddp "no.such.schema"."no.such.default.access.privilege" +\di "no.such.schema"."no.such.index.relation" +\dm "no.such.schema"."no.such.materialized.view" +\ds "no.such.schema"."no.such.relation" +\dt "no.such.schema"."no.such.relation" +\dv "no.such.schema"."no.such.relation" +\des "no.such.schema"."no.such.foreign.server" +\dew "no.such.schema"."no.such.foreign.data.wrapper" +\df "no.such.schema"."no.such.function" +\dF "no.such.schema"."no.such.text.search.configuration" +\dFd "no.such.schema"."no.such.text.search.dictionary" +\dFp "no.such.schema"."no.such.text.search.parser" +\dFt "no.such.schema"."no.such.text.search.template" +\dg "no.such.schema"."no.such.role" +\dL "no.such.schema"."no.such.language" +\do "no.such.schema"."no.such.operator" +\dO "no.such.schema"."no.such.collation" +\dp "no.such.schema"."no.such.access.privilege" +\dP "no.such.schema"."no.such.partitioned.relation" +\drds "no.such.schema"."no.such.setting" +\dRp "no.such.schema"."no.such.publication" +\dRs "no.such.schema"."no.such.subscription" +\dT "no.such.schema"."no.such.data.type" +\dx "no.such.schema"."no.such.installed.extension" +\dX "no.such.schema"."no.such.extended.statistics" +\dy "no.such.schema"."no.such.event.trigger" + +-- again, but with current database and dotted schema qualifications. +\dt regression."no.such.schema"."no.such.table.relation" +\da regression."no.such.schema"."no.such.aggregate.function" +\dc regression."no.such.schema"."no.such.conversion" +\dC regression."no.such.schema"."no.such.cast" +\dd regression."no.such.schema"."no.such.object.description" +\dD regression."no.such.schema"."no.such.domain" +\di regression."no.such.schema"."no.such.index.relation" +\dm regression."no.such.schema"."no.such.materialized.view" +\ds regression."no.such.schema"."no.such.relation" +\dt regression."no.such.schema"."no.such.relation" +\dv regression."no.such.schema"."no.such.relation" +\df regression."no.such.schema"."no.such.function" +\dF regression."no.such.schema"."no.such.text.search.configuration" +\dFd regression."no.such.schema"."no.such.text.search.dictionary" +\dFp regression."no.such.schema"."no.such.text.search.parser" +\dFt regression."no.such.schema"."no.such.text.search.template" +\do regression."no.such.schema"."no.such.operator" +\dO regression."no.such.schema"."no.such.collation" +\dp regression."no.such.schema"."no.such.access.privilege" +\dP regression."no.such.schema"."no.such.partitioned.relation" +\dT regression."no.such.schema"."no.such.data.type" +\dX regression."no.such.schema"."no.such.extended.statistics" + +-- again, but with dotted database and dotted schema qualifications. +\dt "no.such.database"."no.such.schema"."no.such.table.relation" +\da "no.such.database"."no.such.schema"."no.such.aggregate.function" +\dc "no.such.database"."no.such.schema"."no.such.conversion" +\dC "no.such.database"."no.such.schema"."no.such.cast" +\dd "no.such.database"."no.such.schema"."no.such.object.description" +\dD "no.such.database"."no.such.schema"."no.such.domain" +\ddp "no.such.database"."no.such.schema"."no.such.default.access.privilege" +\di "no.such.database"."no.such.schema"."no.such.index.relation" +\dm "no.such.database"."no.such.schema"."no.such.materialized.view" +\ds "no.such.database"."no.such.schema"."no.such.relation" +\dt "no.such.database"."no.such.schema"."no.such.relation" +\dv "no.such.database"."no.such.schema"."no.such.relation" +\df "no.such.database"."no.such.schema"."no.such.function" +\dF "no.such.database"."no.such.schema"."no.such.text.search.configuration" +\dFd "no.such.database"."no.such.schema"."no.such.text.search.dictionary" +\dFp "no.such.database"."no.such.schema"."no.such.text.search.parser" +\dFt "no.such.database"."no.such.schema"."no.such.text.search.template" +\do "no.such.database"."no.such.schema"."no.such.operator" +\dO "no.such.database"."no.such.schema"."no.such.collation" +\dp "no.such.database"."no.such.schema"."no.such.access.privilege" +\dP "no.such.database"."no.such.schema"."no.such.partitioned.relation" +\dT "no.such.database"."no.such.schema"."no.such.data.type" +\dX "no.such.database"."no.such.schema"."no.such.extended.statistics" |