*
* 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 "describe.h"
-#include "dumputils.h"
+#include <ctype.h>
#include "common.h"
-#include "settings.h"
+#include "describe.h"
+#include "dumputils.h"
+#include "mbprint.h"
#include "print.h"
+#include "settings.h"
#include "variables.h"
-#include <ctype.h>
-
-#ifdef WIN32
-/*
- * mbvalidate() is used in function describeOneTableDetails() to make sure
- * all characters of the cells will be printed to the DOS console in a
- * correct way
- */
-#include "mbprint.h"
-#endif
-
static bool describeOneTableDetails(const char *schemaname,
const char *relationname,
const char *oid,
bool verbose);
-static bool add_tablespace_footer(char relkind, Oid tablespace, char **footers,
- int *count, PQExpBufferData buf, bool newline);
+static void add_tablespace_footer(printTableContent *const cont, char relkind,
+ Oid tablespace, const bool newline);
static bool listTSParsersVerbose(const char *pattern);
static bool describeOneTSParser(const char *oid, const char *nspname,
const char *prsname);
PQExpBufferData buf;
PGresult *res = NULL;
printTableOpt myopt = pset.popt.topt;
+ printTableContent cont;
int i;
char *view_def = NULL;
- const char *headers[5];
- char **cells = NULL;
- char **footers = NULL;
+ char *headers[4];
+ char **modifiers = NULL;
char **ptr;
PQExpBufferData title;
PQExpBufferData tmpbuf;
atooid(PQgetvalue(res, 0, 6)) : 0;
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) */
printfPQExpBuffer(&buf, "SELECT a.attname,");
appendPQExpBuffer(&buf, "\n pg_catalog.format_type(a.atttypid, a.atttypmod),"
goto error_return;
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 */
if (tableinfo.relkind == 'v')
{
}
/* 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++)
{
- /* Name */
-#ifdef WIN32
- 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
+ /* Column */
+ printTableAddCell(&cont, PQgetvalue(res, i, 0), false);
/* Type */
-#ifdef WIN32
- 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
+ printTableAddCell(&cont, PQgetvalue(res, i, 1), false);
/* Extra: not null and default */
if (show_modifiers)
{
resetPQExpBuffer(&tmpbuf);
if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
- appendPQExpBufferStr(&tmpbuf, "not null");
+ appendPQExpBufferStr(&tmpbuf, _("not null"));
/* handle "default" here */
/* (note: above we cut off the 'default' string at 128) */
{
if (tmpbuf.len > 0)
appendPQExpBufferStr(&tmpbuf, " ");
- appendPQExpBuffer(&tmpbuf, "default %s",
+ /* translator: default values of column definitions */
+ appendPQExpBuffer(&tmpbuf, _("default %s"),
PQgetvalue(res, i, 2));
}
-#ifdef WIN32
- cells[i * cols + 2] = pg_strdup(mbvalidate(tmpbuf.data, myopt.encoding));
-#else
- cells[i * cols + 2] = pg_strdup(tmpbuf.data);
-#endif
+ modifiers[i] = pg_strdup(tmpbuf.data);
+ printTableAddCell(&cont, modifiers[i], false);
}
/* Description */
if (verbose)
-#ifdef WIN32
- cells[i * cols + cols - 1] = mbvalidate(PQgetvalue(res, i, 5), myopt.encoding);
-#else
- cells[i * cols + cols - 1] = PQgetvalue(res, i, 5);
-#endif
+ printTableAddCell(&cont, PQgetvalue(res, i, 5), false);
}
/* Make title */
schemaname, relationname);
break;
default:
- printfPQExpBuffer(&title, _("?%c? \"%s.%s\""),
+ /* untranslated unknown relkind */
+ printfPQExpBuffer(&title, "?%c? \"%s.%s\"",
tableinfo.relkind, schemaname, relationname);
break;
}
char *indamname = PQgetvalue(result, 0, 4);
char *indtable = PQgetvalue(result, 0, 5);
char *indpred = PQgetvalue(result, 0, 6);
- int count_footers = 0;
if (strcmp(indisprimary, "t") == 0)
printfPQExpBuffer(&tmpbuf, _("primary key, "));
if (strcmp(indisvalid, "t") != 0)
appendPQExpBuffer(&tmpbuf, _(", invalid"));
- footers = pg_malloc_zero(4 * sizeof(*footers));
- footers[count_footers++] = pg_strdup(tmpbuf.data);
- add_tablespace_footer(tableinfo.relkind, tableinfo.tablespace,
- footers, &count_footers, tmpbuf, true);
- footers[count_footers] = NULL;
+ printTableAddFooter(&cont, tmpbuf.data);
+ add_tablespace_footer(&cont, tableinfo.relkind,
+ tableinfo.tablespace, true);
}
else if (view_def)
{
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)
{
printfPQExpBuffer(&buf,
result = PSQLexec(buf.data, false);
if (!result)
goto error_return;
- else
- rule_count = PQntuples(result);
- }
- /* Footer information about a view */
- 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:"));
- footers[count_footers++] = pg_strdup(buf.data);
- for (i = 0; i < rule_count; i++)
+ if (PQntuples(result) > 0)
{
- const char *ruledef;
-
- /* Everything after "CREATE RULE" is echoed verbatim */
- ruledef = PQgetvalue(result, i, 1);
- ruledef += 12;
+ printTableAddFooter(&cont, _("Rules:"));
+ for (i = 0; i < PQntuples(result); i++)
+ {
+ const char *ruledef;
- printfPQExpBuffer(&buf, " %s", ruledef);
+ /* Everything after "CREATE RULE" is echoed verbatim */
+ ruledef = PQgetvalue(result, i, 1);
+ ruledef += 12;
- footers[count_footers++] = pg_strdup(buf.data);
+ printfPQExpBuffer(&buf, " %s", ruledef);
+ printTableAddFooter(&cont, buf.data);
+ }
}
PQclear(result);
}
-
- footers[count_footers] = NULL;
-
}
else if (tableinfo.relkind == 'r')
{
/* Footer information about a table */
- PGresult *result1 = NULL,
- *result2 = NULL,
- *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 */
+ PGresult *result = NULL;
+ int tuples = 0;
+
+ /* print indexes */
if (tableinfo.hasindex)
{
printfPQExpBuffer(&buf,
"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",
oid);
- result1 = PSQLexec(buf.data, false);
- if (!result1)
+ result = PSQLexec(buf.data, false);
+ if (!result)
goto error_return;
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)
{
printfPQExpBuffer(&buf,
"FROM pg_catalog.pg_constraint r\n"
"WHERE r.conrelid = '%s' AND r.contype = 'c' ORDER BY 1",
oid);
- result2 = PSQLexec(buf.data, false);
- if (!result2)
- {
- PQclear(result1);
+ result = PSQLexec(buf.data, false);
+ if (!result)
goto error_return;
- }
else
- check_count = PQntuples(result2);
- }
+ tuples = PQntuples(result);
- /* count rules */
- if (tableinfo.hasrules)
- {
- if (pset.sversion < 80300)
+ if (tuples > 0)
{
- printfPQExpBuffer(&buf,
- "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
- "'O'::char AS ev_enabled\n"
- "FROM pg_catalog.pg_rewrite r\n"
- "WHERE r.ev_class = '%s' ORDER BY 1",
- oid);
- }
- else
- {
- printfPQExpBuffer(&buf,
- "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
- "ev_enabled\n"
- "FROM pg_catalog.pg_rewrite r\n"
- "WHERE r.ev_class = '%s' ORDER BY 1",
- oid);
- }
- result3 = PSQLexec(buf.data, false);
- if (!result3)
- {
- PQclear(result1);
- PQclear(result2);
- goto error_return;
- }
- else
- rule_count = PQntuples(result3);
- }
+ 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));
- /* count triggers (but ignore foreign-key triggers) */
- 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;
+ printTableAddFooter(&cont, buf.data);
+ }
}
- else
- trigger_count = PQntuples(result4);
+ PQclear(result);
}
- /* count foreign-key constraints (there are none if no triggers) */
+ /* print foreign-key constraints (there are none if no triggers) */
if (tableinfo.triggers)
{
printfPQExpBuffer(&buf,
"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);
+ result = PSQLexec(buf.data, false);
+ if (!result)
goto error_return;
- }
else
- foreignkey_count = PQntuples(result5);
+ 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);
}
- /* count incoming foreign-key references (none if no triggers) */
+ /* print incoming foreign-key references (none if no triggers) */
if (tableinfo.triggers)
{
printfPQExpBuffer(&buf,
"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);
+ result = PSQLexec(buf.data, false);
+ if (!result)
goto error_return;
- }
else
- referencedby_count = PQntuples(result6);
- }
+ tuples = PQntuples(result);
- /* 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++)
+ if (tuples > 0)
{
- 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))
+ printTableAddFooter(&cont, _("Referenced by:"));
+ for (i = 0; i < tuples; i++)
{
- appendPQExpBuffer(&buf, ", ");
- appendPQExpBuffer(&buf, tmpbuf.data);
-
- count_footers -= 2;
+ /* 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);
}
- 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);
}
+ PQclear(result);
}
- /* print foreign key constraints */
- if (foreignkey_count > 0)
+ /* print rules */
+ if (tableinfo.hasrules)
{
- printfPQExpBuffer(&buf, _("Foreign-key constraints:"));
- footers[count_footers++] = pg_strdup(buf.data);
- for (i = 0; i < foreignkey_count; i++)
+ if (pset.sversion < 80300)
{
- printfPQExpBuffer(&buf, _(" \"%s\" %s"),
- PQgetvalue(result5, i, 0),
- PQgetvalue(result5, i, 1));
-
- footers[count_footers++] = pg_strdup(buf.data);
+ printfPQExpBuffer(&buf,
+ "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
+ "'O'::char AS ev_enabled\n"
+ "FROM pg_catalog.pg_rewrite r\n"
+ "WHERE r.ev_class = '%s' ORDER BY 1",
+ oid);
}
- }
-
- /* 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++)
+ else
{
- 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);
+ printfPQExpBuffer(&buf,
+ "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
+ "ev_enabled\n"
+ "FROM pg_catalog.pg_rewrite r\n"
+ "WHERE r.ev_class = '%s' ORDER BY 1",
+ oid);
}
- }
-
- /* print rules */
- if (rule_count > 0)
- {
- bool have_heading;
- int category;
+ result = PSQLexec(buf.data, false);
+ if (!result)
+ goto error_return;
+ else
+ tuples = PQntuples(result);
- for (category = 0; category < 4; category++)
+ if (tuples > 0)
{
- have_heading = false;
+ bool have_heading;
+ int category;
- for (i = 0; i < rule_count; i++)
+ for (category = 0; category < 4; category++)
{
- const char *ruledef;
- bool list_rule = false;
+ have_heading = false;
- switch (category)
+ for (i = 0; i < tuples; i++)
{
- case 0:
- if (*PQgetvalue(result3, i, 2) == 'O')
- list_rule = true;
- break;
- case 1:
- if (*PQgetvalue(result3, i, 2) == 'D')
- list_rule = true;
- break;
- case 2:
- if (*PQgetvalue(result3, i, 2) == 'A')
- list_rule = true;
- break;
- case 3:
- if (*PQgetvalue(result3, i, 2) == 'R')
- list_rule = true;
- break;
- }
- if (!list_rule)
- continue;
+ const char *ruledef;
+ bool list_rule = false;
- if (!have_heading)
- {
switch (category)
{
case 0:
- printfPQExpBuffer(&buf, _("Rules:"));
+ if (*PQgetvalue(result, i, 2) == 'O')
+ list_rule = true;
break;
case 1:
- printfPQExpBuffer(&buf, _("Disabled rules:"));
+ if (*PQgetvalue(result, i, 2) == 'D')
+ list_rule = true;
break;
case 2:
- printfPQExpBuffer(&buf, _("Rules firing always:"));
+ if (*PQgetvalue(result, i, 2) == 'A')
+ list_rule = true;
break;
case 3:
- printfPQExpBuffer(&buf, _("Rules firing on replica only:"));
+ if (*PQgetvalue(result, i, 2) == 'R')
+ list_rule = true;
break;
}
- footers[count_footers++] = pg_strdup(buf.data);
- have_heading = true;
- }
+ if (!list_rule)
+ continue;
- /* Everything after "CREATE RULE" is echoed verbatim */
- ruledef = PQgetvalue(result3, i, 1);
- ruledef += 12;
- printfPQExpBuffer(&buf, " %s", ruledef);
- footers[count_footers++] = pg_strdup(buf.data);
+ if (!have_heading)
+ {
+ switch (category)
+ {
+ case 0:
+ printfPQExpBuffer(&buf, _("Rules:"));
+ break;
+ case 1:
+ printfPQExpBuffer(&buf, _("Disabled rules:"));
+ break;
+ case 2:
+ printfPQExpBuffer(&buf, _("Rules firing always:"));
+ break;
+ case 3:
+ printfPQExpBuffer(&buf, _("Rules firing on replica only:"));
+ break;
+ }
+ printTableAddFooter(&cont, buf.data);
+ have_heading = true;
+ }
+
+ /* Everything after "CREATE RULE" is echoed verbatim */
+ ruledef = PQgetvalue(result, i, 1);
+ ruledef += 12;
+ printfPQExpBuffer(&buf, " %s", ruledef);
+ printTableAddFooter(&cont, buf.data);
+ }
}
}
+ PQclear(result);
}
- /* print triggers */
- if (trigger_count > 0)
+ /* print triggers (but ignore foreign-key triggers) */
+ if (tableinfo.triggers)
{
- bool have_heading;
- int category;
-
- /*
- * split the output into 4 different categories. Enabled triggers,
- * disabled triggers and the two special ALWAYS and REPLICA
- * configurations.
- */
- for (category = 0; category < 4; category++)
+ 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)
{
- have_heading = false;
- for (i = 0; i < trigger_count; i++)
+ bool have_heading;
+ int category;
+
+ /*
+ * split the output into 4 different categories. Enabled triggers,
+ * disabled triggers and the two special ALWAYS and REPLICA
+ * configurations.
+ */
+ for (category = 0; category < 4; category++)
{
- bool list_trigger;
- const char *tgdef;
- const char *usingpos;
- const char *tgenabled;
-
- /* Check if this trigger falls into the current category */
- tgenabled = PQgetvalue(result4, i, 2);
- list_trigger = false;
- switch (category)
- {
- case 0:
- if (*tgenabled == 'O' || *tgenabled == 't')
- list_trigger = true;
- break;
- case 1:
- if (*tgenabled == 'D' || *tgenabled == 'f')
- list_trigger = true;
- break;
- case 2:
- if (*tgenabled == 'A')
- list_trigger = true;
- break;
- case 3:
- if (*tgenabled == 'R')
- list_trigger = true;
- break;
- }
- if (list_trigger == false)
- continue;
-
- /* Print the category heading once */
- if (have_heading == false)
+ have_heading = false;
+ for (i = 0; i < tuples; i++)
{
+ bool list_trigger;
+ const char *tgdef;
+ const char *usingpos;
+ const char *tgenabled;
+
+ /* Check if this trigger falls into the current category */
+ tgenabled = PQgetvalue(result, i, 2);
+ list_trigger = false;
switch (category)
{
case 0:
- printfPQExpBuffer(&buf, _("Triggers:"));
+ if (*tgenabled == 'O' || *tgenabled == 't')
+ list_trigger = true;
break;
case 1:
- printfPQExpBuffer(&buf, _("Disabled triggers:"));
+ if (*tgenabled == 'D' || *tgenabled == 'f')
+ list_trigger = true;
break;
case 2:
- printfPQExpBuffer(&buf, _("Triggers firing always:"));
+ if (*tgenabled == 'A')
+ list_trigger = true;
break;
case 3:
- printfPQExpBuffer(&buf, _("Triggers firing on replica only:"));
+ if (*tgenabled == 'R')
+ list_trigger = true;
break;
+ }
+ if (list_trigger == false)
+ continue;
+ /* Print the category heading once */
+ if (have_heading == false)
+ {
+ switch (category)
+ {
+ case 0:
+ printfPQExpBuffer(&buf, _("Triggers:"));
+ break;
+ case 1:
+ printfPQExpBuffer(&buf, _("Disabled triggers:"));
+ break;
+ case 2:
+ printfPQExpBuffer(&buf, _("Triggers firing always:"));
+ break;
+ case 3:
+ printfPQExpBuffer(&buf, _("Triggers firing on replica only:"));
+ break;
+
+ }
+ printTableAddFooter(&cont, buf.data);
+ have_heading = true;
}
- footers[count_footers++] = pg_strdup(buf.data);
- have_heading = true;
- }
- /* Everything after "TRIGGER" is echoed verbatim */
- tgdef = PQgetvalue(result4, i, 1);
- usingpos = strstr(tgdef, " TRIGGER ");
- if (usingpos)
- tgdef = usingpos + 9;
+ /* Everything after "TRIGGER" is echoed verbatim */
+ tgdef = PQgetvalue(result, i, 1);
+ usingpos = strstr(tgdef, " TRIGGER ");
+ if (usingpos)
+ tgdef = usingpos + 9;
- printfPQExpBuffer(&buf, " %s", tgdef);
- footers[count_footers++] = pg_strdup(buf.data);
+ printfPQExpBuffer(&buf, " %s", tgdef);
+ printTableAddFooter(&cont, buf.data);
+ }
}
}
+ PQclear(result);
}
- /* print inherits */
- for (i = 0; i < inherits_count; i++)
+ /* 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);
+
+ result = PSQLexec(buf.data, false);
+ if (!result)
+ goto error_return;
+ else
+ tuples = PQntuples(result);
+
+ for (i = 0; i < tuples; i++)
{
const char *s = _("Inherits");
if (i == 0)
- printfPQExpBuffer(&buf, "%s: %s", s, PQgetvalue(result7, i, 0));
+ printfPQExpBuffer(&buf, "%s: %s", s, PQgetvalue(result, i, 0));
else
- printfPQExpBuffer(&buf, "%*s %s", (int) strlen(s), "", PQgetvalue(result7, i, 0));
- if (i < inherits_count - 1)
+ printfPQExpBuffer(&buf, "%*s %s", (int) strlen(s), "", PQgetvalue(result, i, 0));
+ if (i < tuples - 1)
appendPQExpBuffer(&buf, ",");
- footers[count_footers++] = pg_strdup(buf.data);
+ printTableAddFooter(&cont, buf.data);
}
+ PQclear(result);
if (verbose)
{
printfPQExpBuffer(&buf, "%s: %s", s,
(tableinfo.hasoids ? _("yes") : _("no")));
- footers[count_footers++] = pg_strdup(buf.data);
+ printTableAddFooter(&cont, buf.data);
}
- add_tablespace_footer(tableinfo.relkind, tableinfo.tablespace,
- footers, &count_footers, buf, true);
- /* end of list marker */
- footers[count_footers] = NULL;
-
- PQclear(result1);
- PQclear(result2);
- PQclear(result3);
- PQclear(result4);
- PQclear(result5);
- PQclear(result6);
- PQclear(result7);
+ add_tablespace_footer(&cont, tableinfo.relkind, tableinfo.tablespace,
+ true);
}
- printTable(title.data, headers,
- (const char **) cells, (const char **) footers,
- "llll", &myopt, pset.queryFout, pset.logfile);
+ printTable(&cont, pset.queryFout, pset.logfile);
+ printTableCleanup(&cont);
retval = true;
error_return:
/* clean up */
+ printTableCleanup(&cont);
termPQExpBuffer(&buf);
termPQExpBuffer(&title);
termPQExpBuffer(&tmpbuf);
- if (cells)
- {
- for (i = 0; i < numrows; i++)
- {
- if (show_modifiers)
- free(cells[i * cols + 2]);
- }
- free(cells);
- }
-
- if (footers)
+ if (show_modifiers)
{
- for (ptr = footers; *ptr; ptr++)
+ for (ptr = modifiers; *ptr; ptr++)
free(*ptr);
- free(footers);
+ free(modifiers);
}
if (view_def)
return retval;
}
-
/*
- * Return true if the relation uses non default tablespace;
- * otherwise return false
+ * Add a tablespace description to a footer. If 'newline' is true, it is added
+ * in a new line; otherwise it's appended to the current value of the last
+ * footer.
*/
-static bool
-add_tablespace_footer(char relkind, Oid tablespace, char **footers,
- int *count, PQExpBufferData buf, bool newline)
+static void
+add_tablespace_footer(printTableContent *const cont, char relkind,
+ Oid tablespace, const bool newline)
{
/* relkinds for which we support tablespaces */
if (relkind == 'r' || relkind == 'i')
*/
if (tablespace != 0)
{
- PGresult *result1 = NULL;
+ PGresult *result = NULL;
+ PQExpBufferData buf;
+ initPQExpBuffer(&buf);
printfPQExpBuffer(&buf, "SELECT spcname FROM pg_tablespace \n"
"WHERE oid = '%u';", tablespace);
- result1 = PSQLexec(buf.data, false);
- if (!result1)
- return false;
+ result = PSQLexec(buf.data, false);
+ if (!result)
+ return;
/* Should always be the case, but.... */
- if (PQntuples(result1) > 0)
+ if (PQntuples(result) > 0)
{
- printfPQExpBuffer(&buf,
- newline ? _("Tablespace: \"%s\"") : _("tablespace \"%s\""),
- PQgetvalue(result1, 0, 0));
-
- footers[(*count)++] = pg_strdup(buf.data);
+ if (newline)
+ {
+ /* Add the tablespace as a new footer */
+ printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
+ PQgetvalue(result, 0, 0));
+ printTableAddFooter(cont, buf.data);
+ }
+ else
+ {
+ /* 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(result1);
-
- return true;
+ PQclear(result);
+ termPQExpBuffer(&buf);
}
}
-
- return false;
}
/*
*
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.99 2008/05/10 03:31:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.100 2008/05/12 22:59:58 alvherre Exp $
*/
#include "postgres_fe.h"
-#include "print.h"
-#include "catalog/pg_type.h"
-
#include <math.h>
#include <signal.h>
#include <unistd.h>
#include <locale.h>
+#include "catalog/pg_type.h"
#include "pqsignal.h"
+#include "common.h"
#include "mbprint.h"
+#include "print.h"
/*
* We define the cancel_pressed flag in this file, rather than common.c where
static void
-print_unaligned_text(const char *title, const char *const * headers,
- const char *const * cells, const char *const * footers,
- const char *opt_align, const printTableOpt *opt,
- FILE *fout)
+print_unaligned_text(const printTableContent *cont, FILE *fout)
{
- const char *opt_fieldsep = opt->fieldSep;
- const char *opt_recordsep = opt->recordSep;
- bool opt_tuples_only = opt->tuples_only;
- bool opt_numeric_locale = opt->numericLocale;
- unsigned int col_count = 0;
+ const char *opt_fieldsep = cont->opt->fieldSep;
+ const char *opt_recordsep = cont->opt->recordSep;
+ bool opt_tuples_only = cont->opt->tuples_only;
+ bool opt_numeric_locale = cont->opt->numericLocale;
unsigned int i;
const char *const * ptr;
bool need_recordsep = false;
if (!opt_recordsep)
opt_recordsep = "";
- /* count columns */
- for (ptr = headers; *ptr; ptr++)
- col_count++;
-
- if (opt->start_table)
+ if (cont->opt->start_table)
{
/* print title */
- if (!opt_tuples_only && title)
- fprintf(fout, "%s%s", title, opt_recordsep);
+ if (!opt_tuples_only && cont->title)
+ fprintf(fout, "%s%s", cont->title, opt_recordsep);
/* print headers */
if (!opt_tuples_only)
{
- for (ptr = headers; *ptr; ptr++)
+ for (ptr = cont->headers; *ptr; ptr++)
{
- if (ptr != headers)
+ if (ptr != cont->headers)
fputs(opt_fieldsep, fout);
fputs(*ptr, fout);
}
need_recordsep = true;
/* print cells */
- for (i = 0, ptr = cells; *ptr; i++, ptr++)
+ for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
{
if (need_recordsep)
{
if (cancel_pressed)
break;
}
- if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
+ if (cont->aligns[i % cont->ncolumns] == 'r' && opt_numeric_locale)
{
char *my_cell = format_numeric_locale(*ptr);
else
fputs(*ptr, fout);
- if ((i + 1) % col_count)
+ if ((i + 1) % cont->ncolumns)
fputs(opt_fieldsep, fout);
else
need_recordsep = true;
}
/* print footers */
- if (opt->stop_table)
+ if (cont->opt->stop_table)
{
- if (!opt_tuples_only && footers && !cancel_pressed)
- for (ptr = footers; *ptr; ptr++)
+ if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
+ {
+ printTableFooter *f;
+
+ for (f = cont->footers; f; f = f->next)
{
if (need_recordsep)
{
fputs(opt_recordsep, fout);
need_recordsep = false;
}
- fputs(*ptr, fout);
+ fputs(f->data, fout);
need_recordsep = true;
}
-
+ }
/* the last record needs to be concluded with a newline */
if (need_recordsep)
fputc('\n', fout);
static void
-print_unaligned_vertical(const char *title, const char *const * headers,
- const char *const * cells,
- const char *const * footers, const char *opt_align,
- const printTableOpt *opt, FILE *fout)
+print_unaligned_vertical(const printTableContent *cont, FILE *fout)
{
- const char *opt_fieldsep = opt->fieldSep;
- const char *opt_recordsep = opt->recordSep;
- bool opt_tuples_only = opt->tuples_only;
- bool opt_numeric_locale = opt->numericLocale;
- unsigned int col_count = 0;
+ const char *opt_fieldsep = cont->opt->fieldSep;
+ const char *opt_recordsep = cont->opt->recordSep;
+ bool opt_tuples_only = cont->opt->tuples_only;
+ bool opt_numeric_locale = cont->opt->numericLocale;
unsigned int i;
const char *const * ptr;
bool need_recordsep = false;
if (!opt_recordsep)
opt_recordsep = "";
- /* count columns */
- for (ptr = headers; *ptr; ptr++)
- col_count++;
-
- if (opt->start_table)
+ if (cont->opt->start_table)
{
/* print title */
- if (!opt_tuples_only && title)
+ if (!opt_tuples_only && cont->title)
{
- fputs(title, fout);
+ fputs(cont->title, fout);
need_recordsep = true;
}
}
need_recordsep = true;
/* print records */
- for (i = 0, ptr = cells; *ptr; i++, ptr++)
+ for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
{
if (need_recordsep)
{
break;
}
- fputs(headers[i % col_count], fout);
+ fputs(cont->headers[i % cont->ncolumns], fout);
fputs(opt_fieldsep, fout);
- if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
+ if (cont->aligns[i % cont->ncolumns] == 'r' && opt_numeric_locale)
{
char *my_cell = format_numeric_locale(*ptr);
else
fputs(*ptr, fout);
- if ((i + 1) % col_count)
+ if ((i + 1) % cont->ncolumns)
fputs(opt_recordsep, fout);
else
need_recordsep = true;
}
- if (opt->stop_table)
+ if (cont->opt->stop_table)
{
/* print footers */
- if (!opt_tuples_only && footers && *footers && !cancel_pressed)
+ if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
{
+ printTableFooter *f;
+
fputs(opt_recordsep, fout);
- for (ptr = footers; *ptr; ptr++)
+ for (f = cont->footers; f; f = f->next)
{
fputs(opt_recordsep, fout);
- fputs(*ptr, fout);
+ fputs(f->data, fout);
}
}
/* draw "line" */
static void
-_print_horizontal_line(const unsigned int col_count, const unsigned int *widths, unsigned short border, FILE *fout)
+_print_horizontal_line(const unsigned int ncolumns, const unsigned int *widths,
+ unsigned short border, FILE *fout)
{
unsigned int i,
j;
else if (border == 2)
fputs("+-", fout);
- for (i = 0; i < col_count; i++)
+ for (i = 0; i < ncolumns; i++)
{
for (j = 0; j < widths[i]; j++)
fputc('-', fout);
- if (i < col_count - 1)
+ if (i < ncolumns - 1)
{
if (border == 0)
fputc(' ', fout);
* Print pretty boxes around cells.
*/
static void
-print_aligned_text(const char *title, const char *const * headers,
- const char *const * cells, const char *const * footers,
- const char *opt_align, const printTableOpt *opt,
- bool is_pager, FILE *fout)
+print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
{
- bool opt_tuples_only = opt->tuples_only;
- bool opt_numeric_locale = opt->numericLocale;
- int encoding = opt->encoding;
- unsigned short opt_border = opt->border;
+ bool opt_tuples_only = cont->opt->tuples_only;
+ bool opt_numeric_locale = cont->opt->numericLocale;
+ int encoding = cont->opt->encoding;
+ unsigned short opt_border = cont->opt->border;
unsigned int col_count = 0, cell_count = 0;
if (opt_border > 2)
opt_border = 2;
- /* count columns */
- for (ptr = headers; *ptr; ptr++)
- col_count++;
-
- if (col_count > 0)
+ if (cont->ncolumns > 0)
{
+ col_count = cont->ncolumns;
width_header = pg_local_calloc(col_count, sizeof(*width_header));
width_average = pg_local_calloc(col_count, sizeof(*width_average));
max_width = pg_local_calloc(col_count, sizeof(*max_width));
nl_lines,
bytes_required;
- pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding,
- &width, &nl_lines, &bytes_required);
+ pg_wcssize((unsigned char *) cont->headers[i], strlen(cont->headers[i]),
+ encoding, &width, &nl_lines, &bytes_required);
if (width > max_width[i])
max_width[i] = width;
if (nl_lines > max_nl_lines[i])
}
/* scan all cells, find maximum width, compute cell_count */
- for (i = 0, ptr = cells; *ptr; ptr++, i++, cell_count++)
+ for (i = 0, ptr = cont->cells; *ptr; ptr++, i++, cell_count++)
{
int width,
nl_lines,
/* Get width, ignore nl_lines */
pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding,
&width, &nl_lines, &bytes_required);
- if (opt_numeric_locale && opt_align[i % col_count] == 'r')
+ if (opt_numeric_locale && cont->aligns[i % col_count] == 'r')
{
width += additional_numeric_locale_len(*ptr);
bytes_required += additional_numeric_locale_len(*ptr);
for (i = 0; i < col_count; i++)
width_wrap[i] = max_width[i];
- if (opt->format == PRINT_WRAPPED)
+ if (cont->opt->format == PRINT_WRAPPED)
{
/*
* Choose target output width: \pset columns, or $COLUMNS, or ioctl
*/
- if (opt->columns > 0)
- output_columns = opt->columns;
+ if (cont->opt->columns > 0)
+ output_columns = cont->opt->columns;
else if ((fout == stdout && isatty(fileno(stdout))) || is_pager)
{
- if (opt->env_columns > 0)
- output_columns = opt->env_columns;
+ if (cont->opt->env_columns > 0)
+ output_columns = cont->opt->env_columns;
#ifdef TIOCGWINSZ
else
{
}
/* time to output */
- if (opt->start_table)
+ if (cont->opt->start_table)
{
/* print title */
- if (title && !opt_tuples_only)
+ if (cont->title && !opt_tuples_only)
{
int width, height;
- pg_wcssize((unsigned char *) title, strlen(title), encoding,
- &width, &height, NULL);
+ pg_wcssize((unsigned char *) cont->title, strlen(cont->title),
+ encoding, &width, &height, NULL);
if (width >= width_total)
- fprintf(fout, "%s\n", title); /* Aligned */
+ /* Aligned */
+ fprintf(fout, "%s\n", cont->title);
else
- fprintf(fout, "%-*s%s\n", (width_total - width) / 2, "", title); /* Centered */
+ /* Centered */
+ fprintf(fout, "%-*s%s\n", (width_total - width) / 2, "",
+ cont->title);
}
/* print headers */
_print_horizontal_line(col_count, width_wrap, opt_border, fout);
for (i = 0; i < col_count; i++)
- pg_wcsformat((unsigned char *) headers[i], strlen(headers[i]),
- encoding, col_lineptrs[i], max_nl_lines[i]);
+ pg_wcsformat((unsigned char *) cont->headers[i],
+ strlen(cont->headers[i]), encoding,
+ col_lineptrs[i], max_nl_lines[i]);
more_col_wrapping = col_count;
curr_nl_line = 0;
else if (opt_border == 1)
fputc(curr_nl_line ? '+' : ' ', fout);
- for (i = 0; i < col_count; i++)
+ for (i = 0; i < cont->ncolumns; i++)
{
unsigned int nbspace;
}
/* print cells, one loop per row */
- for (i = 0, ptr = cells; *ptr; i += col_count, ptr += col_count)
+ for (i = 0, ptr = cont->cells; *ptr; i += col_count, ptr += col_count)
{
bool more_lines;
col_lineptrs[j], max_nl_lines[j]);
curr_nl_line[j] = 0;
- if (opt_numeric_locale && opt_align[j % col_count] == 'r')
+ if (opt_numeric_locale && cont->aligns[j % col_count] == 'r')
{
char *my_cell;
if (chars_to_output > width_wrap[j])
chars_to_output = width_wrap[j];
- if (opt_align[j] == 'r') /* Right aligned cell */
+ if (cont->aligns[j] == 'r') /* Right aligned cell */
{
/* spaces first */
fprintf(fout, "%*s", width_wrap[j] - chars_to_output, "");
} while (more_lines);
}
- if (opt->stop_table)
+ if (cont->opt->stop_table)
{
if (opt_border == 2 && !cancel_pressed)
_print_horizontal_line(col_count, width_wrap, opt_border, fout);
/* print footers */
- if (footers && !opt_tuples_only && !cancel_pressed)
- for (ptr = footers; *ptr; ptr++)
- fprintf(fout, "%s\n", *ptr);
+ if (cont->footers && !opt_tuples_only && !cancel_pressed)
+ {
+ printTableFooter *f;
+
+ for (f = cont->footers; f; f = f->next)
+ fprintf(fout, "%s\n", f->data);
+ }
/*
* for some reason MinGW (and MSVC) outputs an extra newline, so this
static void
-print_aligned_vertical(const char *title, const char *const * headers,
- const char *const * cells, const char *const * footers,
- const char *opt_align, const printTableOpt *opt,
- FILE *fout)
+print_aligned_vertical(const printTableContent *cont, FILE *fout)
{
- bool opt_tuples_only = opt->tuples_only;
- bool opt_numeric_locale = opt->numericLocale;
- unsigned short opt_border = opt->border;
- int encoding = opt->encoding;
- unsigned int col_count = 0;
- unsigned long record = opt->prior_records + 1;
+ bool opt_tuples_only = cont->opt->tuples_only;
+ bool opt_numeric_locale = cont->opt->numericLocale;
+ unsigned short opt_border = cont->opt->border;
+ int encoding = cont->opt->encoding;
+ unsigned long record = cont->opt->prior_records + 1;
const char *const * ptr;
unsigned int i,
hwidth = 0,
hformatsize = 0,
dformatsize = 0;
char *divider;
- unsigned int cell_count = 0;
struct lineptr *hlineptr,
*dlineptr;
if (opt_border > 2)
opt_border = 2;
- if (cells[0] == NULL && opt->start_table && opt->stop_table)
+ if (cont->cells[0] == NULL && cont->opt->start_table &&
+ cont->opt->stop_table)
{
fprintf(fout, _("(No rows)\n"));
return;
}
- /* count columns */
- for (ptr = headers; *ptr; ptr++)
- col_count++;
-
/* Find the maximum dimensions for the headers */
- for (i = 0; i < col_count; i++)
+ for (i = 0; i < cont->ncolumns; i++)
{
int width,
height,
fs;
- pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding,
- &width, &height, &fs);
+ pg_wcssize((unsigned char *) cont->headers[i], strlen(cont->headers[i]),
+ encoding, &width, &height, &fs);
if (width > hwidth)
hwidth = width;
if (height > hheight)
hformatsize = fs;
}
- /* Count cells, find their lengths */
- for (ptr = cells; *ptr; ptr++)
- cell_count++;
-
/* find longest data cell */
- for (i = 0, ptr = cells; *ptr; ptr++, i++)
+ for (i = 0, ptr = cont->cells; *ptr; ptr++, i++)
{
int numeric_locale_len;
int width,
height,
fs;
- if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
+ if (cont->aligns[i % cont->ncolumns] == 'r' && opt_numeric_locale)
numeric_locale_len = additional_numeric_locale_len(*ptr);
else
numeric_locale_len = 0;
if (opt_border == 2)
strcat(divider, "-+");
- if (opt->start_table)
+ if (cont->opt->start_table)
{
/* print title */
- if (!opt_tuples_only && title)
- fprintf(fout, "%s\n", title);
+ if (!opt_tuples_only && cont->title)
+ fprintf(fout, "%s\n", cont->title);
}
/* print records */
- for (i = 0, ptr = cells; *ptr; i++, ptr++)
+ for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
{
int line_count,
dcomplete,
hcomplete;
- if (i % col_count == 0)
+ if (i % cont->ncolumns == 0)
{
if (cancel_pressed)
break;
fprintf(fout, "%.*s%s\n", opt_border, divider, record_str);
else
{
- char *div_copy = strdup(divider);
-
- if (!div_copy)
- {
- fprintf(stderr, _("out of memory\n"));
- exit(EXIT_FAILURE);
- }
+ char *div_copy = pg_strdup(divider);
strncpy(div_copy + opt_border, record_str, record_str_len);
fprintf(fout, "%s\n", div_copy);
free(div_copy);
}
}
- else if (i != 0 || !opt->start_table || opt_border == 2)
+ else if (i != 0 || !cont->opt->start_table || opt_border == 2)
fprintf(fout, "%s\n", divider);
}
/* Format the header */
- pg_wcsformat((unsigned char *) headers[i % col_count],
- strlen(headers[i % col_count]),
+ pg_wcsformat((unsigned char *) cont->headers[i % cont->ncolumns],
+ strlen(cont->headers[i % cont->ncolumns]),
encoding, hlineptr, hheight);
/* Format the data */
pg_wcsformat((unsigned char *) *ptr, strlen(*ptr), encoding,
if (!dcomplete)
{
- if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
+ if (cont->aligns[i % cont->ncolumns] == 'r' && opt_numeric_locale)
{
char *my_cell = format_numeric_locale((char *) dlineptr[line_count].ptr);
}
}
- if (opt->stop_table)
+ if (cont->opt->stop_table)
{
if (opt_border == 2 && !cancel_pressed)
fprintf(fout, "%s\n", divider);
/* print footers */
- if (!opt_tuples_only && footers && *footers && !cancel_pressed)
+ if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
{
+ printTableFooter *f;
+
if (opt_border < 2)
fputc('\n', fout);
- for (ptr = footers; *ptr; ptr++)
- fprintf(fout, "%s\n", *ptr);
+ for (f = cont->footers; f; f = f->next)
+ fprintf(fout, "%s\n", f->data);
}
fputc('\n', fout);
static void
-print_html_text(const char *title, const char *const * headers,
- const char *const * cells, const char *const * footers,
- const char *opt_align, const printTableOpt *opt,
- FILE *fout)
+print_html_text(const printTableContent *cont, FILE *fout)
{
- bool opt_tuples_only = opt->tuples_only;
- bool opt_numeric_locale = opt->numericLocale;
- unsigned short opt_border = opt->border;
- const char *opt_table_attr = opt->tableAttr;
- unsigned int col_count = 0;
+ bool opt_tuples_only = cont->opt->tuples_only;
+ bool opt_numeric_locale = cont->opt->numericLocale;
+ unsigned short opt_border = cont->opt->border;
+ const char *opt_table_attr = cont->opt->tableAttr;
unsigned int i;
const char *const * ptr;
if (cancel_pressed)
return;
- /* count columns */
- for (ptr = headers; *ptr; ptr++)
- col_count++;
-
- if (opt->start_table)
+ if (cont->opt->start_table)
{
fprintf(fout, "<table border=\"%d\"", opt_border);
if (opt_table_attr)
fputs(">\n", fout);
/* print title */
- if (!opt_tuples_only && title)
+ if (!opt_tuples_only && cont->title)
{
fputs(" <caption>", fout);
- html_escaped_print(title, fout);
+ html_escaped_print(cont->title, fout);
fputs("</caption>\n", fout);
}
if (!opt_tuples_only)
{
fputs(" <tr>\n", fout);
- for (ptr = headers; *ptr; ptr++)
+ for (ptr = cont->headers; *ptr; ptr++)
{
fputs(" <th align=\"center\">", fout);
html_escaped_print(*ptr, fout);
}
/* print cells */
- for (i = 0, ptr = cells; *ptr; i++, ptr++)
+ for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
{
- if (i % col_count == 0)
+ if (i % cont->ncolumns == 0)
{
if (cancel_pressed)
break;
fputs(" <tr valign=\"top\">\n", fout);
}
- fprintf(fout, " <td align=\"%s\">", opt_align[(i) % col_count] == 'r' ? "right" : "left");
+ fprintf(fout, " <td align=\"%s\">", cont->aligns[(i) % cont->ncolumns] == 'r' ? "right" : "left");
/* is string only whitespace? */
if ((*ptr)[strspn(*ptr, " \t")] == '\0')
fputs(" ", fout);
- else if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
+ else if (cont->aligns[i % cont->ncolumns] == 'r' && opt_numeric_locale)
{
char *my_cell = format_numeric_locale(*ptr);
fputs("</td>\n", fout);
- if ((i + 1) % col_count == 0)
+ if ((i + 1) % cont->ncolumns == 0)
fputs(" </tr>\n", fout);
}
- if (opt->stop_table)
+ if (cont->opt->stop_table)
{
fputs("</table>\n", fout);
/* print footers */
- if (!opt_tuples_only && footers && *footers && !cancel_pressed)
+ if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
{
+ printTableFooter *f;
+
fputs("<p>", fout);
- for (ptr = footers; *ptr; ptr++)
+ for (f = cont->footers; f; f = f->next)
{
- html_escaped_print(*ptr, fout);
+ html_escaped_print(f->data, fout);
fputs("<br />\n", fout);
}
fputs("</p>", fout);
static void
-print_html_vertical(const char *title, const char *const * headers,
- const char *const * cells, const char *const * footers,
- const char *opt_align, const printTableOpt *opt,
- FILE *fout)
+print_html_vertical(const printTableContent *cont, FILE *fout)
{
- bool opt_tuples_only = opt->tuples_only;
- bool opt_numeric_locale = opt->numericLocale;
- unsigned short opt_border = opt->border;
- const char *opt_table_attr = opt->tableAttr;
- unsigned int col_count = 0;
- unsigned long record = opt->prior_records + 1;
+ bool opt_tuples_only = cont->opt->tuples_only;
+ bool opt_numeric_locale = cont->opt->numericLocale;
+ unsigned short opt_border = cont->opt->border;
+ const char *opt_table_attr = cont->opt->tableAttr;
+ unsigned long record = cont->opt->prior_records + 1;
unsigned int i;
const char *const * ptr;
if (cancel_pressed)
return;
- /* count columns */
- for (ptr = headers; *ptr; ptr++)
- col_count++;
-
- if (opt->start_table)
+ if (cont->opt->start_table)
{
fprintf(fout, "<table border=\"%d\"", opt_border);
if (opt_table_attr)
fputs(">\n", fout);
/* print title */
- if (!opt_tuples_only && title)
+ if (!opt_tuples_only && cont->title)
{
fputs(" <caption>", fout);
- html_escaped_print(title, fout);
+ html_escaped_print(cont->title, fout);
fputs("</caption>\n", fout);
}
}
/* print records */
- for (i = 0, ptr = cells; *ptr; i++, ptr++)
+ for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
{
- if (i % col_count == 0)
+ if (i % cont->ncolumns == 0)
{
if (cancel_pressed)
break;
}
fputs(" <tr valign=\"top\">\n"
" <th>", fout);
- html_escaped_print(headers[i % col_count], fout);
+ html_escaped_print(cont->headers[i % cont->ncolumns], fout);
fputs("</th>\n", fout);
- fprintf(fout, " <td align=\"%s\">", opt_align[i % col_count] == 'r' ? "right" : "left");
+ fprintf(fout, " <td align=\"%s\">", cont->aligns[i % cont->ncolumns] == 'r' ? "right" : "left");
/* is string only whitespace? */
if ((*ptr)[strspn(*ptr, " \t")] == '\0')
fputs(" ", fout);
- else if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
+ else if (cont->aligns[i % cont->ncolumns] == 'r' && opt_numeric_locale)
{
char *my_cell = format_numeric_locale(*ptr);
fputs("</td>\n </tr>\n", fout);
}
- if (opt->stop_table)
+ if (cont->opt->stop_table)
{
fputs("</table>\n", fout);
/* print footers */
- if (!opt_tuples_only && footers && *footers && !cancel_pressed)
+ if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
{
+ printTableFooter *f;
+
fputs("<p>", fout);
- for (ptr = footers; *ptr; ptr++)
+ for (f = cont->footers; f; f = f->next)
{
- html_escaped_print(*ptr, fout);
+ html_escaped_print(f->data, fout);
fputs("<br />\n", fout);
}
fputs("</p>", fout);
static void
-print_latex_text(const char *title, const char *const * headers,
- const char *const * cells, const char *const * footers,
- const char *opt_align, const printTableOpt *opt,
- FILE *fout)
+print_latex_text(const printTableContent *cont, FILE *fout)
{
- bool opt_tuples_only = opt->tuples_only;
- bool opt_numeric_locale = opt->numericLocale;
- unsigned short opt_border = opt->border;
- unsigned int col_count = 0;
+ bool opt_tuples_only = cont->opt->tuples_only;
+ bool opt_numeric_locale = cont->opt->numericLocale;
+ unsigned short opt_border = cont->opt->border;
unsigned int i;
const char *const * ptr;
if (opt_border > 2)
opt_border = 2;
- /* count columns */
- for (ptr = headers; *ptr; ptr++)
- col_count++;
-
- if (opt->start_table)
+ if (cont->opt->start_table)
{
/* print title */
- if (!opt_tuples_only && title)
+ if (!opt_tuples_only && cont->title)
{
fputs("\\begin{center}\n", fout);
- latex_escaped_print(title, fout);
+ latex_escaped_print(cont->title, fout);
fputs("\n\\end{center}\n\n", fout);
}
if (opt_border == 2)
fputs("| ", fout);
- for (i = 0; i < col_count; i++)
+ for (i = 0; i < cont->ncolumns; i++)
{
- fputc(*(opt_align + i), fout);
- if (opt_border != 0 && i < col_count - 1)
+ fputc(*(cont->aligns + i), fout);
+ if (opt_border != 0 && i < cont->ncolumns - 1)
fputs(" | ", fout);
}
if (opt_border == 2)
/* print headers */
if (!opt_tuples_only)
{
- for (i = 0, ptr = headers; i < col_count; i++, ptr++)
+ for (i = 0, ptr = cont->headers; i < cont->ncolumns; i++, ptr++)
{
if (i != 0)
fputs(" & ", fout);
}
/* print cells */
- for (i = 0, ptr = cells; *ptr; i++, ptr++)
+ for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
{
if (opt_numeric_locale)
{
else
latex_escaped_print(*ptr, fout);
- if ((i + 1) % col_count == 0)
+ if ((i + 1) % cont->ncolumns == 0)
{
fputs(" \\\\\n", fout);
if (cancel_pressed)
fputs(" & ", fout);
}
- if (opt->stop_table)
+ if (cont->opt->stop_table)
{
if (opt_border == 2)
fputs("\\hline\n", fout);
fputs("\\end{tabular}\n\n\\noindent ", fout);
/* print footers */
- if (footers && !opt_tuples_only && !cancel_pressed)
+ if (cont->footers && !opt_tuples_only && !cancel_pressed)
{
- for (ptr = footers; *ptr; ptr++)
+ printTableFooter *f;
+
+ for (f = cont->footers; f; f = f->next)
{
- latex_escaped_print(*ptr, fout);
+ latex_escaped_print(f->data, fout);
fputs(" \\\\\n", fout);
}
}
static void
-print_latex_vertical(const char *title, const char *const * headers,
- const char *const * cells, const char *const * footers,
- const char *opt_align, const printTableOpt *opt,
- FILE *fout)
+print_latex_vertical(const printTableContent *cont, FILE *fout)
{
- bool opt_tuples_only = opt->tuples_only;
- bool opt_numeric_locale = opt->numericLocale;
- unsigned short opt_border = opt->border;
- unsigned int col_count = 0;
- unsigned long record = opt->prior_records + 1;
+ bool opt_tuples_only = cont->opt->tuples_only;
+ bool opt_numeric_locale = cont->opt->numericLocale;
+ unsigned short opt_border = cont->opt->border;
+ unsigned long record = cont->opt->prior_records + 1;
unsigned int i;
const char *const * ptr;
- (void) opt_align; /* currently unused parameter */
-
if (cancel_pressed)
return;
if (opt_border > 2)
opt_border = 2;
- /* count columns */
- for (ptr = headers; *ptr; ptr++)
- col_count++;
-
- if (opt->start_table)
+ if (cont->opt->start_table)
{
/* print title */
- if (!opt_tuples_only && title)
+ if (!opt_tuples_only && cont->title)
{
fputs("\\begin{center}\n", fout);
- latex_escaped_print(title, fout);
+ latex_escaped_print(cont->title, fout);
fputs("\n\\end{center}\n\n", fout);
}
}
/* print records */
- for (i = 0, ptr = cells; *ptr; i++, ptr++)
+ for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
{
/* new record */
- if (i % col_count == 0)
+ if (i % cont->ncolumns == 0)
{
if (cancel_pressed)
break;
fputs("\\hline\n", fout);
}
- latex_escaped_print(headers[i % col_count], fout);
+ latex_escaped_print(cont->headers[i % cont->ncolumns], fout);
fputs(" & ", fout);
latex_escaped_print(*ptr, fout);
fputs(" \\\\\n", fout);
}
- if (opt->stop_table)
+ if (cont->opt->stop_table)
{
if (opt_border == 2)
fputs("\\hline\n", fout);
fputs("\\end{tabular}\n\n\\noindent ", fout);
/* print footers */
- if (footers && !opt_tuples_only && !cancel_pressed)
+ if (cont->footers && !opt_tuples_only && !cancel_pressed)
{
- for (ptr = footers; *ptr; ptr++)
+ printTableFooter *f;
+
+ for (f = cont->footers; f; f = f->next)
{
if (opt_numeric_locale)
{
- char *my_cell = format_numeric_locale(*ptr);
+ char *my_cell = format_numeric_locale(f->data);
latex_escaped_print(my_cell, fout);
free(my_cell);
}
else
- latex_escaped_print(*ptr, fout);
+ latex_escaped_print(f->data, fout);
fputs(" \\\\\n", fout);
}
}
static void
-print_troff_ms_text(const char *title, const char *const * headers,
- const char *const * cells, const char *const * footers,
- const char *opt_align, const printTableOpt *opt,
- FILE *fout)
+print_troff_ms_text(const printTableContent *cont, FILE *fout)
{
- bool opt_tuples_only = opt->tuples_only;
- bool opt_numeric_locale = opt->numericLocale;
- unsigned short opt_border = opt->border;
- unsigned int col_count = 0;
+ bool opt_tuples_only = cont->opt->tuples_only;
+ bool opt_numeric_locale = cont->opt->numericLocale;
+ unsigned short opt_border = cont->opt->border;
unsigned int i;
const char *const * ptr;
if (opt_border > 2)
opt_border = 2;
- /* count columns */
- for (ptr = headers; *ptr; ptr++)
- col_count++;
-
- if (opt->start_table)
+ if (cont->opt->start_table)
{
/* print title */
- if (!opt_tuples_only && title)
+ if (!opt_tuples_only && cont->title)
{
fputs(".LP\n.DS C\n", fout);
- troff_ms_escaped_print(title, fout);
+ troff_ms_escaped_print(cont->title, fout);
fputs("\n.DE\n", fout);
}
else
fputs("center;\n", fout);
- for (i = 0; i < col_count; i++)
+ for (i = 0; i < cont->ncolumns; i++)
{
- fputc(*(opt_align + i), fout);
- if (opt_border > 0 && i < col_count - 1)
+ fputc(*(cont->aligns + i), fout);
+ if (opt_border > 0 && i < cont->ncolumns - 1)
fputs(" | ", fout);
}
fputs(".\n", fout);
/* print headers */
if (!opt_tuples_only)
{
- for (i = 0, ptr = headers; i < col_count; i++, ptr++)
+ for (i = 0, ptr = cont->headers; i < cont->ncolumns; i++, ptr++)
{
if (i != 0)
fputc('\t', fout);
}
/* print cells */
- for (i = 0, ptr = cells; *ptr; i++, ptr++)
+ for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
{
if (opt_numeric_locale)
{
else
troff_ms_escaped_print(*ptr, fout);
- if ((i + 1) % col_count == 0)
+ if ((i + 1) % cont->ncolumns == 0)
{
fputc('\n', fout);
if (cancel_pressed)
fputc('\t', fout);
}
- if (opt->stop_table)
+ if (cont->opt->stop_table)
{
fputs(".TE\n.DS L\n", fout);
/* print footers */
- if (footers && !opt_tuples_only && !cancel_pressed)
- for (ptr = footers; *ptr; ptr++)
+ if (cont->footers && !opt_tuples_only && !cancel_pressed)
+ {
+ printTableFooter *f;
+
+ for (f = cont->footers; f; f = f->next)
{
- troff_ms_escaped_print(*ptr, fout);
+ troff_ms_escaped_print(f->data, fout);
fputc('\n', fout);
}
+ }
fputs(".DE\n", fout);
}
static void
-print_troff_ms_vertical(const char *title, const char *const * headers,
- const char *const * cells, const char *const * footers,
- const char *opt_align, const printTableOpt *opt,
- FILE *fout)
+print_troff_ms_vertical(const printTableContent *cont, FILE *fout)
{
- bool opt_tuples_only = opt->tuples_only;
- bool opt_numeric_locale = opt->numericLocale;
- unsigned short opt_border = opt->border;
- unsigned int col_count = 0;
- unsigned long record = opt->prior_records + 1;
+ bool opt_tuples_only = cont->opt->tuples_only;
+ bool opt_numeric_locale = cont->opt->numericLocale;
+ unsigned short opt_border = cont->opt->border;
+ unsigned long record = cont->opt->prior_records + 1;
unsigned int i;
const char *const * ptr;
unsigned short current_format = 0; /* 0=none, 1=header, 2=body */
- (void) opt_align; /* currently unused parameter */
-
if (cancel_pressed)
return;
if (opt_border > 2)
opt_border = 2;
- /* count columns */
- for (ptr = headers; *ptr; ptr++)
- col_count++;
-
- if (opt->start_table)
+ if (cont->opt->start_table)
{
/* print title */
- if (!opt_tuples_only && title)
+ if (!opt_tuples_only && cont->title)
{
fputs(".LP\n.DS C\n", fout);
- troff_ms_escaped_print(title, fout);
+ troff_ms_escaped_print(cont->title, fout);
fputs("\n.DE\n", fout);
}
current_format = 2; /* assume tuples printed already */
/* print records */
- for (i = 0, ptr = cells; *ptr; i++, ptr++)
+ for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
{
/* new record */
- if (i % col_count == 0)
+ if (i % cont->ncolumns == 0)
{
if (cancel_pressed)
break;
}
}
- troff_ms_escaped_print(headers[i % col_count], fout);
+ troff_ms_escaped_print(cont->headers[i % cont->ncolumns], fout);
fputc('\t', fout);
if (opt_numeric_locale)
{
fputc('\n', fout);
}
- if (opt->stop_table)
+ if (cont->opt->stop_table)
{
fputs(".TE\n.DS L\n", fout);
/* print footers */
- if (footers && !opt_tuples_only && !cancel_pressed)
- for (ptr = footers; *ptr; ptr++)
+ if (cont->footers && !opt_tuples_only && !cancel_pressed)
+ {
+ printTableFooter *f;
+
+ for (f = cont->footers; f; f = f->next)
{
- troff_ms_escaped_print(*ptr, fout);
+ troff_ms_escaped_print(f->data, fout);
fputc('\n', fout);
}
+ }
fputs(".DE\n", fout);
}
}
}
+/*
+ * Initialise a table contents struct.
+ *
+ * Must be called before any other printTable method is used.
+ *
+ * If you call this, you must call printTableCleanup once you're done with the
+ * table.
+ */
+void
+printTableInit(printTableContent *const content, const printTableOpt *opt,
+ const char *title, int ncolumns, int nrows)
+{
+ content->opt = opt;
+ content->title = title;
+ content->ncolumns = ncolumns;
+ content->nrows = nrows;
+
+ content->headers = pg_local_calloc(ncolumns + 1,
+ sizeof(*content->headers));
+
+ content->cells = pg_local_calloc(ncolumns * nrows + 1,
+ sizeof(*content->cells));
+
+ content->footers = NULL;
+
+ content->aligns = pg_local_calloc(ncolumns + 1,
+ sizeof(*content->align));
+
+ content->header = content->headers;
+ content->cell = content->cells;
+ content->footer = content->footers;
+ content->align = content->aligns;
+}
+/*
+ * Add a header to the table.
+ *
+ * Headers are not duplicated; you must ensure that the header string is
+ * available for the lifetime of the printTableContent struct.
+ *
+ * If translate is true, the function will pass the header through gettext.
+ * Otherwise, the header will not be translated.
+ *
+ * align is either 'l' or 'r', and specifies the alignment for cells in this
+ * column.
+ */
void
-printTable(const char *title,
- const char *const * headers,
- const char *const * cells,
- const char *const * footers,
- const char *align,
- const printTableOpt *opt, FILE *fout, FILE *flog)
+printTableAddHeader(printTableContent *const content, const char *header,
+ bool translate, char align)
+{
+#ifndef ENABLE_NLS
+ (void) translate; /* unused parameter */
+#endif
+
+ if (content->header >= content->headers + content->ncolumns)
+ {
+ fprintf(stderr, _("Cannot add header to table content: "
+ "column count of %d exceeded.\n"),
+ content->ncolumns);
+ exit(EXIT_FAILURE);
+ }
+
+ *content->header = (char *) mbvalidate((unsigned char *) header,
+ content->opt->encoding);
+#ifdef ENABLE_NLS
+ if (translate)
+ *content->header = _(*content->header);
+#endif
+ content->header++;
+
+ *content->align = align;
+ content->align++;
+}
+
+/*
+ * Add a cell to the table.
+ *
+ * Cells are not duplicated; you must ensure that the cell string is available
+ * for the lifetime of the printTableContent struct.
+ *
+ * If translate is true, the function will pass the cell through gettext.
+ * Otherwise, the cell will not be translated.
+ */
+void
+printTableAddCell(printTableContent *const content, const char *cell,
+ bool translate)
+{
+#ifndef ENABLE_NLS
+ (void) translate; /* unused parameter */
+#endif
+
+ if (content->cell >= content->cells + (content->ncolumns * content->nrows))
+ {
+ fprintf(stderr, _("Cannot add cell to table content: "
+ "total cell count of %d exceeded.\n"),
+ content->ncolumns * content->nrows);
+ exit(EXIT_FAILURE);
+ }
+
+ *content->cell = (char *) mbvalidate((unsigned char *) cell,
+ content->opt->encoding);
+
+#ifdef ENABLE_NLS
+ if (translate)
+ *content->header = _(*content->header);
+#endif
+ content->cell++;
+}
+
+/*
+ * Add a footer to the table.
+ *
+ * Footers are added as elements of a singly-linked list, and the content is
+ * strdup'd, so there is no need to keep the original footer string around.
+ *
+ * Footers are never translated by the function. If you want the footer
+ * translated you must do so yourself, before calling printTableAddFooter. The
+ * reason this works differently to headers and cells is that footers tend to
+ * be made of up individually translated components, rather than being
+ * translated as a whole.
+ */
+void
+printTableAddFooter(printTableContent *const content, const char *footer)
+{
+ printTableFooter *f;
+
+ f = pg_local_calloc(1, sizeof(*f));
+ f->data = pg_strdup(footer);
+
+ if (content->footers == NULL)
+ content->footers = f;
+ else
+ content->footer->next = f;
+
+ content->footer = f;
+}
+
+/*
+ * Change the content of the last-added footer.
+ *
+ * The current contents of the last-added footer are freed, and replaced by the
+ * content given in *footer. If there was no previous footer, add a new one.
+ *
+ * The content is strdup'd, so there is no need to keep the original string
+ * around.
+ */
+void
+printTableSetFooter(printTableContent *const content, const char *footer)
+{
+ if (content->footers != NULL)
+ {
+ free(content->footer->data);
+ content->footer->data = pg_strdup(footer);
+ }
+ else
+ printTableAddFooter(content, footer);
+}
+
+/*
+ * Free all memory allocated to this struct.
+ *
+ * Once this has been called, the struct is unusable unless you pass it to
+ * printTableInit() again.
+ */
+void
+printTableCleanup(printTableContent *content)
+{
+ free(content->headers);
+ free(content->cells);
+ free(content->aligns);
+
+ content->opt = NULL;
+ content->title = NULL;
+ content->headers = NULL;
+ content->cells = NULL;
+ content->aligns = NULL;
+ content->header = NULL;
+ content->cell = NULL;
+ content->align = NULL;
+
+ if (content->footers)
+ {
+ for (content->footer = content->footers; content->footer;)
+ {
+ printTableFooter *f;
+
+ f = content->footer;
+ content->footer = f->next;
+ free(f->data);
+ free(f);
+ }
+ }
+ content->footers = NULL;
+ content->footer = NULL;
+}
+
+/*
+ * Use this to print just any table in the supported formats.
+ */
+void
+printTable(const printTableContent *cont, FILE *fout, FILE *flog)
{
- static const char *default_footer[] = {NULL};
FILE *output;
bool is_pager = false;
-
+
if (cancel_pressed)
return;
- if (opt->format == PRINT_NOTHING)
+ if (cont->opt->format == PRINT_NOTHING)
return;
- if (!footers)
- footers = default_footer;
-
if (fout == stdout)
{
- int col_count = 0,
- row_count = 0,
- lines;
- const char *const * ptr;
-
- /* rough estimate of columns and rows */
- if (headers)
- for (ptr = headers; *ptr; ptr++)
- col_count++;
- if (cells)
- for (ptr = cells; *ptr; ptr++)
- row_count++;
- if (col_count > 0)
- row_count /= col_count;
-
- if (opt->expanded)
- lines = (col_count + 1) * row_count;
+ int lines;
+
+ if (cont->opt->expanded)
+ lines = (cont->ncolumns + 1) * cont->nrows;
else
- lines = row_count + 1;
- if (footers && !opt->tuples_only)
- for (ptr = footers; *ptr; ptr++)
+ lines = cont->nrows + 1;
+
+ if (!cont->opt->tuples_only)
+ {
+ printTableFooter *f;
+
+ /*
+ * FIXME -- this is slightly bogus: it counts the number of
+ * footers, not the number of lines in them.
+ */
+ for (f = cont->footers; f; f = f->next)
lines++;
- output = PageOutput(lines, opt->pager);
+ }
+
+ output = PageOutput(lines, cont->opt->pager);
is_pager = (output != fout);
}
else
/* print the stuff */
if (flog)
- print_aligned_text(title, headers, cells, footers, align,
- opt, is_pager, flog);
+ print_aligned_text(cont, is_pager, flog);
- switch (opt->format)
+ switch (cont->opt->format)
{
case PRINT_UNALIGNED:
- if (opt->expanded)
- print_unaligned_vertical(title, headers, cells, footers, align,
- opt, output);
+ if (cont->opt->expanded)
+ print_unaligned_vertical(cont, output);
else
- print_unaligned_text(title, headers, cells, footers, align,
- opt, output);
+ print_unaligned_text(cont, output);
break;
case PRINT_ALIGNED:
case PRINT_WRAPPED:
- if (opt->expanded)
- print_aligned_vertical(title, headers, cells, footers, align,
- opt, output);
+ if (cont->opt->expanded)
+ print_aligned_vertical(cont, output);
else
- print_aligned_text(title, headers, cells, footers, align,
- opt, is_pager, output);
+ print_aligned_text(cont, is_pager, output);
break;
case PRINT_HTML:
- if (opt->expanded)
- print_html_vertical(title, headers, cells, footers, align,
- opt, output);
+ if (cont->opt->expanded)
+ print_html_vertical(cont, output);
else
- print_html_text(title, headers, cells, footers, align,
- opt, output);
+ print_html_text(cont, output);
break;
case PRINT_LATEX:
- if (opt->expanded)
- print_latex_vertical(title, headers, cells, footers, align,
- opt, output);
+ if (cont->opt->expanded)
+ print_latex_vertical(cont, output);
else
- print_latex_text(title, headers, cells, footers, align,
- opt, output);
+ print_latex_text(cont, output);
break;
case PRINT_TROFF_MS:
- if (opt->expanded)
- print_troff_ms_vertical(title, headers, cells, footers, align,
- opt, output);
+ if (cont->opt->expanded)
+ print_troff_ms_vertical(cont, output);
else
- print_troff_ms_text(title, headers, cells, footers, align,
- opt, output);
+ print_troff_ms_text(cont, output);
break;
default:
- fprintf(stderr, _("invalid output format (internal error): %d"), opt->format);
+ fprintf(stderr, _("invalid output format (internal error): %d"),
+ cont->opt->format);
exit(EXIT_FAILURE);
}
ClosePager(output);
}
-
+/*
+ * Use this to print query results
+ *
+ * It calls printTable with all the things set straight.
+ */
void
printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *flog)
{
- int ntuples;
- int nfields;
- int ncells;
- const char **headers;
- const char **cells;
- char **footers;
- char *align;
+ printTableContent cont;
int i,
r,
c;
if (cancel_pressed)
return;
- /* extract headers */
- ntuples = PQntuples(result);
- nfields = PQnfields(result);
-
- headers = pg_local_calloc(nfields + 1, sizeof(*headers));
-
- for (i = 0; i < nfields; i++)
- {
- headers[i] = (char *) mbvalidate((unsigned char *) PQfname(result, i),
- opt->topt.encoding);
-#ifdef ENABLE_NLS
- if (opt->trans_headers)
- headers[i] = _(headers[i]);
-#endif
- }
-
- /* set cells */
- ncells = ntuples * nfields;
- cells = pg_local_calloc(ncells + 1, sizeof(*cells));
-
- i = 0;
- for (r = 0; r < ntuples; r++)
- {
- for (c = 0; c < nfields; c++)
- {
- if (PQgetisnull(result, r, c))
- cells[i] = opt->nullPrint ? opt->nullPrint : "";
- else
- {
- cells[i] = (char *)
- mbvalidate((unsigned char *) PQgetvalue(result, r, c),
- opt->topt.encoding);
-#ifdef ENABLE_NLS
- if (opt->trans_columns && opt->trans_columns[c])
- cells[i] = _(cells[i]);
-#endif
- }
- i++;
- }
- }
-
- /* set footers */
+ printTableInit(&cont, &opt->topt, opt->title,
+ PQnfields(result), PQntuples(result));
- if (opt->footers)
- footers = opt->footers;
- else if (!opt->topt.expanded && opt->default_footer)
- {
- unsigned long total_records;
-
- footers = pg_local_calloc(2, sizeof(*footers));
- footers[0] = pg_local_malloc(100);
- total_records = opt->topt.prior_records + ntuples;
- if (total_records == 1)
- snprintf(footers[0], 100, _("(1 row)"));
- else
- snprintf(footers[0], 100, _("(%lu rows)"), total_records);
- }
- else
- footers = NULL;
-
- /* set alignment */
- align = pg_local_calloc(nfields + 1, sizeof(*align));
-
- for (i = 0; i < nfields; i++)
+ for (i = 0; i < cont.ncolumns; i++)
{
+ char align;
Oid ftype = PQftype(result, i);
switch (ftype)
case XIDOID:
case CIDOID:
case CASHOID:
- align[i] = 'r';
+ align = 'r';
break;
default:
- align[i] = 'l';
+ align = 'l';
break;
}
+
+ printTableAddHeader(&cont, PQfname(result, i),
+ opt->trans_headers, align);
}
- /* call table printer */
- printTable(opt->title, headers, cells,
- (const char *const *) footers,
- align, &opt->topt, fout, flog);
+ /* set cells */
+ for (r = 0; r < cont.nrows; r++)
+ {
+ for (c = 0; c < cont.ncolumns; c++)
+ {
+ char *cell;
+ bool translate;
+
+ if (PQgetisnull(result, r, c))
+ cell = opt->nullPrint ? opt->nullPrint : "";
+ else
+ cell = PQgetvalue(result, r, c);
+
+ translate = (opt->trans_columns && opt->trans_columns[c]);
+ printTableAddCell(&cont, cell, translate);
+ }
+ }
- free(headers);
- free(cells);
- if (footers && !opt->footers)
+ /* set footers */
+ if (opt->footers)
+ {
+ char **footer;
+
+ for (footer = opt->footers; *footer; footer++)
+ printTableAddFooter(&cont, *footer);
+ }
+ else if (!opt->topt.expanded && opt->default_footer)
{
- free(footers[0]);
- free(footers);
+ unsigned long total_records;
+ char default_footer[100];
+
+ total_records = opt->topt.prior_records + cont.nrows;
+ if (total_records == 1)
+ snprintf(default_footer, 100, _("(1 row)"));
+ else
+ snprintf(default_footer, 100, _("(%lu rows)"), total_records);
+
+ printTableAddFooter(&cont, default_footer);
}
- free(align);
+
+ printTable(&cont, fout, flog);
+ printTableCleanup(&cont);
}
extlconv = localeconv();
if (*extlconv->decimal_point)
- decimal_point = strdup(extlconv->decimal_point);
+ decimal_point = pg_strdup(extlconv->decimal_point);
else
decimal_point = "."; /* SQL output standard */
if (*extlconv->grouping && atoi(extlconv->grouping) > 0)
- grouping = strdup(extlconv->grouping);
+ grouping = pg_strdup(extlconv->grouping);
else
grouping = "3"; /* most common */
/* similar code exists in formatting.c */
if (*extlconv->thousands_sep)
- thousands_sep = strdup(extlconv->thousands_sep);
+ thousands_sep = pg_strdup(extlconv->thousands_sep);
/* Make sure thousands separator doesn't match decimal point symbol. */
else if (strcmp(decimal_point, ",") != 0)
thousands_sep = ",";