diff options
Diffstat (limited to 'src/bin')
-rw-r--r-- | src/bin/pg_dump/dumputils.c | 2 | ||||
-rw-r--r-- | src/bin/pg_dump/pg_backup_archiver.c | 2 | ||||
-rw-r--r-- | src/bin/pg_dump/pg_dump.c | 73 | ||||
-rw-r--r-- | src/bin/psql/command.c | 6 | ||||
-rw-r--r-- | src/bin/psql/describe.c | 123 | ||||
-rw-r--r-- | src/bin/psql/describe.h | 3 | ||||
-rw-r--r-- | src/bin/psql/help.c | 4 | ||||
-rw-r--r-- | src/bin/psql/tab-complete.c | 86 |
8 files changed, 258 insertions, 41 deletions
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c index e280b5de174..0f814f142f2 100644 --- a/src/bin/pg_dump/dumputils.c +++ b/src/bin/pg_dump/dumputils.c @@ -868,6 +868,8 @@ do { \ CONVERT_PRIV('U', "USAGE"); else if (strcmp(type, "FOREIGN SERVER") == 0) CONVERT_PRIV('U', "USAGE"); + else if (strcmp(type, "FOREIGN TABLE") == 0) + CONVERT_PRIV('r', "SELECT"); else if (strcmp(type, "LARGE OBJECT") == 0) { CONVERT_PRIV('r', "SELECT"); diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index e1f3b055def..64d8d93dda8 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -2726,6 +2726,7 @@ _getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH) strcmp(type, "DOMAIN") == 0 || strcmp(type, "TABLE") == 0 || strcmp(type, "TYPE") == 0 || + strcmp(type, "FOREIGN TABLE") == 0 || strcmp(type, "TEXT SEARCH DICTIONARY") == 0 || strcmp(type, "TEXT SEARCH CONFIGURATION") == 0) { @@ -2918,6 +2919,7 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat strcmp(te->desc, "TYPE") == 0 || strcmp(te->desc, "VIEW") == 0 || strcmp(te->desc, "SEQUENCE") == 0 || + strcmp(te->desc, "FOREIGN TABLE") == 0 || strcmp(te->desc, "TEXT SEARCH DICTIONARY") == 0 || strcmp(te->desc, "TEXT SEARCH CONFIGURATION") == 0 || strcmp(te->desc, "FOREIGN DATA WRAPPER") == 0 || diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 08288e871a9..b0a0dc56072 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -975,8 +975,9 @@ expand_table_name_patterns(SimpleStringList *patterns, SimpleOidList *oids) "SELECT c.oid" "\nFROM pg_catalog.pg_class c" "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace" - "\nWHERE c.relkind in ('%c', '%c', '%c')\n", - RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW); + "\nWHERE c.relkind in ('%c', '%c', '%c', '%c')\n", + RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW, + RELKIND_FOREIGN_TABLE); processSQLNamePattern(g_conn, query, cell->val, true, false, "n.nspname", "c.relname", NULL, "pg_catalog.pg_table_is_visible(c.oid)"); @@ -1476,6 +1477,9 @@ getTableData(TableInfo *tblinfo, int numTables, bool oids) /* Skip SEQUENCEs (handled elsewhere) */ if (tblinfo[i].relkind == RELKIND_SEQUENCE) continue; + /* Skip FOREIGN TABLEs (no data to dump) */ + if (tblinfo[i].relkind == RELKIND_FOREIGN_TABLE) + continue; /* Skip unlogged tables if so requested */ if (tblinfo[i].relpersistence == RELPERSISTENCE_UNLOGGED && no_unlogged_table_data) @@ -3513,12 +3517,13 @@ getTables(int *numTables) "d.objsubid = 0 AND " "d.refclassid = c.tableoid AND d.deptype = 'a') " "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) " - "WHERE c.relkind in ('%c', '%c', '%c', '%c') " + "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c') " "ORDER BY c.oid", username_subquery, RELKIND_SEQUENCE, RELKIND_RELATION, RELKIND_SEQUENCE, - RELKIND_VIEW, RELKIND_COMPOSITE_TYPE); + RELKIND_VIEW, RELKIND_COMPOSITE_TYPE, + RELKIND_FOREIGN_TABLE); } else if (g_fout->remoteVersion >= 90000) { @@ -3871,7 +3876,7 @@ getTables(int *numTables) * assume our lock on the child is enough to prevent schema * alterations to parent tables. * - * NOTE: it'd be kinda nice to lock views and sequences too, not only + * NOTE: it'd be kinda nice to lock other relations too, not only * plain tables, but the backend doesn't presently allow that. */ if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION) @@ -10938,7 +10943,9 @@ dumpTable(Archive *fout, TableInfo *tbinfo) /* Handle the ACL here */ namecopy = strdup(fmtId(tbinfo->dobj.name)); dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, - (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE", + (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : + (tbinfo->relkind == RELKIND_FOREIGN_TABLE) ? "FOREIGN TABLE" : + "TABLE", namecopy, NULL, tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name, tbinfo->rolname, tbinfo->relacl); @@ -11007,6 +11014,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) int j, k; bool toast_set = false; + char *srvname; + char *ftoptions = NULL; /* Make sure we are in proper schema */ selectSourceSchema(tbinfo->dobj.namespace->dobj.name); @@ -11080,7 +11089,35 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) } else { - reltypename = "TABLE"; + if (tbinfo->relkind == RELKIND_FOREIGN_TABLE) + { + int i_srvname; + int i_ftoptions; + + reltypename = "FOREIGN TABLE"; + + /* retrieve name of foreign server and generic options */ + appendPQExpBuffer(query, + "SELECT fs.srvname, array_to_string(ARRAY(" + " SELECT option_name || ' ' || quote_literal(option_value)" + " FROM pg_options_to_table(ftoptions)), ', ') AS ftoptions " + "FROM pg_foreign_table ft JOIN pg_foreign_server fs " + " ON (fs.oid = ft.ftserver) " + "WHERE ft.ftrelid = %u", tbinfo->dobj.catId.oid); + res = PQexec(g_conn, query->data); + check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK); + i_srvname = PQfnumber(res, "srvname"); + i_ftoptions = PQfnumber(res, "ftoptions"); + srvname = strdup(PQgetvalue(res, 0, i_srvname)); + ftoptions = strdup(PQgetvalue(res, 0, i_ftoptions)); + PQclear(res); + } + else + { + reltypename = "TABLE"; + srvname = NULL; + ftoptions = NULL; + } numParents = tbinfo->numParents; parents = tbinfo->parents; @@ -11088,7 +11125,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) * DROP must be fully qualified in case same name appears in * pg_catalog */ - appendPQExpBuffer(delq, "DROP TABLE %s.", + appendPQExpBuffer(delq, "DROP %s %s.", reltypename, fmtId(tbinfo->dobj.namespace->dobj.name)); appendPQExpBuffer(delq, "%s;\n", fmtId(tbinfo->dobj.name)); @@ -11096,12 +11133,11 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) if (binary_upgrade) binary_upgrade_set_relfilenodes(q, tbinfo->dobj.catId.oid, false); - if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED) - appendPQExpBuffer(q, "CREATE UNLOGGED TABLE %s", - fmtId(tbinfo->dobj.name)); - else - appendPQExpBuffer(q, "CREATE TABLE %s", - fmtId(tbinfo->dobj.name)); + appendPQExpBuffer(q, "CREATE %s%s %s", + tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ? + "UNLOGGED " : "", + reltypename, + fmtId(tbinfo->dobj.name)); if (tbinfo->reloftype) appendPQExpBuffer(q, " OF %s", tbinfo->reloftype); actual_atts = 0; @@ -11235,6 +11271,9 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) appendPQExpBuffer(q, ")"); } + if (tbinfo->relkind == RELKIND_FOREIGN_TABLE) + appendPQExpBuffer(q, "\nSERVER %s", srvname); + if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) || (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)) { @@ -11254,6 +11293,10 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) appendPQExpBuffer(q, ")"); } + /* Dump generic options if any */ + if (ftoptions && ftoptions[0]) + appendPQExpBuffer(q, "\nOPTIONS (%s)", ftoptions); + appendPQExpBuffer(q, ";\n"); /* @@ -11268,7 +11311,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) * order. That also means we have to take care about setting * attislocal correctly, plus fix up any inherited CHECK constraints. */ - if (binary_upgrade) + if (binary_upgrade && tbinfo->relkind == RELKIND_RELATION) { for (j = 0; j < tbinfo->numatts; j++) { diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 04be60f73e6..962c13c1360 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -369,7 +369,7 @@ exec_command(const char *cmd, success = describeTableDetails(pattern, show_verbose, show_system); else /* standard listing of interesting things */ - success = listTables("tvs", NULL, show_verbose, show_system); + success = listTables("tvsE", NULL, show_verbose, show_system); break; case 'a': success = describeAggregates(pattern, show_verbose, show_system); @@ -432,6 +432,7 @@ exec_command(const char *cmd, case 'v': case 'i': case 's': + case 'E': success = listTables(&cmd[1], pattern, show_verbose, show_system); break; case 'r': @@ -483,6 +484,9 @@ exec_command(const char *cmd, case 'w': success = listForeignDataWrappers(pattern, show_verbose); break; + case 't': + success = listForeignTables(pattern, show_verbose); + break; default: status = PSQL_CMD_UNKNOWN; break; diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 19ba517d1ba..205190f729e 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -687,11 +687,12 @@ permissionsList(const char *pattern) printfPQExpBuffer(&buf, "SELECT n.nspname as \"%s\",\n" " c.relname as \"%s\",\n" - " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'S' THEN '%s' END as \"%s\",\n" + " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'S' THEN '%s' WHEN 'f' THEN '%s' END as \"%s\",\n" " ", gettext_noop("Schema"), gettext_noop("Name"), gettext_noop("table"), gettext_noop("view"), gettext_noop("sequence"), + gettext_noop("foreign table"), gettext_noop("Type")); printACLColumn(&buf, "c.relacl"); @@ -707,7 +708,7 @@ permissionsList(const char *pattern) appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_class c\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n" - "WHERE c.relkind IN ('r', 'v', 'S')\n"); + "WHERE c.relkind IN ('r', 'v', 'S', 'f')\n"); /* * Unless a schema pattern is specified, we suppress system and temp @@ -921,15 +922,16 @@ objectDescription(const char *pattern, bool showSystem) " n.nspname as nspname,\n" " CAST(c.relname AS pg_catalog.text) as name,\n" " CAST(\n" - " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' END" + " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' WHEN 'f' THEN '%s' END" " AS pg_catalog.text) as object\n" " FROM pg_catalog.pg_class c\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n" - " WHERE c.relkind IN ('r', 'v', 'i', 'S')\n", + " WHERE c.relkind IN ('r', 'v', 'i', 'S', 'f')\n", gettext_noop("table"), gettext_noop("view"), gettext_noop("index"), - gettext_noop("sequence")); + gettext_noop("sequence"), + gettext_noop("foreign table")); if (!showSystem && !pattern) appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n" @@ -1325,6 +1327,10 @@ describeOneTableDetails(const char *schemaname, printfPQExpBuffer(&title, _("Composite type \"%s.%s\""), schemaname, relationname); break; + case 'f': + printfPQExpBuffer(&title, _("Foreign table \"%s.%s\""), + schemaname, relationname); + break; default: /* untranslated unknown relkind */ printfPQExpBuffer(&title, "?%c? \"%s.%s\"", @@ -1337,7 +1343,8 @@ describeOneTableDetails(const char *schemaname, headers[1] = gettext_noop("Type"); cols = 2; - if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v') + if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' || + tableinfo.relkind == 'f') { show_modifiers = true; headers[cols++] = gettext_noop("Modifiers"); @@ -1565,7 +1572,7 @@ describeOneTableDetails(const char *schemaname, PQclear(result); } } - else if (tableinfo.relkind == 'r') + else if (tableinfo.relkind == 'r' || tableinfo.relkind == 'f') { /* Footer information about a table */ PGresult *result = NULL; @@ -1984,11 +1991,36 @@ describeOneTableDetails(const char *schemaname, /* * Finish printing the footer information about a table. */ - if (tableinfo.relkind == 'r') + if (tableinfo.relkind == 'r' || tableinfo.relkind == 'f') { PGresult *result; int tuples; + /* print foreign server name */ + if (tableinfo.relkind == 'f') + { + /* Footer information about foreign table */ + printfPQExpBuffer(&buf, + "SELECT s.srvname\n" + "FROM pg_catalog.pg_foreign_table f,\n" + " pg_catalog.pg_foreign_server s\n" + "WHERE f.ftrelid = %s AND s.oid = f.ftserver", + oid); + result = PSQLexec(buf.data, false); + if (!result) + goto error_return; + else if (PQntuples(result) != 1) + { + PQclear(result); + goto error_return; + } + + printfPQExpBuffer(&buf, "Server: %s", + PQgetvalue(result, 0, 0)); + printTableAddFooter(&cont, buf.data); + PQclear(result); + } + /* print inherited tables */ printfPQExpBuffer(&buf, "SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhparent AND i.inhrelid = '%s' ORDER BY inhseqno", oid); @@ -2406,8 +2438,9 @@ listDbRoleSettings(const char *pattern, const char *pattern2) * i - indexes * v - views * s - sequences + * E - foreign table (Note: different from 'f', the relkind value) * (any order of the above is fine) - * If tabtypes is empty, we default to \dtvs. + * If tabtypes is empty, we default to \dtvsE. */ bool listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSystem) @@ -2416,14 +2449,15 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys bool showIndexes = strchr(tabtypes, 'i') != NULL; bool showViews = strchr(tabtypes, 'v') != NULL; bool showSeq = strchr(tabtypes, 's') != NULL; + bool showForeign = strchr(tabtypes, 'E') != NULL; PQExpBufferData buf; PGresult *res; printQueryOpt myopt = pset.popt; static const bool translate_columns[] = {false, false, true, false, false, false, false}; - if (!(showTables || showIndexes || showViews || showSeq)) - showTables = showViews = showSeq = true; + if (!(showTables || showIndexes || showViews || showSeq || showForeign)) + showTables = showViews = showSeq = showForeign = true; initPQExpBuffer(&buf); @@ -2434,7 +2468,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys printfPQExpBuffer(&buf, "SELECT n.nspname as \"%s\",\n" " c.relname as \"%s\",\n" - " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' WHEN 's' THEN '%s' END as \"%s\",\n" + " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' WHEN 's' THEN '%s' WHEN 'f' THEN '%s' END as \"%s\",\n" " pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"", gettext_noop("Schema"), gettext_noop("Name"), @@ -2443,6 +2477,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys gettext_noop("index"), gettext_noop("sequence"), gettext_noop("special"), + gettext_noop("foreign table"), gettext_noop("Type"), gettext_noop("Owner")); @@ -2480,6 +2515,9 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys if (showSystem || pattern) appendPQExpBuffer(&buf, "'s',"); /* was RELKIND_SPECIAL in <= * 8.1 */ + if (showForeign) + appendPQExpBuffer(&buf, "'f',"); + appendPQExpBuffer(&buf, "''"); /* dummy */ appendPQExpBuffer(&buf, ")\n"); @@ -3530,6 +3568,67 @@ listUserMappings(const char *pattern, bool verbose) } /* + * \det + * + * Describes foreign tables. + */ +bool +listForeignTables(const char *pattern, bool verbose) +{ + PQExpBufferData buf; + PGresult *res; + printQueryOpt myopt = pset.popt; + + if (pset.sversion < 90100) + { + fprintf(stderr, _("The server (version %d.%d) does not support foreign table.\n"), + pset.sversion / 10000, (pset.sversion / 100) % 100); + return true; + } + + initPQExpBuffer(&buf); + printfPQExpBuffer(&buf, + "SELECT n.nspname AS \"%s\",\n" + " c.relname AS \"%s\",\n" + " s.srvname AS \"%s\"", + gettext_noop("Schema"), + gettext_noop("Table"), + gettext_noop("Server")); + + if (verbose) + appendPQExpBuffer(&buf, + ",\n ft.ftoptions AS \"%s\"", + gettext_noop("Options")); + + appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_foreign_table ft,"); + appendPQExpBuffer(&buf, "\n pg_catalog.pg_class c,"); + appendPQExpBuffer(&buf, "\n pg_catalog.pg_namespace n,"); + appendPQExpBuffer(&buf, "\n pg_catalog.pg_foreign_server s\n"); + appendPQExpBuffer(&buf, "\nWHERE c.oid = ft.ftrelid"); + appendPQExpBuffer(&buf, "\nAND s.oid = ft.ftserver\n"); + appendPQExpBuffer(&buf, "\nAND n.oid = c.relnamespace\n"); + + processSQLNamePattern(pset.db, &buf, pattern, true, false, + NULL, "n.nspname", "c.relname", NULL); + + appendPQExpBuffer(&buf, "ORDER BY 1, 2;"); + + res = PSQLexec(buf.data, false); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + myopt.title = _("List of foreign tables"); + myopt.translate_header = true; + + printQuery(res, &myopt, pset.queryFout, pset.logfile); + + PQclear(res); + return true; +} + +/* * printACLColumn * * Helper function for consistently formatting ACL (privilege) columns. diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h index 6d9fada58f2..2029ef848df 100644 --- a/src/bin/psql/describe.h +++ b/src/bin/psql/describe.h @@ -81,5 +81,8 @@ extern bool listForeignServers(const char *pattern, bool verbose); /* \deu */ extern bool listUserMappings(const char *pattern, bool verbose); +/* \det */ +extern bool listForeignTables(const char *pattern, bool verbose); + #endif /* DESCRIBE_H */ diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index 8ab3b4722ec..96c85a25d6c 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -158,7 +158,7 @@ slashUsage(unsigned short int pager) { FILE *output; - output = PageOutput(90, pager); + output = PageOutput(92, pager); /* if you add/remove a line here, change the row count above */ @@ -199,6 +199,7 @@ slashUsage(unsigned short int pager) fprintf(output, _(" \\dd[S] [PATTERN] show comments on objects\n")); fprintf(output, _(" \\ddp [PATTERN] list default privileges\n")); fprintf(output, _(" \\dD[S] [PATTERN] list domains\n")); + fprintf(output, _(" \\det[+] [PATTERN] list foreign tables\n")); fprintf(output, _(" \\des[+] [PATTERN] list foreign servers\n")); fprintf(output, _(" \\deu[+] [PATTERN] list user mappings\n")); fprintf(output, _(" \\dew[+] [PATTERN] list foreign-data wrappers\n")); @@ -219,6 +220,7 @@ slashUsage(unsigned short int pager) fprintf(output, _(" \\dT[S+] [PATTERN] list data types\n")); fprintf(output, _(" \\du[+] [PATTERN] list roles\n")); fprintf(output, _(" \\dv[S+] [PATTERN] list views\n")); + fprintf(output, _(" \\dE[S+] [PATTERN] list foreign tables\n")); fprintf(output, _(" \\l[+] list all databases\n")); fprintf(output, _(" \\sf[+] FUNCNAME show a function's definition\n")); fprintf(output, _(" \\z [PATTERN] same as \\dp\n")); diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 2b140c150da..414baa695d3 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -288,6 +288,21 @@ static const SchemaQuery Query_for_list_of_sequences = { NULL }; +static const SchemaQuery Query_for_list_of_foreign_tables = { + /* catname */ + "pg_catalog.pg_class c", + /* selcondition */ + "c.relkind IN ('f')", + /* viscondition */ + "pg_catalog.pg_table_is_visible(c.oid)", + /* namespace */ + "c.relnamespace", + /* result */ + "pg_catalog.quote_ident(c.relname)", + /* qualresult */ + NULL +}; + static const SchemaQuery Query_for_list_of_tables = { /* catname */ "pg_catalog.pg_class c", @@ -354,11 +369,11 @@ static const SchemaQuery Query_for_list_of_updatables = { NULL }; -static const SchemaQuery Query_for_list_of_tisv = { +static const SchemaQuery Query_for_list_of_tisvf = { /* catname */ "pg_catalog.pg_class c", /* selcondition */ - "c.relkind IN ('r', 'i', 'S', 'v')", + "c.relkind IN ('r', 'i', 'S', 'v', 'f')", /* viscondition */ "pg_catalog.pg_table_is_visible(c.oid)", /* namespace */ @@ -369,11 +384,11 @@ static const SchemaQuery Query_for_list_of_tisv = { NULL }; -static const SchemaQuery Query_for_list_of_tsv = { +static const SchemaQuery Query_for_list_of_tsvf = { /* catname */ "pg_catalog.pg_class c", /* selcondition */ - "c.relkind IN ('r', 'S', 'v')", + "c.relkind IN ('r', 'S', 'v', 'f')", /* viscondition */ "pg_catalog.pg_table_is_visible(c.oid)", /* namespace */ @@ -592,6 +607,7 @@ static const pgsql_thing_t words_after_create[] = { {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, true}, {"DOMAIN", NULL, &Query_for_list_of_domains}, {"FOREIGN DATA WRAPPER", NULL, NULL}, + {"FOREIGN TABLE", NULL, NULL}, {"FUNCTION", NULL, &Query_for_list_of_functions}, {"GROUP", Query_for_list_of_roles}, {"LANGUAGE", Query_for_list_of_languages}, @@ -696,7 +712,7 @@ psql_completion(char *text, int start, int end) static const char *const backslash_commands[] = { "\\a", "\\connect", "\\conninfo", "\\C", "\\cd", "\\copy", "\\copyright", - "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\des", "\\deu", "\\dew", "\\df", + "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\des", "\\det", "\\deu", "\\dew", "\\df", "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dn", "\\do", "\\dp", "\\drds", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du", "\\e", "\\echo", "\\ef", "\\encoding", @@ -759,7 +775,7 @@ psql_completion(char *text, int start, int end) pg_strcasecmp(prev3_wd, "TABLE") != 0) { static const char *const list_ALTER[] = - {"AGGREGATE", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN", "FOREIGN DATA WRAPPER", "FUNCTION", + {"AGGREGATE", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION", "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "OPERATOR", "ROLE", "SCHEMA", "SERVER", "SEQUENCE", "TABLE", "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", "USER", "USER MAPPING FOR", "VIEW", NULL}; @@ -822,6 +838,16 @@ psql_completion(char *text, int start, int end) COMPLETE_WITH_LIST(list_ALTERDATABASE); } + /* ALTER FOREIGN */ + else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 && + pg_strcasecmp(prev_wd, "FOREIGN") == 0) + { + static const char *const list_ALTER_FOREIGN[] = + {"DATA WRAPPER", "TABLE", NULL}; + + COMPLETE_WITH_LIST(list_ALTER_FOREIGN); + } + /* ALTER FOREIGN DATA WRAPPER <name> */ else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && pg_strcasecmp(prev4_wd, "FOREIGN") == 0 && @@ -834,6 +860,17 @@ psql_completion(char *text, int start, int end) COMPLETE_WITH_LIST(list_ALTER_FDW); } + /* ALTER FOREIGN TABLE <name> */ + else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && + pg_strcasecmp(prev3_wd, "FOREIGN") == 0 && + pg_strcasecmp(prev2_wd, "TABLE") == 0) + { + static const char *const list_ALTER_FOREIGN_TABLE[] = + {"ALTER", "DROP", "RENAME", "OWNER TO", "SET SCHEMA", NULL}; + + COMPLETE_WITH_LIST(list_ALTER_FOREIGN_TABLE); + } + /* ALTER INDEX <name> */ else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && pg_strcasecmp(prev2_wd, "INDEX") == 0) @@ -1448,7 +1485,7 @@ psql_completion(char *text, int start, int end) pg_strcasecmp(prev_wd, "ON") == 0) { static const char *const list_COMMENT[] = - {"CAST", "CONVERSION", "DATABASE", "INDEX", "LANGUAGE", "RULE", "SCHEMA", + {"CAST", "CONVERSION", "DATABASE", "FOREIGN TABLE", "INDEX", "LANGUAGE", "RULE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION", "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT", "TABLESPACE", "TEXT SEARCH", "ROLE", NULL}; @@ -1541,6 +1578,16 @@ psql_completion(char *text, int start, int end) pg_strcasecmp(prev_wd, "TEMPLATE") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_template_databases); + /* CREATE FOREIGN */ + else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 && + pg_strcasecmp(prev_wd, "FOREIGN") == 0) + { + static const char *const list_CREATE_FOREIGN[] = + {"DATA WRAPPER", "TABLE", NULL}; + + COMPLETE_WITH_LIST(list_CREATE_FOREIGN); + } + /* CREATE FOREIGN DATA WRAPPER */ else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 && pg_strcasecmp(prev4_wd, "FOREIGN") == 0 && @@ -1911,6 +1958,14 @@ psql_completion(char *text, int start, int end) COMPLETE_WITH_LIST(list_DROPCR); } } + else if (pg_strcasecmp(prev2_wd, "DROP") == 0 && + pg_strcasecmp(prev_wd, "FOREIGN") == 0) + { + static const char *const drop_CREATE_FOREIGN[] = + {"DATA WRAPPER", "TABLE", NULL}; + + COMPLETE_WITH_LIST(drop_CREATE_FOREIGN); + } else if (pg_strcasecmp(prev4_wd, "DROP") == 0 && (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 || pg_strcasecmp(prev3_wd, "FUNCTION") == 0) && @@ -2015,6 +2070,12 @@ psql_completion(char *text, int start, int end) pg_strcasecmp(prev_wd, "WRAPPER") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_fdws); +/* FOREIGN TABLE */ + else if (pg_strcasecmp(prev3_wd, "CREATE") != 0 && + pg_strcasecmp(prev2_wd, "FOREIGN") == 0 && + pg_strcasecmp(prev_wd, "TABLE") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL); + /* GRANT && REVOKE */ /* Complete GRANT/REVOKE with a list of privileges */ else if (pg_strcasecmp(prev_wd, "GRANT") == 0 || @@ -2046,10 +2107,11 @@ psql_completion(char *text, int start, int end) else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 || pg_strcasecmp(prev3_wd, "REVOKE") == 0) && pg_strcasecmp(prev_wd, "ON") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf, " UNION SELECT 'DATABASE'" " UNION SELECT 'FOREIGN DATA WRAPPER'" " UNION SELECT 'FOREIGN SERVER'" + " UNION SELECT 'FOREIGN TABLE'" " UNION SELECT 'FUNCTION'" " UNION SELECT 'LANGUAGE'" " UNION SELECT 'LARGE OBJECT'" @@ -2061,7 +2123,7 @@ psql_completion(char *text, int start, int end) pg_strcasecmp(prev_wd, "FOREIGN") == 0) { static const char *const list_privilege_foreign[] = - {"DATA WRAPPER", "SERVER", NULL}; + {"DATA WRAPPER", "SERVER", "TABLE", NULL}; COMPLETE_WITH_LIST(list_privilege_foreign); } @@ -2582,7 +2644,7 @@ psql_completion(char *text, int start, int end) else if (pg_strcasecmp(prev_wd, "FROM") == 0 && pg_strcasecmp(prev3_wd, "COPY") != 0 && pg_strcasecmp(prev3_wd, "\\copy") != 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL); + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf, NULL); /* Backslash commands */ /* TODO: \dc \dd \dl */ @@ -2620,7 +2682,7 @@ psql_completion(char *text, int start, int end) COMPLETE_WITH_QUERY(Query_for_list_of_schemas); else if (strncmp(prev_wd, "\\dp", strlen("\\dp")) == 0 || strncmp(prev_wd, "\\z", strlen("\\z")) == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL); + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf, NULL); else if (strncmp(prev_wd, "\\ds", strlen("\\ds")) == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL); else if (strncmp(prev_wd, "\\dt", strlen("\\dt")) == 0) @@ -2635,7 +2697,7 @@ psql_completion(char *text, int start, int end) /* must be at end of \d list */ else if (strncmp(prev_wd, "\\d", strlen("\\d")) == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisv, NULL); + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisvf, NULL); else if (strcmp(prev_wd, "\\ef") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL); |