mirror of
https://github.com/postgres/postgres.git
synced 2025-04-27 22:56:53 +03:00
Improve psql's internal print.c code by introducing an actual print API.
Provides for better code readability, but mainly this is infrastructure changes to allow further changes such as arbitrary footers on printed tables. Also, the translation status of each element in the table is more easily customized. Brendan Jurd, with some editorialization by me.
This commit is contained in:
parent
9340c6372f
commit
1e9199e84c
@ -3,36 +3,27 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.170 2008/05/05 01:21:03 adunstan Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.171 2008/05/12 22:59:58 alvherre Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
#include "describe.h"
|
|
||||||
|
|
||||||
#include "dumputils.h"
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "settings.h"
|
|
||||||
#include "print.h"
|
|
||||||
#include "variables.h"
|
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#ifdef WIN32
|
#include "common.h"
|
||||||
/*
|
#include "describe.h"
|
||||||
* mbvalidate() is used in function describeOneTableDetails() to make sure
|
#include "dumputils.h"
|
||||||
* all characters of the cells will be printed to the DOS console in a
|
|
||||||
* correct way
|
|
||||||
*/
|
|
||||||
#include "mbprint.h"
|
#include "mbprint.h"
|
||||||
#endif
|
#include "print.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "variables.h"
|
||||||
|
|
||||||
|
|
||||||
static bool describeOneTableDetails(const char *schemaname,
|
static bool describeOneTableDetails(const char *schemaname,
|
||||||
const char *relationname,
|
const char *relationname,
|
||||||
const char *oid,
|
const char *oid,
|
||||||
bool verbose);
|
bool verbose);
|
||||||
static bool add_tablespace_footer(char relkind, Oid tablespace, char **footers,
|
static void add_tablespace_footer(printTableContent *const cont, char relkind,
|
||||||
int *count, PQExpBufferData buf, bool newline);
|
Oid tablespace, const bool newline);
|
||||||
static bool listTSParsersVerbose(const char *pattern);
|
static bool listTSParsersVerbose(const char *pattern);
|
||||||
static bool describeOneTSParser(const char *oid, const char *nspname,
|
static bool describeOneTSParser(const char *oid, const char *nspname,
|
||||||
const char *prsname);
|
const char *prsname);
|
||||||
@ -789,11 +780,11 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
PQExpBufferData buf;
|
PQExpBufferData buf;
|
||||||
PGresult *res = NULL;
|
PGresult *res = NULL;
|
||||||
printTableOpt myopt = pset.popt.topt;
|
printTableOpt myopt = pset.popt.topt;
|
||||||
|
printTableContent cont;
|
||||||
int i;
|
int i;
|
||||||
char *view_def = NULL;
|
char *view_def = NULL;
|
||||||
const char *headers[5];
|
char *headers[4];
|
||||||
char **cells = NULL;
|
char **modifiers = NULL;
|
||||||
char **footers = NULL;
|
|
||||||
char **ptr;
|
char **ptr;
|
||||||
PQExpBufferData title;
|
PQExpBufferData title;
|
||||||
PQExpBufferData tmpbuf;
|
PQExpBufferData tmpbuf;
|
||||||
@ -852,25 +843,6 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
atooid(PQgetvalue(res, 0, 6)) : 0;
|
atooid(PQgetvalue(res, 0, 6)) : 0;
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
headers[0] = _("Column");
|
|
||||||
headers[1] = _("Type");
|
|
||||||
cols = 2;
|
|
||||||
|
|
||||||
if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v')
|
|
||||||
{
|
|
||||||
show_modifiers = true;
|
|
||||||
cols++;
|
|
||||||
headers[cols - 1] = _("Modifiers");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
{
|
|
||||||
cols++;
|
|
||||||
headers[cols - 1] = _("Description");
|
|
||||||
}
|
|
||||||
|
|
||||||
headers[cols] = NULL;
|
|
||||||
|
|
||||||
/* Get column info (index requires additional checks) */
|
/* Get column info (index requires additional checks) */
|
||||||
printfPQExpBuffer(&buf, "SELECT a.attname,");
|
printfPQExpBuffer(&buf, "SELECT a.attname,");
|
||||||
appendPQExpBuffer(&buf, "\n pg_catalog.format_type(a.atttypid, a.atttypmod),"
|
appendPQExpBuffer(&buf, "\n pg_catalog.format_type(a.atttypid, a.atttypmod),"
|
||||||
@ -893,6 +865,26 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
goto error_return;
|
goto error_return;
|
||||||
numrows = PQntuples(res);
|
numrows = PQntuples(res);
|
||||||
|
|
||||||
|
/* Set the number of columns, and their names */
|
||||||
|
cols = 2;
|
||||||
|
headers[0] = "Column";
|
||||||
|
headers[1] = "Type";
|
||||||
|
|
||||||
|
if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v')
|
||||||
|
{
|
||||||
|
show_modifiers = true;
|
||||||
|
headers[cols++] = "Modifiers";
|
||||||
|
modifiers = pg_malloc_zero((numrows + 1) * sizeof(*modifiers));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
headers[cols++] = "Description";
|
||||||
|
|
||||||
|
printTableInit(&cont, &myopt, title.data, cols, numrows);
|
||||||
|
|
||||||
|
for (i = 0; i < cols; i++)
|
||||||
|
printTableAddHeader(&cont, headers[i], true, 'l');
|
||||||
|
|
||||||
/* Check if table is a view */
|
/* Check if table is a view */
|
||||||
if (tableinfo.relkind == 'v')
|
if (tableinfo.relkind == 'v')
|
||||||
{
|
{
|
||||||
@ -910,33 +902,20 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Generate table cells to be printed */
|
/* Generate table cells to be printed */
|
||||||
/* note: initialize all cells[] to NULL in case of error exit */
|
|
||||||
cells = pg_malloc_zero((numrows * cols + 1) * sizeof(*cells));
|
|
||||||
|
|
||||||
for (i = 0; i < numrows; i++)
|
for (i = 0; i < numrows; i++)
|
||||||
{
|
{
|
||||||
/* Name */
|
/* Column */
|
||||||
#ifdef WIN32
|
printTableAddCell(&cont, PQgetvalue(res, i, 0), false);
|
||||||
cells[i * cols + 0] = mbvalidate(PQgetvalue(res, i, 0), myopt.encoding);
|
|
||||||
#else
|
|
||||||
cells[i * cols + 0] = PQgetvalue(res, i, 0); /* don't free this
|
|
||||||
* afterwards */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Type */
|
/* Type */
|
||||||
#ifdef WIN32
|
printTableAddCell(&cont, PQgetvalue(res, i, 1), false);
|
||||||
cells[i * cols + 1] = mbvalidate(PQgetvalue(res, i, 1), myopt.encoding);
|
|
||||||
#else
|
|
||||||
cells[i * cols + 1] = PQgetvalue(res, i, 1); /* don't free this
|
|
||||||
* either */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Extra: not null and default */
|
/* Extra: not null and default */
|
||||||
if (show_modifiers)
|
if (show_modifiers)
|
||||||
{
|
{
|
||||||
resetPQExpBuffer(&tmpbuf);
|
resetPQExpBuffer(&tmpbuf);
|
||||||
if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
|
if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
|
||||||
appendPQExpBufferStr(&tmpbuf, "not null");
|
appendPQExpBufferStr(&tmpbuf, _("not null"));
|
||||||
|
|
||||||
/* handle "default" here */
|
/* handle "default" here */
|
||||||
/* (note: above we cut off the 'default' string at 128) */
|
/* (note: above we cut off the 'default' string at 128) */
|
||||||
@ -944,24 +923,18 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
{
|
{
|
||||||
if (tmpbuf.len > 0)
|
if (tmpbuf.len > 0)
|
||||||
appendPQExpBufferStr(&tmpbuf, " ");
|
appendPQExpBufferStr(&tmpbuf, " ");
|
||||||
appendPQExpBuffer(&tmpbuf, "default %s",
|
/* translator: default values of column definitions */
|
||||||
|
appendPQExpBuffer(&tmpbuf, _("default %s"),
|
||||||
PQgetvalue(res, i, 2));
|
PQgetvalue(res, i, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WIN32
|
modifiers[i] = pg_strdup(tmpbuf.data);
|
||||||
cells[i * cols + 2] = pg_strdup(mbvalidate(tmpbuf.data, myopt.encoding));
|
printTableAddCell(&cont, modifiers[i], false);
|
||||||
#else
|
|
||||||
cells[i * cols + 2] = pg_strdup(tmpbuf.data);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Description */
|
/* Description */
|
||||||
if (verbose)
|
if (verbose)
|
||||||
#ifdef WIN32
|
printTableAddCell(&cont, PQgetvalue(res, i, 5), false);
|
||||||
cells[i * cols + cols - 1] = mbvalidate(PQgetvalue(res, i, 5), myopt.encoding);
|
|
||||||
#else
|
|
||||||
cells[i * cols + cols - 1] = PQgetvalue(res, i, 5);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make title */
|
/* Make title */
|
||||||
@ -997,7 +970,8 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
schemaname, relationname);
|
schemaname, relationname);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printfPQExpBuffer(&title, _("?%c? \"%s.%s\""),
|
/* untranslated unknown relkind */
|
||||||
|
printfPQExpBuffer(&title, "?%c? \"%s.%s\"",
|
||||||
tableinfo.relkind, schemaname, relationname);
|
tableinfo.relkind, schemaname, relationname);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1033,7 +1007,6 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
char *indamname = PQgetvalue(result, 0, 4);
|
char *indamname = PQgetvalue(result, 0, 4);
|
||||||
char *indtable = PQgetvalue(result, 0, 5);
|
char *indtable = PQgetvalue(result, 0, 5);
|
||||||
char *indpred = PQgetvalue(result, 0, 6);
|
char *indpred = PQgetvalue(result, 0, 6);
|
||||||
int count_footers = 0;
|
|
||||||
|
|
||||||
if (strcmp(indisprimary, "t") == 0)
|
if (strcmp(indisprimary, "t") == 0)
|
||||||
printfPQExpBuffer(&tmpbuf, _("primary key, "));
|
printfPQExpBuffer(&tmpbuf, _("primary key, "));
|
||||||
@ -1056,11 +1029,9 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
if (strcmp(indisvalid, "t") != 0)
|
if (strcmp(indisvalid, "t") != 0)
|
||||||
appendPQExpBuffer(&tmpbuf, _(", invalid"));
|
appendPQExpBuffer(&tmpbuf, _(", invalid"));
|
||||||
|
|
||||||
footers = pg_malloc_zero(4 * sizeof(*footers));
|
printTableAddFooter(&cont, tmpbuf.data);
|
||||||
footers[count_footers++] = pg_strdup(tmpbuf.data);
|
add_tablespace_footer(&cont, tableinfo.relkind,
|
||||||
add_tablespace_footer(tableinfo.relkind, tableinfo.tablespace,
|
tableinfo.tablespace, true);
|
||||||
footers, &count_footers, tmpbuf, true);
|
|
||||||
footers[count_footers] = NULL;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1069,10 +1040,12 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
else if (view_def)
|
else if (view_def)
|
||||||
{
|
{
|
||||||
PGresult *result = NULL;
|
PGresult *result = NULL;
|
||||||
int rule_count = 0;
|
|
||||||
int count_footers = 0;
|
|
||||||
|
|
||||||
/* count rules other than the view rule */
|
/* Footer information about a view */
|
||||||
|
printTableAddFooter(&cont, _("View definition:"));
|
||||||
|
printTableAddFooter(&cont, view_def);
|
||||||
|
|
||||||
|
/* print rules */
|
||||||
if (tableinfo.hasrules)
|
if (tableinfo.hasrules)
|
||||||
{
|
{
|
||||||
printfPQExpBuffer(&buf,
|
printfPQExpBuffer(&buf,
|
||||||
@ -1083,23 +1056,11 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
result = PSQLexec(buf.data, false);
|
result = PSQLexec(buf.data, false);
|
||||||
if (!result)
|
if (!result)
|
||||||
goto error_return;
|
goto error_return;
|
||||||
else
|
|
||||||
rule_count = PQntuples(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Footer information about a view */
|
if (PQntuples(result) > 0)
|
||||||
footers = pg_malloc_zero((rule_count + 3) * sizeof(*footers));
|
|
||||||
footers[count_footers] = pg_malloc(64 + strlen(view_def));
|
|
||||||
snprintf(footers[count_footers], 64 + strlen(view_def),
|
|
||||||
_("View definition:\n%s"), view_def);
|
|
||||||
count_footers++;
|
|
||||||
|
|
||||||
/* print rules */
|
|
||||||
if (rule_count > 0)
|
|
||||||
{
|
{
|
||||||
printfPQExpBuffer(&buf, _("Rules:"));
|
printTableAddFooter(&cont, _("Rules:"));
|
||||||
footers[count_footers++] = pg_strdup(buf.data);
|
for (i = 0; i < PQntuples(result); i++)
|
||||||
for (i = 0; i < rule_count; i++)
|
|
||||||
{
|
{
|
||||||
const char *ruledef;
|
const char *ruledef;
|
||||||
|
|
||||||
@ -1108,35 +1069,19 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
ruledef += 12;
|
ruledef += 12;
|
||||||
|
|
||||||
printfPQExpBuffer(&buf, " %s", ruledef);
|
printfPQExpBuffer(&buf, " %s", ruledef);
|
||||||
|
printTableAddFooter(&cont, buf.data);
|
||||||
footers[count_footers++] = pg_strdup(buf.data);
|
}
|
||||||
}
|
}
|
||||||
PQclear(result);
|
PQclear(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
footers[count_footers] = NULL;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (tableinfo.relkind == 'r')
|
else if (tableinfo.relkind == 'r')
|
||||||
{
|
{
|
||||||
/* Footer information about a table */
|
/* Footer information about a table */
|
||||||
PGresult *result1 = NULL,
|
PGresult *result = NULL;
|
||||||
*result2 = NULL,
|
int tuples = 0;
|
||||||
*result3 = NULL,
|
|
||||||
*result4 = NULL,
|
|
||||||
*result5 = NULL,
|
|
||||||
*result6 = NULL,
|
|
||||||
*result7 = NULL;
|
|
||||||
int check_count = 0,
|
|
||||||
index_count = 0,
|
|
||||||
foreignkey_count = 0,
|
|
||||||
rule_count = 0,
|
|
||||||
trigger_count = 0,
|
|
||||||
referencedby_count = 0,
|
|
||||||
inherits_count = 0;
|
|
||||||
int count_footers = 0;
|
|
||||||
|
|
||||||
/* count indexes */
|
/* print indexes */
|
||||||
if (tableinfo.hasindex)
|
if (tableinfo.hasindex)
|
||||||
{
|
{
|
||||||
printfPQExpBuffer(&buf,
|
printfPQExpBuffer(&buf,
|
||||||
@ -1146,14 +1091,57 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
"WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
|
"WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
|
||||||
"ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname",
|
"ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname",
|
||||||
oid);
|
oid);
|
||||||
result1 = PSQLexec(buf.data, false);
|
result = PSQLexec(buf.data, false);
|
||||||
if (!result1)
|
if (!result)
|
||||||
goto error_return;
|
goto error_return;
|
||||||
else
|
else
|
||||||
index_count = PQntuples(result1);
|
tuples = PQntuples(result);
|
||||||
|
|
||||||
|
if (tuples > 0)
|
||||||
|
{
|
||||||
|
printTableAddFooter(&cont, _("Indexes:"));
|
||||||
|
for (i = 0; i < tuples; i++)
|
||||||
|
{
|
||||||
|
const char *indexdef;
|
||||||
|
const char *usingpos;
|
||||||
|
|
||||||
|
/* untranslated index name */
|
||||||
|
printfPQExpBuffer(&buf, " \"%s\"",
|
||||||
|
PQgetvalue(result, i, 0));
|
||||||
|
|
||||||
|
/* Label as primary key or unique (but not both) */
|
||||||
|
appendPQExpBuffer(&buf,
|
||||||
|
strcmp(PQgetvalue(result, i, 1), "t") == 0
|
||||||
|
? " PRIMARY KEY," :
|
||||||
|
(strcmp(PQgetvalue(result, i, 2), "t") == 0
|
||||||
|
? " UNIQUE,"
|
||||||
|
: ""));
|
||||||
|
/* Everything after "USING" is echoed verbatim */
|
||||||
|
indexdef = PQgetvalue(result, i, 5);
|
||||||
|
usingpos = strstr(indexdef, " USING ");
|
||||||
|
if (usingpos)
|
||||||
|
indexdef = usingpos + 7;
|
||||||
|
|
||||||
|
appendPQExpBuffer(&buf, " %s", indexdef);
|
||||||
|
|
||||||
|
if (strcmp(PQgetvalue(result, i, 3), "t") == 0)
|
||||||
|
appendPQExpBuffer(&buf, " CLUSTER");
|
||||||
|
|
||||||
|
if (strcmp(PQgetvalue(result, i, 4), "t") != 0)
|
||||||
|
appendPQExpBuffer(&buf, " INVALID");
|
||||||
|
|
||||||
|
printTableAddFooter(&cont, buf.data);
|
||||||
|
|
||||||
|
/* Print tablespace of the index on the same line */
|
||||||
|
add_tablespace_footer(&cont, 'i',
|
||||||
|
atooid(PQgetvalue(result, i, 6)),
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PQclear(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* count table (and column) check constraints */
|
/* print table (and column) check constraints */
|
||||||
if (tableinfo.checks)
|
if (tableinfo.checks)
|
||||||
{
|
{
|
||||||
printfPQExpBuffer(&buf,
|
printfPQExpBuffer(&buf,
|
||||||
@ -1162,17 +1150,93 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
"FROM pg_catalog.pg_constraint r\n"
|
"FROM pg_catalog.pg_constraint r\n"
|
||||||
"WHERE r.conrelid = '%s' AND r.contype = 'c' ORDER BY 1",
|
"WHERE r.conrelid = '%s' AND r.contype = 'c' ORDER BY 1",
|
||||||
oid);
|
oid);
|
||||||
result2 = PSQLexec(buf.data, false);
|
result = PSQLexec(buf.data, false);
|
||||||
if (!result2)
|
if (!result)
|
||||||
{
|
|
||||||
PQclear(result1);
|
|
||||||
goto error_return;
|
goto error_return;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
check_count = PQntuples(result2);
|
tuples = PQntuples(result);
|
||||||
|
|
||||||
|
if (tuples > 0)
|
||||||
|
{
|
||||||
|
printTableAddFooter(&cont, _("Check constraints:"));
|
||||||
|
for (i = 0; i < tuples; i++)
|
||||||
|
{
|
||||||
|
/* untranslated contraint name and def */
|
||||||
|
printfPQExpBuffer(&buf, " \"%s\" %s",
|
||||||
|
PQgetvalue(result, i, 0),
|
||||||
|
PQgetvalue(result, i, 1));
|
||||||
|
|
||||||
|
printTableAddFooter(&cont, buf.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PQclear(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* count rules */
|
/* print foreign-key constraints (there are none if no triggers) */
|
||||||
|
if (tableinfo.triggers)
|
||||||
|
{
|
||||||
|
printfPQExpBuffer(&buf,
|
||||||
|
"SELECT conname,\n"
|
||||||
|
" pg_catalog.pg_get_constraintdef(oid, true) as condef\n"
|
||||||
|
"FROM pg_catalog.pg_constraint r\n"
|
||||||
|
"WHERE r.conrelid = '%s' AND r.contype = 'f' ORDER BY 1",
|
||||||
|
oid);
|
||||||
|
result = PSQLexec(buf.data, false);
|
||||||
|
if (!result)
|
||||||
|
goto error_return;
|
||||||
|
else
|
||||||
|
tuples = PQntuples(result);
|
||||||
|
|
||||||
|
if (tuples > 0)
|
||||||
|
{
|
||||||
|
printTableAddFooter(&cont, _("Foreign-key constraints:"));
|
||||||
|
for (i = 0; i < tuples; i++)
|
||||||
|
{
|
||||||
|
/* untranslated constraint name and def */
|
||||||
|
printfPQExpBuffer(&buf, " \"%s\" %s",
|
||||||
|
PQgetvalue(result, i, 0),
|
||||||
|
PQgetvalue(result, i, 1));
|
||||||
|
|
||||||
|
printTableAddFooter(&cont, buf.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PQclear(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* print incoming foreign-key references (none if no triggers) */
|
||||||
|
if (tableinfo.triggers)
|
||||||
|
{
|
||||||
|
printfPQExpBuffer(&buf,
|
||||||
|
"SELECT conname, conrelid::pg_catalog.regclass,\n"
|
||||||
|
" pg_catalog.pg_get_constraintdef(oid, true) as condef\n"
|
||||||
|
"FROM pg_catalog.pg_constraint c\n"
|
||||||
|
"WHERE c.confrelid = '%s' AND c.contype = 'f' ORDER BY 1",
|
||||||
|
oid);
|
||||||
|
result = PSQLexec(buf.data, false);
|
||||||
|
if (!result)
|
||||||
|
goto error_return;
|
||||||
|
else
|
||||||
|
tuples = PQntuples(result);
|
||||||
|
|
||||||
|
if (tuples > 0)
|
||||||
|
{
|
||||||
|
printTableAddFooter(&cont, _("Referenced by:"));
|
||||||
|
for (i = 0; i < tuples; i++)
|
||||||
|
{
|
||||||
|
/* translator: the first %s is a FK name, the following are
|
||||||
|
* a table name and the FK definition */
|
||||||
|
printfPQExpBuffer(&buf, _(" \"%s\" IN %s %s"),
|
||||||
|
PQgetvalue(result, i, 0),
|
||||||
|
PQgetvalue(result, i, 1),
|
||||||
|
PQgetvalue(result, i, 2));
|
||||||
|
|
||||||
|
printTableAddFooter(&cont, buf.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PQclear(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* print rules */
|
||||||
if (tableinfo.hasrules)
|
if (tableinfo.hasrules)
|
||||||
{
|
{
|
||||||
if (pset.sversion < 80300)
|
if (pset.sversion < 80300)
|
||||||
@ -1193,208 +1257,13 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
"WHERE r.ev_class = '%s' ORDER BY 1",
|
"WHERE r.ev_class = '%s' ORDER BY 1",
|
||||||
oid);
|
oid);
|
||||||
}
|
}
|
||||||
result3 = PSQLexec(buf.data, false);
|
result = PSQLexec(buf.data, false);
|
||||||
if (!result3)
|
if (!result)
|
||||||
{
|
|
||||||
PQclear(result1);
|
|
||||||
PQclear(result2);
|
|
||||||
goto error_return;
|
goto error_return;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
rule_count = PQntuples(result3);
|
tuples = PQntuples(result);
|
||||||
}
|
|
||||||
|
|
||||||
/* count triggers (but ignore foreign-key triggers) */
|
if (tuples > 0)
|
||||||
if (tableinfo.triggers)
|
|
||||||
{
|
|
||||||
printfPQExpBuffer(&buf,
|
|
||||||
"SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid), "
|
|
||||||
"t.tgenabled\n"
|
|
||||||
"FROM pg_catalog.pg_trigger t\n"
|
|
||||||
"WHERE t.tgrelid = '%s' "
|
|
||||||
"AND t.tgconstraint = 0\n"
|
|
||||||
"ORDER BY 1",
|
|
||||||
oid);
|
|
||||||
result4 = PSQLexec(buf.data, false);
|
|
||||||
if (!result4)
|
|
||||||
{
|
|
||||||
PQclear(result1);
|
|
||||||
PQclear(result2);
|
|
||||||
PQclear(result3);
|
|
||||||
goto error_return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
trigger_count = PQntuples(result4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* count foreign-key constraints (there are none if no triggers) */
|
|
||||||
if (tableinfo.triggers)
|
|
||||||
{
|
|
||||||
printfPQExpBuffer(&buf,
|
|
||||||
"SELECT conname,\n"
|
|
||||||
" pg_catalog.pg_get_constraintdef(oid, true) as condef\n"
|
|
||||||
"FROM pg_catalog.pg_constraint r\n"
|
|
||||||
"WHERE r.conrelid = '%s' AND r.contype = 'f' ORDER BY 1",
|
|
||||||
oid);
|
|
||||||
result5 = PSQLexec(buf.data, false);
|
|
||||||
if (!result5)
|
|
||||||
{
|
|
||||||
PQclear(result1);
|
|
||||||
PQclear(result2);
|
|
||||||
PQclear(result3);
|
|
||||||
PQclear(result4);
|
|
||||||
goto error_return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
foreignkey_count = PQntuples(result5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* count incoming foreign-key references (none if no triggers) */
|
|
||||||
if (tableinfo.triggers)
|
|
||||||
{
|
|
||||||
printfPQExpBuffer(&buf,
|
|
||||||
"SELECT conname, conrelid::pg_catalog.regclass,\n"
|
|
||||||
" pg_catalog.pg_get_constraintdef(oid, true) as condef\n"
|
|
||||||
"FROM pg_catalog.pg_constraint c\n"
|
|
||||||
"WHERE c.confrelid = '%s' AND c.contype = 'f' ORDER BY 1",
|
|
||||||
oid);
|
|
||||||
result6 = PSQLexec(buf.data, false);
|
|
||||||
if (!result6)
|
|
||||||
{
|
|
||||||
PQclear(result1);
|
|
||||||
PQclear(result2);
|
|
||||||
PQclear(result3);
|
|
||||||
PQclear(result4);
|
|
||||||
PQclear(result5);
|
|
||||||
goto error_return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
referencedby_count = PQntuples(result6);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* count 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);
|
|
||||||
|
|
||||||
result7 = PSQLexec(buf.data, false);
|
|
||||||
if (!result7)
|
|
||||||
{
|
|
||||||
PQclear(result1);
|
|
||||||
PQclear(result2);
|
|
||||||
PQclear(result3);
|
|
||||||
PQclear(result4);
|
|
||||||
PQclear(result5);
|
|
||||||
PQclear(result6);
|
|
||||||
goto error_return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
inherits_count = PQntuples(result7);
|
|
||||||
|
|
||||||
footers = pg_malloc_zero((index_count + check_count + rule_count + trigger_count + foreignkey_count + referencedby_count + inherits_count + 8 + 1) * sizeof(*footers));
|
|
||||||
|
|
||||||
/* print indexes */
|
|
||||||
if (index_count > 0)
|
|
||||||
{
|
|
||||||
printfPQExpBuffer(&buf, _("Indexes:"));
|
|
||||||
footers[count_footers++] = pg_strdup(buf.data);
|
|
||||||
for (i = 0; i < index_count; i++)
|
|
||||||
{
|
|
||||||
const char *indexdef;
|
|
||||||
const char *usingpos;
|
|
||||||
PQExpBufferData tmpbuf;
|
|
||||||
|
|
||||||
/* Output index name */
|
|
||||||
printfPQExpBuffer(&buf, _(" \"%s\""),
|
|
||||||
PQgetvalue(result1, i, 0));
|
|
||||||
|
|
||||||
/* Label as primary key or unique (but not both) */
|
|
||||||
appendPQExpBuffer(&buf,
|
|
||||||
strcmp(PQgetvalue(result1, i, 1), "t") == 0
|
|
||||||
? " PRIMARY KEY," :
|
|
||||||
(strcmp(PQgetvalue(result1, i, 2), "t") == 0
|
|
||||||
? " UNIQUE,"
|
|
||||||
: ""));
|
|
||||||
/* Everything after "USING" is echoed verbatim */
|
|
||||||
indexdef = PQgetvalue(result1, i, 5);
|
|
||||||
usingpos = strstr(indexdef, " USING ");
|
|
||||||
if (usingpos)
|
|
||||||
indexdef = usingpos + 7;
|
|
||||||
|
|
||||||
appendPQExpBuffer(&buf, " %s", indexdef);
|
|
||||||
|
|
||||||
if (strcmp(PQgetvalue(result1, i, 3), "t") == 0)
|
|
||||||
appendPQExpBuffer(&buf, " CLUSTER");
|
|
||||||
|
|
||||||
if (strcmp(PQgetvalue(result1, i, 4), "t") != 0)
|
|
||||||
appendPQExpBuffer(&buf, " INVALID");
|
|
||||||
|
|
||||||
/* Print tablespace of the index on the same line */
|
|
||||||
count_footers += 1;
|
|
||||||
initPQExpBuffer(&tmpbuf);
|
|
||||||
if (add_tablespace_footer('i',
|
|
||||||
atooid(PQgetvalue(result1, i, 6)),
|
|
||||||
footers, &count_footers, tmpbuf, false))
|
|
||||||
{
|
|
||||||
appendPQExpBuffer(&buf, ", ");
|
|
||||||
appendPQExpBuffer(&buf, tmpbuf.data);
|
|
||||||
|
|
||||||
count_footers -= 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
count_footers -= 1;
|
|
||||||
termPQExpBuffer(&tmpbuf);
|
|
||||||
|
|
||||||
footers[count_footers++] = pg_strdup(buf.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* print check constraints */
|
|
||||||
if (check_count > 0)
|
|
||||||
{
|
|
||||||
printfPQExpBuffer(&buf, _("Check constraints:"));
|
|
||||||
footers[count_footers++] = pg_strdup(buf.data);
|
|
||||||
for (i = 0; i < check_count; i++)
|
|
||||||
{
|
|
||||||
printfPQExpBuffer(&buf, _(" \"%s\" %s"),
|
|
||||||
PQgetvalue(result2, i, 0),
|
|
||||||
PQgetvalue(result2, i, 1));
|
|
||||||
|
|
||||||
footers[count_footers++] = pg_strdup(buf.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* print foreign key constraints */
|
|
||||||
if (foreignkey_count > 0)
|
|
||||||
{
|
|
||||||
printfPQExpBuffer(&buf, _("Foreign-key constraints:"));
|
|
||||||
footers[count_footers++] = pg_strdup(buf.data);
|
|
||||||
for (i = 0; i < foreignkey_count; i++)
|
|
||||||
{
|
|
||||||
printfPQExpBuffer(&buf, _(" \"%s\" %s"),
|
|
||||||
PQgetvalue(result5, i, 0),
|
|
||||||
PQgetvalue(result5, i, 1));
|
|
||||||
|
|
||||||
footers[count_footers++] = pg_strdup(buf.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* print incoming foreign-key constraints */
|
|
||||||
if (referencedby_count > 0)
|
|
||||||
{
|
|
||||||
printfPQExpBuffer(&buf, _("Referenced by:"));
|
|
||||||
footers[count_footers++] = pg_strdup(buf.data);
|
|
||||||
for (i = 0; i < referencedby_count; i++)
|
|
||||||
{
|
|
||||||
printfPQExpBuffer(&buf, _(" \"%s\" IN %s %s"),
|
|
||||||
PQgetvalue(result6, i, 0),
|
|
||||||
PQgetvalue(result6, i, 1),
|
|
||||||
PQgetvalue(result6, i, 2));
|
|
||||||
|
|
||||||
footers[count_footers++] = pg_strdup(buf.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* print rules */
|
|
||||||
if (rule_count > 0)
|
|
||||||
{
|
{
|
||||||
bool have_heading;
|
bool have_heading;
|
||||||
int category;
|
int category;
|
||||||
@ -1403,7 +1272,7 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
{
|
{
|
||||||
have_heading = false;
|
have_heading = false;
|
||||||
|
|
||||||
for (i = 0; i < rule_count; i++)
|
for (i = 0; i < tuples; i++)
|
||||||
{
|
{
|
||||||
const char *ruledef;
|
const char *ruledef;
|
||||||
bool list_rule = false;
|
bool list_rule = false;
|
||||||
@ -1411,19 +1280,19 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
switch (category)
|
switch (category)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
if (*PQgetvalue(result3, i, 2) == 'O')
|
if (*PQgetvalue(result, i, 2) == 'O')
|
||||||
list_rule = true;
|
list_rule = true;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (*PQgetvalue(result3, i, 2) == 'D')
|
if (*PQgetvalue(result, i, 2) == 'D')
|
||||||
list_rule = true;
|
list_rule = true;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (*PQgetvalue(result3, i, 2) == 'A')
|
if (*PQgetvalue(result, i, 2) == 'A')
|
||||||
list_rule = true;
|
list_rule = true;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (*PQgetvalue(result3, i, 2) == 'R')
|
if (*PQgetvalue(result, i, 2) == 'R')
|
||||||
list_rule = true;
|
list_rule = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1447,21 +1316,39 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
printfPQExpBuffer(&buf, _("Rules firing on replica only:"));
|
printfPQExpBuffer(&buf, _("Rules firing on replica only:"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
footers[count_footers++] = pg_strdup(buf.data);
|
printTableAddFooter(&cont, buf.data);
|
||||||
have_heading = true;
|
have_heading = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Everything after "CREATE RULE" is echoed verbatim */
|
/* Everything after "CREATE RULE" is echoed verbatim */
|
||||||
ruledef = PQgetvalue(result3, i, 1);
|
ruledef = PQgetvalue(result, i, 1);
|
||||||
ruledef += 12;
|
ruledef += 12;
|
||||||
printfPQExpBuffer(&buf, " %s", ruledef);
|
printfPQExpBuffer(&buf, " %s", ruledef);
|
||||||
footers[count_footers++] = pg_strdup(buf.data);
|
printTableAddFooter(&cont, buf.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PQclear(result);
|
||||||
|
}
|
||||||
|
|
||||||
/* print triggers */
|
/* print triggers (but ignore foreign-key triggers) */
|
||||||
if (trigger_count > 0)
|
if (tableinfo.triggers)
|
||||||
|
{
|
||||||
|
printfPQExpBuffer(&buf,
|
||||||
|
"SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid), "
|
||||||
|
"t.tgenabled\n"
|
||||||
|
"FROM pg_catalog.pg_trigger t\n"
|
||||||
|
"WHERE t.tgrelid = '%s' "
|
||||||
|
"AND t.tgconstraint = 0\n"
|
||||||
|
"ORDER BY 1",
|
||||||
|
oid);
|
||||||
|
result = PSQLexec(buf.data, false);
|
||||||
|
if (!result)
|
||||||
|
goto error_return;
|
||||||
|
else
|
||||||
|
tuples = PQntuples(result);
|
||||||
|
|
||||||
|
if (tuples > 0)
|
||||||
{
|
{
|
||||||
bool have_heading;
|
bool have_heading;
|
||||||
int category;
|
int category;
|
||||||
@ -1474,7 +1361,7 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
for (category = 0; category < 4; category++)
|
for (category = 0; category < 4; category++)
|
||||||
{
|
{
|
||||||
have_heading = false;
|
have_heading = false;
|
||||||
for (i = 0; i < trigger_count; i++)
|
for (i = 0; i < tuples; i++)
|
||||||
{
|
{
|
||||||
bool list_trigger;
|
bool list_trigger;
|
||||||
const char *tgdef;
|
const char *tgdef;
|
||||||
@ -1482,7 +1369,7 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
const char *tgenabled;
|
const char *tgenabled;
|
||||||
|
|
||||||
/* Check if this trigger falls into the current category */
|
/* Check if this trigger falls into the current category */
|
||||||
tgenabled = PQgetvalue(result4, i, 2);
|
tgenabled = PQgetvalue(result, i, 2);
|
||||||
list_trigger = false;
|
list_trigger = false;
|
||||||
switch (category)
|
switch (category)
|
||||||
{
|
{
|
||||||
@ -1525,36 +1412,47 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
footers[count_footers++] = pg_strdup(buf.data);
|
printTableAddFooter(&cont, buf.data);
|
||||||
have_heading = true;
|
have_heading = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Everything after "TRIGGER" is echoed verbatim */
|
/* Everything after "TRIGGER" is echoed verbatim */
|
||||||
tgdef = PQgetvalue(result4, i, 1);
|
tgdef = PQgetvalue(result, i, 1);
|
||||||
usingpos = strstr(tgdef, " TRIGGER ");
|
usingpos = strstr(tgdef, " TRIGGER ");
|
||||||
if (usingpos)
|
if (usingpos)
|
||||||
tgdef = usingpos + 9;
|
tgdef = usingpos + 9;
|
||||||
|
|
||||||
printfPQExpBuffer(&buf, " %s", tgdef);
|
printfPQExpBuffer(&buf, " %s", tgdef);
|
||||||
footers[count_footers++] = pg_strdup(buf.data);
|
printTableAddFooter(&cont, buf.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PQclear(result);
|
||||||
|
}
|
||||||
|
|
||||||
/* print inherits */
|
/* print inherited tables */
|
||||||
for (i = 0; i < inherits_count; i++)
|
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);
|
||||||
|
|
||||||
|
result = PSQLexec(buf.data, false);
|
||||||
|
if (!result)
|
||||||
|
goto error_return;
|
||||||
|
else
|
||||||
|
tuples = PQntuples(result);
|
||||||
|
|
||||||
|
for (i = 0; i < tuples; i++)
|
||||||
{
|
{
|
||||||
const char *s = _("Inherits");
|
const char *s = _("Inherits");
|
||||||
|
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
printfPQExpBuffer(&buf, "%s: %s", s, PQgetvalue(result7, i, 0));
|
printfPQExpBuffer(&buf, "%s: %s", s, PQgetvalue(result, i, 0));
|
||||||
else
|
else
|
||||||
printfPQExpBuffer(&buf, "%*s %s", (int) strlen(s), "", PQgetvalue(result7, i, 0));
|
printfPQExpBuffer(&buf, "%*s %s", (int) strlen(s), "", PQgetvalue(result, i, 0));
|
||||||
if (i < inherits_count - 1)
|
if (i < tuples - 1)
|
||||||
appendPQExpBuffer(&buf, ",");
|
appendPQExpBuffer(&buf, ",");
|
||||||
|
|
||||||
footers[count_footers++] = pg_strdup(buf.data);
|
printTableAddFooter(&cont, buf.data);
|
||||||
}
|
}
|
||||||
|
PQclear(result);
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
{
|
{
|
||||||
@ -1562,51 +1460,31 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
|
|
||||||
printfPQExpBuffer(&buf, "%s: %s", s,
|
printfPQExpBuffer(&buf, "%s: %s", s,
|
||||||
(tableinfo.hasoids ? _("yes") : _("no")));
|
(tableinfo.hasoids ? _("yes") : _("no")));
|
||||||
footers[count_footers++] = pg_strdup(buf.data);
|
printTableAddFooter(&cont, buf.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
add_tablespace_footer(tableinfo.relkind, tableinfo.tablespace,
|
add_tablespace_footer(&cont, tableinfo.relkind, tableinfo.tablespace,
|
||||||
footers, &count_footers, buf, true);
|
true);
|
||||||
/* end of list marker */
|
|
||||||
footers[count_footers] = NULL;
|
|
||||||
|
|
||||||
PQclear(result1);
|
|
||||||
PQclear(result2);
|
|
||||||
PQclear(result3);
|
|
||||||
PQclear(result4);
|
|
||||||
PQclear(result5);
|
|
||||||
PQclear(result6);
|
|
||||||
PQclear(result7);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printTable(title.data, headers,
|
printTable(&cont, pset.queryFout, pset.logfile);
|
||||||
(const char **) cells, (const char **) footers,
|
printTableCleanup(&cont);
|
||||||
"llll", &myopt, pset.queryFout, pset.logfile);
|
|
||||||
|
|
||||||
retval = true;
|
retval = true;
|
||||||
|
|
||||||
error_return:
|
error_return:
|
||||||
|
|
||||||
/* clean up */
|
/* clean up */
|
||||||
|
printTableCleanup(&cont);
|
||||||
termPQExpBuffer(&buf);
|
termPQExpBuffer(&buf);
|
||||||
termPQExpBuffer(&title);
|
termPQExpBuffer(&title);
|
||||||
termPQExpBuffer(&tmpbuf);
|
termPQExpBuffer(&tmpbuf);
|
||||||
|
|
||||||
if (cells)
|
|
||||||
{
|
|
||||||
for (i = 0; i < numrows; i++)
|
|
||||||
{
|
|
||||||
if (show_modifiers)
|
if (show_modifiers)
|
||||||
free(cells[i * cols + 2]);
|
|
||||||
}
|
|
||||||
free(cells);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (footers)
|
|
||||||
{
|
{
|
||||||
for (ptr = footers; *ptr; ptr++)
|
for (ptr = modifiers; *ptr; ptr++)
|
||||||
free(*ptr);
|
free(*ptr);
|
||||||
free(footers);
|
free(modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (view_def)
|
if (view_def)
|
||||||
@ -1618,14 +1496,14 @@ error_return:
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return true if the relation uses non default tablespace;
|
* Add a tablespace description to a footer. If 'newline' is true, it is added
|
||||||
* otherwise return false
|
* in a new line; otherwise it's appended to the current value of the last
|
||||||
|
* footer.
|
||||||
*/
|
*/
|
||||||
static bool
|
static void
|
||||||
add_tablespace_footer(char relkind, Oid tablespace, char **footers,
|
add_tablespace_footer(printTableContent *const cont, char relkind,
|
||||||
int *count, PQExpBufferData buf, bool newline)
|
Oid tablespace, const bool newline)
|
||||||
{
|
{
|
||||||
/* relkinds for which we support tablespaces */
|
/* relkinds for which we support tablespaces */
|
||||||
if (relkind == 'r' || relkind == 'i')
|
if (relkind == 'r' || relkind == 'i')
|
||||||
@ -1636,29 +1514,40 @@ add_tablespace_footer(char relkind, Oid tablespace, char **footers,
|
|||||||
*/
|
*/
|
||||||
if (tablespace != 0)
|
if (tablespace != 0)
|
||||||
{
|
{
|
||||||
PGresult *result1 = NULL;
|
PGresult *result = NULL;
|
||||||
|
PQExpBufferData buf;
|
||||||
|
|
||||||
|
initPQExpBuffer(&buf);
|
||||||
printfPQExpBuffer(&buf, "SELECT spcname FROM pg_tablespace \n"
|
printfPQExpBuffer(&buf, "SELECT spcname FROM pg_tablespace \n"
|
||||||
"WHERE oid = '%u';", tablespace);
|
"WHERE oid = '%u';", tablespace);
|
||||||
result1 = PSQLexec(buf.data, false);
|
result = PSQLexec(buf.data, false);
|
||||||
if (!result1)
|
if (!result)
|
||||||
return false;
|
return;
|
||||||
/* Should always be the case, but.... */
|
/* Should always be the case, but.... */
|
||||||
if (PQntuples(result1) > 0)
|
if (PQntuples(result) > 0)
|
||||||
{
|
{
|
||||||
printfPQExpBuffer(&buf,
|
if (newline)
|
||||||
newline ? _("Tablespace: \"%s\"") : _("tablespace \"%s\""),
|
{
|
||||||
PQgetvalue(result1, 0, 0));
|
/* Add the tablespace as a new footer */
|
||||||
|
printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
|
||||||
footers[(*count)++] = pg_strdup(buf.data);
|
PQgetvalue(result, 0, 0));
|
||||||
|
printTableAddFooter(cont, buf.data);
|
||||||
}
|
}
|
||||||
PQclear(result1);
|
else
|
||||||
|
{
|
||||||
return true;
|
/* Append the tablespace to the latest footer */
|
||||||
|
printfPQExpBuffer(&buf, "%s", cont->footer->data);
|
||||||
|
/* translator: before this string there's an index
|
||||||
|
* description like '"foo_pkey" PRIMARY KEY, btree (a)' */
|
||||||
|
appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
|
||||||
|
PQgetvalue(result, 0, 0));
|
||||||
|
printTableSetFooter(cont, buf.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PQclear(result);
|
||||||
|
termPQExpBuffer(&buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/print.h,v 1.36 2008/05/08 17:04:26 momjian Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/print.h,v 1.37 2008/05/12 22:59:58 alvherre Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef PRINT_H
|
#ifndef PRINT_H
|
||||||
#define PRINT_H
|
#define PRINT_H
|
||||||
@ -11,11 +11,6 @@
|
|||||||
#include "libpq-fe.h"
|
#include "libpq-fe.h"
|
||||||
|
|
||||||
|
|
||||||
extern FILE *PageOutput(int lines, unsigned short int pager);
|
|
||||||
extern void ClosePager(FILE *pagerpipe);
|
|
||||||
|
|
||||||
extern void html_escaped_print(const char *in, FILE *fout);
|
|
||||||
|
|
||||||
enum printFormat
|
enum printFormat
|
||||||
{
|
{
|
||||||
PRINT_NOTHING = 0, /* to make sure someone initializes this */
|
PRINT_NOTHING = 0, /* to make sure someone initializes this */
|
||||||
@ -29,7 +24,7 @@ enum printFormat
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef struct _printTableOpt
|
typedef struct printTableOpt
|
||||||
{
|
{
|
||||||
enum printFormat format; /* one of the above */
|
enum printFormat format; /* one of the above */
|
||||||
bool expanded; /* expanded/vertical output (if supported by
|
bool expanded; /* expanded/vertical output (if supported by
|
||||||
@ -52,25 +47,42 @@ typedef struct _printTableOpt
|
|||||||
int columns; /* target width for wrapped format */
|
int columns; /* target width for wrapped format */
|
||||||
} printTableOpt;
|
} printTableOpt;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Table footers are implemented as a singly-linked list.
|
||||||
|
*
|
||||||
|
* This is so that you don't need to know the number of footers in order to
|
||||||
|
* initialise the printTableContent struct, which is very convenient when
|
||||||
|
* preparing complex footers (as in describeOneTableDetails).
|
||||||
|
*/
|
||||||
|
typedef struct printTableFooter
|
||||||
|
{
|
||||||
|
char *data;
|
||||||
|
struct printTableFooter *next;
|
||||||
|
} printTableFooter;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use this to print just any table in the supported formats.
|
* The table content struct holds all the information which will be displayed
|
||||||
* - title is just any string (NULL is fine)
|
* by printTable().
|
||||||
* - headers is the column headings (NULL ptr terminated). It must be given and
|
|
||||||
* complete since the column count is generated from this.
|
|
||||||
* - cells are the data cells to be printed. Now you know why the correct
|
|
||||||
* column count is important
|
|
||||||
* - footers are lines to be printed below the table
|
|
||||||
* - align is an 'l' or an 'r' for every column, if the output format needs it.
|
|
||||||
* (You must specify this long enough. Otherwise anything could happen.)
|
|
||||||
*/
|
*/
|
||||||
void printTable(const char *title, const char *const * headers,
|
typedef struct printTableContent
|
||||||
const char *const * cells, const char *const * footers,
|
{
|
||||||
const char *align,
|
const printTableOpt *opt;
|
||||||
const printTableOpt *opt, FILE *fout, FILE *flog);
|
const char *title; /* May be NULL */
|
||||||
|
int ncolumns; /* Specified in Init() */
|
||||||
|
int nrows; /* Specified in Init() */
|
||||||
|
const char **headers; /* NULL-terminated array of header strings */
|
||||||
|
const char **header; /* Pointer to the last added header */
|
||||||
|
const char **cells; /* NULL-terminated array of cell content
|
||||||
|
strings */
|
||||||
|
const char **cell; /* Pointer to the last added cell */
|
||||||
|
printTableFooter *footers; /* Pointer to the first footer */
|
||||||
|
printTableFooter *footer; /* Pointer to the last added footer */
|
||||||
|
char *aligns; /* Array of alignment specifiers; 'l' or 'r',
|
||||||
|
one per column */
|
||||||
|
char *align; /* Pointer to the last added alignment */
|
||||||
|
} printTableContent;
|
||||||
|
|
||||||
|
typedef struct printQueryOpt
|
||||||
typedef struct _printQueryOpt
|
|
||||||
{
|
{
|
||||||
printTableOpt topt; /* the options above */
|
printTableOpt topt; /* the options above */
|
||||||
char *nullPrint; /* how to print null entities */
|
char *nullPrint; /* how to print null entities */
|
||||||
@ -82,15 +94,29 @@ typedef struct _printQueryOpt
|
|||||||
const bool *trans_columns; /* trans_columns[i-1] => do gettext on col i */
|
const bool *trans_columns; /* trans_columns[i-1] => do gettext on col i */
|
||||||
} printQueryOpt;
|
} printQueryOpt;
|
||||||
|
|
||||||
/*
|
|
||||||
* Use this to print query results
|
extern FILE *PageOutput(int lines, unsigned short int pager);
|
||||||
*
|
extern void ClosePager(FILE *pagerpipe);
|
||||||
* It calls the printTable above with all the things set straight.
|
|
||||||
*/
|
extern void html_escaped_print(const char *in, FILE *fout);
|
||||||
void printQuery(const PGresult *result, const printQueryOpt *opt,
|
|
||||||
|
extern void printTableInit(printTableContent *const content,
|
||||||
|
const printTableOpt *opt, const char *title,
|
||||||
|
const int ncolumns, const int nrows);
|
||||||
|
extern void printTableAddHeader(printTableContent *const content,
|
||||||
|
const char *header, const bool translate, const char align);
|
||||||
|
extern void printTableAddCell(printTableContent *const content,
|
||||||
|
const char *cell, const bool translate);
|
||||||
|
extern void printTableAddFooter(printTableContent *const content,
|
||||||
|
const char *footer);
|
||||||
|
extern void printTableSetFooter(printTableContent *const content,
|
||||||
|
const char *footer);
|
||||||
|
extern void printTableCleanup(printTableContent *const content);
|
||||||
|
extern void printTable(const printTableContent *cont, FILE *fout, FILE *flog);
|
||||||
|
extern void printQuery(const PGresult *result, const printQueryOpt *opt,
|
||||||
FILE *fout, FILE *flog);
|
FILE *fout, FILE *flog);
|
||||||
|
|
||||||
void setDecimalLocale(void);
|
extern void setDecimalLocale(void);
|
||||||
|
|
||||||
#ifndef __CYGWIN__
|
#ifndef __CYGWIN__
|
||||||
#define DEFAULT_PAGER "more"
|
#define DEFAULT_PAGER "more"
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/scripts/common.c,v 1.31 2008/01/01 19:45:56 momjian Exp $
|
* $PostgreSQL: pgsql/src/bin/scripts/common.c,v 1.32 2008/05/12 22:59:58 alvherre Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -229,6 +229,27 @@ executeMaintenanceCommand(PGconn *conn, const char *query, bool echo)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "Safe" wrapper around strdup(). Pulled from psql/common.c
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
pg_strdup(const char *string)
|
||||||
|
{
|
||||||
|
char *tmp;
|
||||||
|
|
||||||
|
if (!string)
|
||||||
|
{
|
||||||
|
fprintf(stderr, _("pg_strdup: cannot duplicate null pointer (internal error)\n"));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
tmp = strdup(string);
|
||||||
|
if (!tmp)
|
||||||
|
{
|
||||||
|
fprintf(stderr, _("out of memory\n"));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check yes/no answer in a localized way. 1=yes, 0=no, -1=neither.
|
* Check yes/no answer in a localized way. 1=yes, 0=no, -1=neither.
|
||||||
@ -274,7 +295,6 @@ yesno_prompt(const char *question)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SetCancelConn
|
* SetCancelConn
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user