aboutsummaryrefslogtreecommitdiff
path: root/src/bin/psql/describe.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2011-01-01 23:48:11 -0500
committerRobert Haas <rhaas@postgresql.org>2011-01-01 23:48:11 -0500
commit0d692a0dc9f0e532c67c577187fe5d7d323cb95b (patch)
tree5177be3794b8ffa768a3cd852221425bd2a74347 /src/bin/psql/describe.c
parent6600d5e91c754789002ed794c18cb856c190f58f (diff)
downloadpostgresql-0d692a0dc9f0e532c67c577187fe5d7d323cb95b.tar.gz
postgresql-0d692a0dc9f0e532c67c577187fe5d7d323cb95b.zip
Basic foreign table support.
Foreign tables are a core component of SQL/MED. This commit does not provide a working SQL/MED infrastructure, because foreign tables cannot yet be queried. Support for foreign table scans will need to be added in a future patch. However, this patch creates the necessary system catalog structure, syntax support, and support for ancillary operations such as COMMENT and SECURITY LABEL. Shigeru Hanada, heavily revised by Robert Haas
Diffstat (limited to 'src/bin/psql/describe.c')
-rw-r--r--src/bin/psql/describe.c123
1 files changed, 111 insertions, 12 deletions
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.