diff options
Diffstat (limited to 'src/bin/psql/describe.c')
-rw-r--r-- | src/bin/psql/describe.c | 520 |
1 files changed, 518 insertions, 2 deletions
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 6dd156af4af..f258e16ce1a 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -3,7 +3,7 @@ * * Copyright (c) 2000-2007, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.157 2007/07/25 22:16:18 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.158 2007/08/21 01:11:22 tgl Exp $ */ #include "postgres_fe.h" #include "describe.h" @@ -33,6 +33,14 @@ static bool describeOneTableDetails(const char *schemaname, bool verbose); static bool add_tablespace_footer(char relkind, Oid tablespace, char **footers, int *count, PQExpBufferData buf, bool newline); +static bool listTSParsersVerbose(const char *pattern); +static bool describeOneTSParser(const char *oid, const char *nspname, + const char *prsname); +static bool listTSConfigsVerbose(const char *pattern); +static bool describeOneTSConfig(const char *oid, const char *nspname, + const char *cfgname, + const char *pnspname, const char *prsname); + /*---------------- * Handlers for various slash commands displaying some sort of list @@ -325,7 +333,6 @@ describeTypes(const char *pattern, bool verbose) } - /* \do */ bool @@ -1930,3 +1937,512 @@ listSchemas(const char *pattern, bool verbose) PQclear(res); return true; } + + +/* + * \dFp + * list text search parsers + */ +bool +listTSParsers(const char *pattern, bool verbose) +{ + PQExpBufferData buf; + PGresult *res; + printQueryOpt myopt = pset.popt; + + if (verbose) + return listTSParsersVerbose(pattern); + + initPQExpBuffer(&buf); + + printfPQExpBuffer(&buf, + "SELECT \n" + " n.nspname as \"%s\",\n" + " p.prsname as \"%s\",\n" + " pg_catalog.obj_description(p.oid, 'pg_ts_parser') as \"%s\"\n" + "FROM pg_catalog.pg_ts_parser p \n" + "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n", + _("Schema"), + _("Name"), + _("Description") + ); + + processSQLNamePattern(pset.db, &buf, pattern, false, false, + "n.nspname", "p.prsname", NULL, + "pg_catalog.pg_ts_parser_is_visible(p.oid)"); + + appendPQExpBuffer(&buf, "ORDER BY 1, 2;"); + + res = PSQLexec(buf.data, false); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + myopt.title = _("List of text search parsers"); + + printQuery(res, &myopt, pset.queryFout, pset.logfile); + + PQclear(res); + return true; +} + +/* + * full description of parsers + */ +static bool +listTSParsersVerbose(const char *pattern) +{ + PQExpBufferData buf; + PGresult *res; + int i; + + initPQExpBuffer(&buf); + + printfPQExpBuffer(&buf, + "SELECT p.oid, \n" + " n.nspname, \n" + " p.prsname \n" + "FROM pg_catalog.pg_ts_parser p\n" + "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)"); + + appendPQExpBuffer(&buf, "ORDER BY 1, 2;"); + + res = PSQLexec(buf.data, false); + termPQExpBuffer(&buf); + if (!res) + return false; + + if (PQntuples(res) == 0) + { + if (!pset.quiet) + fprintf(stderr, _("Did not find any text search parser named \"%s\".\n"), + pattern); + PQclear(res); + return false; + } + + for (i = 0; i < PQntuples(res); i++) + { + const char *oid; + const char *nspname = NULL; + const char *prsname; + + oid = PQgetvalue(res, i, 0); + if (!PQgetisnull(res, i, 1)) + nspname = PQgetvalue(res, i, 1); + prsname = PQgetvalue(res, i, 2); + + if (!describeOneTSParser(oid, nspname, prsname)) + { + PQclear(res); + return false; + } + + if (cancel_pressed) + { + PQclear(res); + return false; + } + } + + PQclear(res); + return true; +} + +static bool +describeOneTSParser(const char *oid, const char *nspname, const char *prsname) +{ + PQExpBufferData buf; + PGresult *res; + char title[1024]; + printQueryOpt myopt = pset.popt; + + initPQExpBuffer(&buf); + + printfPQExpBuffer(&buf, + "SELECT '%s' AS \"%s\", \n" + " p.prsstart::pg_catalog.regproc AS \"%s\", \n" + " pg_catalog.obj_description(p.prsstart, 'pg_proc') as \"%s\" \n" + " FROM pg_catalog.pg_ts_parser p \n" + " WHERE p.oid = '%s' \n" + "UNION ALL \n" + "SELECT '%s', \n" + " p.prstoken::pg_catalog.regproc, \n" + " pg_catalog.obj_description(p.prstoken, 'pg_proc') \n" + " FROM pg_catalog.pg_ts_parser p \n" + " WHERE p.oid = '%s' \n" + "UNION ALL \n" + "SELECT '%s', \n" + " p.prsend::pg_catalog.regproc, \n" + " pg_catalog.obj_description(p.prsend, 'pg_proc') \n" + " FROM pg_catalog.pg_ts_parser p \n" + " WHERE p.oid = '%s' \n" + "UNION ALL \n" + "SELECT '%s', \n" + " p.prsheadline::pg_catalog.regproc, \n" + " pg_catalog.obj_description(p.prsheadline, 'pg_proc') \n" + " FROM pg_catalog.pg_ts_parser p \n" + " WHERE p.oid = '%s' \n" + "UNION ALL \n" + "SELECT '%s', \n" + " p.prslextype::pg_catalog.regproc, \n" + " pg_catalog.obj_description(p.prslextype, 'pg_proc') \n" + " FROM pg_catalog.pg_ts_parser p \n" + " WHERE p.oid = '%s' \n", + _("Start parse"), + _("Method"), _("Function"), _("Description"), + oid, + _("Get next token"), oid, + _("End parse"), oid, + _("Get headline"), oid, + _("Get lexeme types"), oid + ); + + res = PSQLexec(buf.data, false); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + if (nspname) + sprintf(title, _("Text search parser \"%s.%s\""), nspname, prsname); + else + sprintf(title, _("Text search parser \"%s\""), prsname); + myopt.title = title; + myopt.footers = NULL; + myopt.default_footer = false; + + printQuery(res, &myopt, pset.queryFout, pset.logfile); + + PQclear(res); + + initPQExpBuffer(&buf); + + printfPQExpBuffer(&buf, + "SELECT t.alias as \"%s\", \n" + " t.description as \"%s\" \n" + "FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t \n" + "ORDER BY 1;", + _("Token name"), + _("Description"), + oid); + + res = PSQLexec(buf.data, false); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + if (nspname) + sprintf(title, _("Token types for parser \"%s.%s\""), nspname, prsname); + else + sprintf(title, _("Token types for parser \"%s\""), prsname); + myopt.title = title; + myopt.footers = NULL; + myopt.default_footer = true; + + printQuery(res, &myopt, pset.queryFout, pset.logfile); + + PQclear(res); + return true; +} + + +/* + * \dFd + * list text search dictionaries + */ +bool +listTSDictionaries(const char *pattern, bool verbose) +{ + PQExpBufferData buf; + PGresult *res; + printQueryOpt myopt = pset.popt; + + initPQExpBuffer(&buf); + + printfPQExpBuffer(&buf, + "SELECT \n" + " n.nspname as \"%s\",\n" + " d.dictname as \"%s\",\n", + _("Schema"), + _("Name")); + + if (verbose) + { + appendPQExpBuffer(&buf, + " ( SELECT COALESCE(nt.nspname, '(null)')::pg_catalog.text || '.' || t.tmplname FROM \n" + " pg_catalog.pg_ts_template t \n" + " LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace \n" + " WHERE d.dicttemplate = t.oid ) AS \"%s\", \n" + " d.dictinitoption as \"%s\", \n", + _("Template"), + _("Init options")); + } + + appendPQExpBuffer(&buf, + " pg_catalog.obj_description(d.oid, 'pg_ts_dict') as \"%s\"\n", + _("Description")); + + appendPQExpBuffer(&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)"); + + appendPQExpBuffer(&buf, "ORDER BY 1, 2;"); + + res = PSQLexec(buf.data, false); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + myopt.title = _("List of text search dictionaries"); + + printQuery(res, &myopt, pset.queryFout, pset.logfile); + + PQclear(res); + return true; +} + + +/* + * \dFt + * list text search templates + */ +bool +listTSTemplates(const char *pattern, bool verbose) +{ + PQExpBufferData buf; + PGresult *res; + printQueryOpt myopt = pset.popt; + + initPQExpBuffer(&buf); + + printfPQExpBuffer(&buf, + "SELECT \n" + " n.nspname AS \"%s\",\n" + " t.tmplname AS \"%s\",\n" + " t.tmplinit::pg_catalog.regproc AS \"%s\",\n" + " t.tmpllexize::pg_catalog.regproc AS \"%s\",\n" + " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n", + _("Schema"), + _("Name"), + _("Init"), + _("Lexize"), + _("Description")); + + appendPQExpBuffer(&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)"); + + appendPQExpBuffer(&buf, "ORDER BY 1, 2;"); + + res = PSQLexec(buf.data, false); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + myopt.title = _("List of text search templates"); + + printQuery(res, &myopt, pset.queryFout, pset.logfile); + + PQclear(res); + return true; +} + + +/* + * \dF + * list text search configurations + */ +bool +listTSConfigs(const char *pattern, bool verbose) +{ + PQExpBufferData buf; + PGresult *res; + printQueryOpt myopt = pset.popt; + + if (verbose) + return listTSConfigsVerbose(pattern); + + initPQExpBuffer(&buf); + + printfPQExpBuffer(&buf, + "SELECT \n" + " n.nspname as \"%s\",\n" + " c.cfgname as \"%s\",\n" + " pg_catalog.obj_description(c.oid, 'pg_ts_config') as \"%s\"\n" + "FROM pg_catalog.pg_ts_config c\n" + "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace \n", + _("Schema"), + _("Name"), + _("Description") + ); + + processSQLNamePattern(pset.db, &buf, pattern, false, false, + "n.nspname", "c.cfgname", NULL, + "pg_catalog.pg_ts_config_is_visible(c.oid)"); + + appendPQExpBuffer(&buf, "ORDER BY 1, 2;"); + + res = PSQLexec(buf.data, false); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + myopt.title = _("List of text search configurations"); + + printQuery(res, &myopt, pset.queryFout, pset.logfile); + + PQclear(res); + return true; +} + +static bool +listTSConfigsVerbose(const char *pattern) +{ + PQExpBufferData buf; + PGresult *res; + int i; + + initPQExpBuffer(&buf); + + printfPQExpBuffer(&buf, + "SELECT c.oid, c.cfgname,\n" + " n.nspname, \n" + " p.prsname, \n" + " np.nspname as pnspname \n" + "FROM pg_catalog.pg_ts_config c \n" + " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace, \n" + " pg_catalog.pg_ts_parser p \n" + " LEFT JOIN pg_catalog.pg_namespace np ON np.oid = p.prsnamespace \n" + "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)"); + + appendPQExpBuffer(&buf, "ORDER BY 3, 2;"); + + res = PSQLexec(buf.data, false); + termPQExpBuffer(&buf); + if (!res) + return false; + + if (PQntuples(res) == 0) + { + if (!pset.quiet) + fprintf(stderr, _("Did not find any text search configuration named \"%s\".\n"), + pattern); + PQclear(res); + return false; + } + + for (i = 0; i < PQntuples(res); i++) + { + const char *oid; + const char *cfgname; + const char *nspname = NULL; + const char *prsname; + const char *pnspname = NULL; + + oid = PQgetvalue(res, i, 0); + cfgname = PQgetvalue(res, i, 1); + if (!PQgetisnull(res, i, 2)) + nspname = PQgetvalue(res, i, 2); + prsname = PQgetvalue(res, i, 3); + if (!PQgetisnull(res, i, 4)) + pnspname = PQgetvalue(res, i, 4); + + if (!describeOneTSConfig(oid, nspname, cfgname, pnspname, prsname)) + { + PQclear(res); + return false; + } + + if (cancel_pressed) + { + PQclear(res); + return false; + } + } + + PQclear(res); + return true; +} + +static bool +describeOneTSConfig(const char *oid, const char *nspname, const char *cfgname, + const char *pnspname, const char *prsname) +{ + PQExpBufferData buf, + title; + PGresult *res; + printQueryOpt myopt = pset.popt; + + initPQExpBuffer(&buf); + + printfPQExpBuffer(&buf, + "SELECT \n" + " ( SELECT t.alias FROM \n" + " pg_catalog.ts_token_type(c.cfgparser) AS t \n" + " WHERE t.tokid = m.maptokentype ) AS \"%s\", \n" + " pg_catalog.btrim( \n" + " ARRAY( SELECT mm.mapdict::pg_catalog.regdictionary \n" + " FROM pg_catalog.pg_ts_config_map AS mm \n" + " WHERE mm.mapcfg = m.mapcfg AND mm.maptokentype = m.maptokentype \n" + " ORDER BY mapcfg, maptokentype, mapseqno \n" + " ) :: pg_catalog.text , \n" + " '{}') AS \"%s\" \n" + "FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m \n" + "WHERE c.oid = '%s' AND m.mapcfg = c.oid \n" + "GROUP BY m.mapcfg, m.maptokentype, c.cfgparser \n" + "ORDER BY 1", + _("Token"), + _("Dictionaries"), + oid); + + res = PSQLexec(buf.data, false); + termPQExpBuffer(&buf); + if (!res) + return false; + + initPQExpBuffer(&title); + + if (nspname) + appendPQExpBuffer(&title, _("Text search configuration \"%s.%s\""), nspname, cfgname); + else + appendPQExpBuffer(&title, _("Text search configuration \"%s\""), cfgname); + + if (pnspname) + appendPQExpBuffer(&title, _("\nParser: \"%s.%s\""), pnspname, prsname); + else + appendPQExpBuffer(&title, _("\nParser: \"%s\""), prsname); + + myopt.nullPrint = NULL; + myopt.title = title.data; + myopt.footers = NULL; + myopt.default_footer = false; + + printQuery(res, &myopt, pset.queryFout, pset.logfile); + + termPQExpBuffer(&title); + + PQclear(res); + return true; +} |