2000-01-19 00:30:24 +01:00
/*
* psql - the PostgreSQL interactive terminal
*
2008-07-03 05:37:17 +02:00
* Support for the various \ d ( " describe " ) commands . Note that the current
* expectation is that all functions in this file will succeed when working
* with servers of versions 7.4 and up . It ' s okay to omit irrelevant
* information for an old server , but not to fail outright .
*
2012-01-02 00:01:58 +01:00
* Copyright ( c ) 2000 - 2012 , PostgreSQL Global Development Group
2000-01-19 00:30:24 +01:00
*
2010-09-20 22:08:53 +02:00
* src / bin / psql / describe . c
2000-01-19 00:30:24 +01:00
*/
2001-02-10 03:31:31 +01:00
# include "postgres_fe.h"
1999-11-04 22:56:02 +01:00
2008-05-13 00:59:58 +02:00
# include <ctype.h>
1999-11-04 22:56:02 +01:00
# include "common.h"
2008-05-13 00:59:58 +02:00
# include "describe.h"
# include "dumputils.h"
# include "mbprint.h"
1999-11-04 22:56:02 +01:00
# include "print.h"
2008-05-13 00:59:58 +02:00
# include "settings.h"
1999-11-04 22:56:02 +01:00
# include "variables.h"
2003-07-27 05:32:26 +02:00
2002-08-10 05:56:24 +02:00
static bool describeOneTableDetails ( const char * schemaname ,
2002-09-04 22:31:48 +02:00
const char * relationname ,
const char * oid ,
bool verbose ) ;
2008-05-13 00:59:58 +02:00
static void add_tablespace_footer ( printTableContent * const cont , char relkind ,
2009-06-11 16:49:15 +02:00
Oid tablespace , const bool newline ) ;
2008-05-13 02:23:17 +02:00
static void add_role_attribute ( PQExpBuffer buf , const char * const str ) ;
2007-08-21 03:11:32 +02:00
static bool listTSParsersVerbose ( const char * pattern ) ;
static bool describeOneTSParser ( const char * oid , const char * nspname ,
2007-11-15 22:14:46 +01:00
const char * prsname ) ;
2007-08-21 03:11:32 +02:00
static bool listTSConfigsVerbose ( const char * pattern ) ;
static bool describeOneTSConfig ( const char * oid , const char * nspname ,
2007-11-15 22:14:46 +01:00
const char * cfgname ,
const char * pnspname , const char * prsname ) ;
2008-12-31 19:07:47 +01:00
static void printACLColumn ( PQExpBuffer buf , const char * colname ) ;
2011-02-08 22:08:41 +01:00
static bool listOneExtensionContents ( const char * extname , const char * oid ) ;
2007-08-21 03:11:32 +02:00
2004-07-12 22:41:13 +02:00
1999-11-04 22:56:02 +01:00
/*----------------
* Handlers for various slash commands displaying some sort of list
* of things in the database .
*
2008-07-03 05:37:17 +02:00
* Note : try to format the queries to look nice in - E output .
1999-11-04 22:56:02 +01:00
* - - - - - - - - - - - - - - - -
*/
/* \da
2002-08-10 05:56:24 +02:00
* Takes an optional regexp to select particular aggregates
1999-11-04 22:56:02 +01:00
*/
bool
2009-01-06 22:10:30 +01:00
describeAggregates ( const char * pattern , bool verbose , bool showSystem )
1999-11-04 22:56:02 +01:00
{
2002-04-24 07:24:00 +02:00
PQExpBufferData buf ;
1999-11-05 00:14:30 +01:00
PGresult * res ;
2000-01-14 23:18:03 +01:00
printQueryOpt myopt = pset . popt ;
1999-11-05 00:14:30 +01:00
2002-04-24 07:24:00 +02:00
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" SELECT n.nspname as \" %s \" , \n "
" p.proname AS \" %s \" , \n "
2009-06-11 16:49:15 +02:00
" pg_catalog.format_type(p.prorettype, NULL) AS \" %s \" , \n " ,
2008-07-03 05:37:17 +02:00
gettext_noop ( " Schema " ) ,
gettext_noop ( " Name " ) ,
gettext_noop ( " Result data type " ) ) ;
if ( pset . sversion > = 80200 )
2009-06-11 16:49:15 +02:00
appendPQExpBuffer ( & buf ,
" CASE WHEN p.pronargs = 0 \n "
" THEN CAST('*' AS pg_catalog.text) \n "
" ELSE \n "
" pg_catalog.array_to_string(ARRAY( \n "
" SELECT \n "
" pg_catalog.format_type(p.proargtypes[s.i], NULL) \n "
" FROM \n "
" pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i) \n "
" ), ', ') \n "
" END AS \" %s \" , \n " ,
gettext_noop ( " Argument data types " ) ) ;
2008-07-03 05:37:17 +02:00
else
2009-06-11 16:49:15 +02:00
appendPQExpBuffer ( & buf ,
" pg_catalog.format_type(p.proargtypes[0], NULL) AS \" %s \" , \n " ,
gettext_noop ( " Argument data types " ) ) ;
2008-07-03 05:37:17 +02:00
appendPQExpBuffer ( & buf ,
2007-11-15 22:14:46 +01:00
" pg_catalog.obj_description(p.oid, 'pg_proc') as \" %s \" \n "
2002-09-04 22:31:48 +02:00
" FROM pg_catalog.pg_proc p \n "
2007-11-15 22:14:46 +01:00
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace \n "
2002-09-04 22:31:48 +02:00
" WHERE p.proisagg \n " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Description " ) ) ;
* Includes tab completion. It's not magic, but it's very cool. At any
rate
it's better than what used to be there.
* Does proper SQL "host variable" substitution as pointed out by Andreas
Zeugwetter (thanks): select * from :foo; Also some changes in how ':'
and ';' are treated (escape with \ to send to backend). This does
_not_
affect the '::' cast operator, but perhaps others that contain : or ;
(but there are none right now).
* To show description with a <something> listing, append '?' to command
name, e.g., \df?. This seemed to be the convenient and logical
solution.
Or append a '+' to see more useless information, e.g., \df+.
* Fixed fflush()'ing bug pointed out by Jan during the regression test
discussion.
* Added LastOid variable. This ought to take care of TODO item "Add a
function to return the last inserted oid, for use in psql scripts"
(under CLIENTS)
E.g.,
insert into foo values(...);
insert into bar values(..., :LastOid);
\echo $LastOid
* \d command shows constraints, rules, and triggers defined on the table
(in addition to indices)
* Various fixes, optimizations, corrections
* Documentation update as well
Note: This now requires snprintf(), which, if necessary, is taken from
src/backend/port. This is certainly a little weird, but it should
suffice
until a source tree cleanup is done.
Enjoy.
--
Peter Eisentraut Sernanders väg 10:115
1999-11-26 05:24:17 +01:00
2009-06-11 16:49:15 +02:00
if ( ! showSystem & & ! pattern )
appendPQExpBuffer ( & buf , " AND n.nspname <> 'pg_catalog' \n "
" AND n.nspname <> 'information_schema' \n " ) ;
2009-01-06 22:10:30 +01:00
2006-10-10 01:30:33 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , true , false ,
" n.nspname " , " p.proname " , NULL ,
" pg_catalog.pg_function_is_visible(p.oid) " ) ;
1999-11-05 00:14:30 +01:00
2008-07-03 05:37:17 +02:00
appendPQExpBuffer ( & buf , " ORDER BY 1, 2, 4; " ) ;
1999-11-05 00:14:30 +01:00
2002-10-15 04:24:16 +02:00
res = PSQLexec ( buf . data , false ) ;
2002-04-24 07:24:00 +02:00
termPQExpBuffer ( & buf ) ;
1999-11-05 00:14:30 +01:00
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
2001-06-30 19:26:12 +02:00
myopt . title = _ ( " List of aggregate functions " ) ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
1999-11-05 00:14:30 +01:00
2005-06-14 04:57:45 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
1999-11-05 00:14:30 +01:00
PQclear ( res ) ;
return true ;
1999-11-04 22:56:02 +01:00
}
2004-06-18 08:14:31 +02:00
/* \db
* Takes an optional regexp to select particular tablespaces
*/
bool
2004-07-15 05:56:06 +02:00
describeTablespaces ( const char * pattern , bool verbose )
2004-06-18 08:14:31 +02:00
{
PQExpBufferData buf ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
2004-11-05 20:17:13 +01:00
if ( pset . sversion < 80000 )
2004-08-29 07:07:03 +02:00
{
2008-07-03 05:37:17 +02:00
fprintf ( stderr , _ ( " The server (version %d.%d) does not support tablespaces. \n " ) ,
pset . sversion / 10000 , ( pset . sversion / 100 ) % 100 ) ;
2004-08-29 07:07:03 +02:00
return true ;
2004-08-20 22:18:23 +02:00
}
2004-06-18 08:14:31 +02:00
initPQExpBuffer ( & buf ) ;
2011-12-07 10:35:00 +01:00
if ( pset . sversion > = 90200 )
printfPQExpBuffer ( & buf ,
" SELECT spcname AS \" %s \" , \n "
2012-06-10 21:20:04 +02:00
" pg_catalog.pg_get_userbyid(spcowner) AS \" %s \" , \n "
" pg_catalog.pg_tablespace_location(oid) AS \" %s \" " ,
2011-12-07 10:35:00 +01:00
gettext_noop ( " Name " ) ,
gettext_noop ( " Owner " ) ,
gettext_noop ( " Location " ) ) ;
else
printfPQExpBuffer ( & buf ,
" SELECT spcname AS \" %s \" , \n "
2012-06-10 21:20:04 +02:00
" pg_catalog.pg_get_userbyid(spcowner) AS \" %s \" , \n "
2011-12-07 10:35:00 +01:00
" spclocation AS \" %s \" " ,
gettext_noop ( " Name " ) ,
gettext_noop ( " Owner " ) ,
gettext_noop ( " Location " ) ) ;
2004-06-18 08:14:31 +02:00
2004-07-15 05:56:06 +02:00
if ( verbose )
2008-12-31 19:07:47 +01:00
{
appendPQExpBuffer ( & buf , " , \n " ) ;
printACLColumn ( & buf , " spcacl " ) ;
}
2008-07-03 05:37:17 +02:00
if ( verbose & & pset . sversion > = 80200 )
appendPQExpBuffer ( & buf ,
2009-06-11 16:49:15 +02:00
" , \n pg_catalog.shobj_description(oid, 'pg_tablespace') AS \" %s \" " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Description " ) ) ;
2004-08-29 07:07:03 +02:00
2004-07-15 05:56:06 +02:00
appendPQExpBuffer ( & buf ,
" \n FROM pg_catalog.pg_tablespace \n " ) ;
2006-10-10 01:30:33 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , false , false ,
NULL , " spcname " , NULL ,
NULL ) ;
2004-06-18 08:14:31 +02:00
appendPQExpBuffer ( & buf , " ORDER BY 1; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
myopt . title = _ ( " List of tablespaces " ) ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
2004-06-18 08:14:31 +02:00
2005-06-14 04:57:45 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
2004-06-18 08:14:31 +02:00
PQclear ( res ) ;
return true ;
}
1999-11-04 22:56:02 +01:00
/* \df
2009-04-21 17:49:06 +02:00
* Takes an optional regexp to select particular functions .
*
* As with \ d , you can specify the kinds of functions you want :
*
* a for aggregates
* n for normal
* t for trigger
* w for window
*
* and you can mix and match these in any order .
1999-11-04 22:56:02 +01:00
*/
bool
2009-04-21 17:49:06 +02:00
describeFunctions ( const char * functypes , const char * pattern , bool verbose , bool showSystem )
1999-11-04 22:56:02 +01:00
{
2009-05-05 04:29:06 +02:00
bool showAggregate = strchr ( functypes , ' a ' ) ! = NULL ;
bool showNormal = strchr ( functypes , ' n ' ) ! = NULL ;
bool showTrigger = strchr ( functypes , ' t ' ) ! = NULL ;
bool showWindow = strchr ( functypes , ' w ' ) ! = NULL ;
bool have_where ;
2002-04-24 07:24:00 +02:00
PQExpBufferData buf ;
1999-11-05 00:14:30 +01:00
PGresult * res ;
2000-01-14 23:18:03 +01:00
printQueryOpt myopt = pset . popt ;
2009-05-05 04:29:06 +02:00
static const bool translate_columns [ ] = { false , false , false , false , true , true , false , false , false , false } ;
1999-11-05 00:14:30 +01:00
2009-04-21 19:28:01 +02:00
if ( strlen ( functypes ) ! = strspn ( functypes , " antwS+ " ) )
{
fprintf ( stderr , _ ( " \\ df only takes [antwS+] as options \n " ) ) ;
return true ;
}
2009-04-21 17:49:06 +02:00
if ( showWindow & & pset . sversion < 80400 )
{
2009-06-10 23:51:56 +02:00
fprintf ( stderr , _ ( " \\ df does not take a \" w \" option with server version %d.%d \n " ) ,
2009-04-21 17:49:06 +02:00
pset . sversion / 10000 , ( pset . sversion / 100 ) % 100 ) ;
return true ;
}
if ( ! showAggregate & & ! showNormal & & ! showTrigger & & ! showWindow )
{
showAggregate = showNormal = showTrigger = true ;
if ( pset . sversion > = 80400 )
showWindow = true ;
}
2002-04-24 07:24:00 +02:00
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
2004-09-10 06:10:53 +02:00
" SELECT n.nspname as \" %s \" , \n "
2008-07-18 05:32:53 +02:00
" p.proname as \" %s \" , \n " ,
2008-07-03 05:37:17 +02:00
gettext_noop ( " Schema " ) ,
2008-07-18 05:32:53 +02:00
gettext_noop ( " Name " ) ) ;
2008-07-03 05:37:17 +02:00
2009-06-11 16:49:15 +02:00
if ( pset . sversion > = 80400 )
2008-07-18 05:32:53 +02:00
appendPQExpBuffer ( & buf ,
2009-06-11 16:49:15 +02:00
" pg_catalog.pg_get_function_result(p.oid) as \" %s \" , \n "
" pg_catalog.pg_get_function_arguments(p.oid) as \" %s \" , \n "
2009-04-21 17:49:06 +02:00
" CASE \n "
" WHEN p.proisagg THEN '%s' \n "
" WHEN p.proiswindow THEN '%s' \n "
2009-05-05 04:29:06 +02:00
" WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s' \n "
2009-04-21 17:49:06 +02:00
" ELSE '%s' \n "
" END as \" %s \" " ,
2008-07-18 05:32:53 +02:00
gettext_noop ( " Result data type " ) ,
2009-06-11 16:49:15 +02:00
gettext_noop ( " Argument data types " ) ,
/* translator: "agg" is short for "aggregate" */
gettext_noop ( " agg " ) ,
gettext_noop ( " window " ) ,
gettext_noop ( " trigger " ) ,
gettext_noop ( " normal " ) ,
gettext_noop ( " Type " ) ) ;
else if ( pset . sversion > = 80100 )
2008-07-03 05:37:17 +02:00
appendPQExpBuffer ( & buf ,
2009-06-11 16:49:15 +02:00
" CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END || \n "
2008-07-18 05:32:53 +02:00
" pg_catalog.format_type(p.prorettype, NULL) as \" %s \" , \n "
2009-06-11 16:49:15 +02:00
" CASE WHEN proallargtypes IS NOT NULL THEN \n "
" pg_catalog.array_to_string(ARRAY( \n "
" SELECT \n "
" CASE \n "
" WHEN p.proargmodes[s.i] = 'i' THEN '' \n "
2006-07-17 02:21:23 +02:00
" WHEN p.proargmodes[s.i] = 'o' THEN 'OUT ' \n "
2009-06-11 16:49:15 +02:00
" WHEN p.proargmodes[s.i] = 'b' THEN 'INOUT ' \n "
" WHEN p.proargmodes[s.i] = 'v' THEN 'VARIADIC ' \n "
" END || \n "
" CASE \n "
2006-10-04 02:30:14 +02:00
" WHEN COALESCE(p.proargnames[s.i], '') = '' THEN '' \n "
2009-06-11 16:49:15 +02:00
" ELSE p.proargnames[s.i] || ' ' \n "
" END || \n "
2006-10-04 02:30:14 +02:00
" pg_catalog.format_type(p.proallargtypes[s.i], NULL) \n "
2009-06-11 16:49:15 +02:00
" FROM \n "
" pg_catalog.generate_series(1, pg_catalog.array_upper(p.proallargtypes, 1)) AS s(i) \n "
" ), ', ') \n "
" ELSE \n "
" pg_catalog.array_to_string(ARRAY( \n "
" SELECT \n "
" CASE \n "
2006-10-04 02:30:14 +02:00
" WHEN COALESCE(p.proargnames[s.i+1], '') = '' THEN '' \n "
2009-06-11 16:49:15 +02:00
" ELSE p.proargnames[s.i+1] || ' ' \n "
" END || \n "
2006-10-04 02:30:14 +02:00
" pg_catalog.format_type(p.proargtypes[s.i], NULL) \n "
2009-06-11 16:49:15 +02:00
" FROM \n "
" pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i) \n "
" ), ', ') \n "
" END AS \" %s \" , \n "
" CASE \n "
" WHEN p.proisagg THEN '%s' \n "
" WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s' \n "
" ELSE '%s' \n "
" END AS \" %s \" " ,
2008-07-18 05:32:53 +02:00
gettext_noop ( " Result data type " ) ,
2009-04-21 17:49:06 +02:00
gettext_noop ( " Argument data types " ) ,
2009-06-11 16:49:15 +02:00
/* translator: "agg" is short for "aggregate" */
2009-04-21 17:49:06 +02:00
gettext_noop ( " agg " ) ,
gettext_noop ( " trigger " ) ,
gettext_noop ( " normal " ) ,
gettext_noop ( " Type " ) ) ;
2008-07-03 05:37:17 +02:00
else
appendPQExpBuffer ( & buf ,
2009-06-11 16:49:15 +02:00
" CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END || \n "
2008-07-18 05:32:53 +02:00
" pg_catalog.format_type(p.prorettype, NULL) as \" %s \" , \n "
2009-06-11 16:49:15 +02:00
" pg_catalog.oidvectortypes(p.proargtypes) as \" %s \" , \n "
" CASE \n "
" WHEN p.proisagg THEN '%s' \n "
" WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s' \n "
" ELSE '%s' \n "
" END AS \" %s \" " ,
2008-07-18 05:32:53 +02:00
gettext_noop ( " Result data type " ) ,
2009-04-21 17:49:06 +02:00
gettext_noop ( " Argument data types " ) ,
2009-06-11 16:49:15 +02:00
/* translator: "agg" is short for "aggregate" */
2009-04-21 17:49:06 +02:00
gettext_noop ( " agg " ) ,
gettext_noop ( " trigger " ) ,
gettext_noop ( " normal " ) ,
gettext_noop ( " Type " ) ) ;
2001-06-30 19:26:12 +02:00
2000-04-12 19:17:23 +02:00
if ( verbose )
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf ,
2007-06-28 08:40:16 +02:00
" , \n CASE \n "
2009-05-05 04:29:06 +02:00
" WHEN p.provolatile = 'i' THEN '%s' \n "
" WHEN p.provolatile = 's' THEN '%s' \n "
" WHEN p.provolatile = 'v' THEN '%s' \n "
2007-06-28 08:40:16 +02:00
" END as \" %s \" "
2009-06-11 16:49:15 +02:00
" , \n pg_catalog.pg_get_userbyid(p.proowner) as \" %s \" , \n "
2002-09-04 22:31:48 +02:00
" l.lanname as \" %s \" , \n "
" p.prosrc as \" %s \" , \n "
2005-10-15 04:49:52 +02:00
" pg_catalog.obj_description(p.oid, 'pg_proc') as \" %s \" " ,
2009-05-05 04:29:06 +02:00
gettext_noop ( " immutable " ) ,
gettext_noop ( " stable " ) ,
gettext_noop ( " volatile " ) ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Volatility " ) ,
gettext_noop ( " Owner " ) ,
gettext_noop ( " Language " ) ,
gettext_noop ( " Source code " ) ,
gettext_noop ( " Description " ) ) ;
* Includes tab completion. It's not magic, but it's very cool. At any
rate
it's better than what used to be there.
* Does proper SQL "host variable" substitution as pointed out by Andreas
Zeugwetter (thanks): select * from :foo; Also some changes in how ':'
and ';' are treated (escape with \ to send to backend). This does
_not_
affect the '::' cast operator, but perhaps others that contain : or ;
(but there are none right now).
* To show description with a <something> listing, append '?' to command
name, e.g., \df?. This seemed to be the convenient and logical
solution.
Or append a '+' to see more useless information, e.g., \df+.
* Fixed fflush()'ing bug pointed out by Jan during the regression test
discussion.
* Added LastOid variable. This ought to take care of TODO item "Add a
function to return the last inserted oid, for use in psql scripts"
(under CLIENTS)
E.g.,
insert into foo values(...);
insert into bar values(..., :LastOid);
\echo $LastOid
* \d command shows constraints, rules, and triggers defined on the table
(in addition to indices)
* Various fixes, optimizations, corrections
* Documentation update as well
Note: This now requires snprintf(), which, if necessary, is taken from
src/backend/port. This is certainly a little weird, but it should
suffice
until a source tree cleanup is done.
Enjoy.
--
Peter Eisentraut Sernanders väg 10:115
1999-11-26 05:24:17 +01:00
2008-07-03 05:37:17 +02:00
appendPQExpBuffer ( & buf ,
" \n FROM pg_catalog.pg_proc p "
2009-06-11 16:49:15 +02:00
" \n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace \n " ) ;
2008-07-03 05:37:17 +02:00
if ( verbose )
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf ,
2009-06-11 16:49:15 +02:00
" LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang \n " ) ;
* Includes tab completion. It's not magic, but it's very cool. At any
rate
it's better than what used to be there.
* Does proper SQL "host variable" substitution as pointed out by Andreas
Zeugwetter (thanks): select * from :foo; Also some changes in how ':'
and ';' are treated (escape with \ to send to backend). This does
_not_
affect the '::' cast operator, but perhaps others that contain : or ;
(but there are none right now).
* To show description with a <something> listing, append '?' to command
name, e.g., \df?. This seemed to be the convenient and logical
solution.
Or append a '+' to see more useless information, e.g., \df+.
* Fixed fflush()'ing bug pointed out by Jan during the regression test
discussion.
* Added LastOid variable. This ought to take care of TODO item "Add a
function to return the last inserted oid, for use in psql scripts"
(under CLIENTS)
E.g.,
insert into foo values(...);
insert into bar values(..., :LastOid);
\echo $LastOid
* \d command shows constraints, rules, and triggers defined on the table
(in addition to indices)
* Various fixes, optimizations, corrections
* Documentation update as well
Note: This now requires snprintf(), which, if necessary, is taken from
src/backend/port. This is certainly a little weird, but it should
suffice
until a source tree cleanup is done.
Enjoy.
--
Peter Eisentraut Sernanders väg 10:115
1999-11-26 05:24:17 +01:00
2009-05-05 04:29:06 +02:00
have_where = false ;
2009-04-21 17:49:06 +02:00
2009-05-05 04:29:06 +02:00
/* filter by function type, if requested */
2009-04-21 17:49:06 +02:00
if ( showNormal & & showAggregate & & showTrigger & & showWindow )
2009-06-11 16:49:15 +02:00
/* Do nothing */ ;
2009-04-21 17:49:06 +02:00
else if ( showNormal )
{
if ( ! showAggregate )
2009-05-05 04:29:06 +02:00
{
if ( have_where )
appendPQExpBuffer ( & buf , " AND " ) ;
else
{
appendPQExpBuffer ( & buf , " WHERE " ) ;
have_where = true ;
}
appendPQExpBuffer ( & buf , " NOT p.proisagg \n " ) ;
}
2009-04-21 17:49:06 +02:00
if ( ! showTrigger )
{
2009-05-05 04:29:06 +02:00
if ( have_where )
appendPQExpBuffer ( & buf , " AND " ) ;
else
{
appendPQExpBuffer ( & buf , " WHERE " ) ;
have_where = true ;
}
appendPQExpBuffer ( & buf , " p.prorettype <> 'pg_catalog.trigger'::pg_catalog.regtype \n " ) ;
}
if ( ! showWindow & & pset . sversion > = 80400 )
{
if ( have_where )
appendPQExpBuffer ( & buf , " AND " ) ;
2009-04-21 17:49:06 +02:00
else
2009-05-05 04:29:06 +02:00
{
appendPQExpBuffer ( & buf , " WHERE " ) ;
have_where = true ;
}
appendPQExpBuffer ( & buf , " NOT p.proiswindow \n " ) ;
2009-04-21 17:49:06 +02:00
}
}
else
{
2009-06-11 16:49:15 +02:00
bool needs_or = false ;
2009-04-21 17:49:06 +02:00
2009-05-05 04:29:06 +02:00
appendPQExpBuffer ( & buf , " WHERE ( \n " ) ;
have_where = true ;
/* Note: at least one of these must be true ... */
2009-04-21 17:49:06 +02:00
if ( showAggregate )
{
2009-06-11 16:49:15 +02:00
appendPQExpBuffer ( & buf , " p.proisagg \n " ) ;
2009-04-21 17:49:06 +02:00
needs_or = true ;
}
if ( showTrigger )
{
if ( needs_or )
2009-05-05 04:29:06 +02:00
appendPQExpBuffer ( & buf , " OR " ) ;
appendPQExpBuffer ( & buf ,
2009-06-11 16:49:15 +02:00
" p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype \n " ) ;
2009-04-21 17:49:06 +02:00
needs_or = true ;
}
if ( showWindow )
{
if ( needs_or )
2009-05-05 04:29:06 +02:00
appendPQExpBuffer ( & buf , " OR " ) ;
2009-04-21 17:49:06 +02:00
appendPQExpBuffer ( & buf , " p.proiswindow \n " ) ;
2009-05-05 04:29:06 +02:00
needs_or = true ;
2009-04-21 17:49:06 +02:00
}
appendPQExpBuffer ( & buf , " ) \n " ) ;
}
2002-08-10 05:56:24 +02:00
2009-10-28 19:09:44 +01:00
processSQLNamePattern ( pset . db , & buf , pattern , have_where , false ,
2009-05-05 04:29:06 +02:00
" n.nspname " , " p.proname " , NULL ,
" pg_catalog.pg_function_is_visible(p.oid) " ) ;
2009-06-11 16:49:15 +02:00
if ( ! showSystem & & ! pattern )
appendPQExpBuffer ( & buf , " AND n.nspname <> 'pg_catalog' \n "
" AND n.nspname <> 'information_schema' \n " ) ;
2009-01-06 22:10:30 +01:00
2008-07-03 05:37:17 +02:00
appendPQExpBuffer ( & buf , " ORDER BY 1, 2, 4; " ) ;
1999-11-05 00:14:30 +01:00
2002-10-15 04:24:16 +02:00
res = PSQLexec ( buf . data , false ) ;
2002-04-24 07:24:00 +02:00
termPQExpBuffer ( & buf ) ;
1999-11-05 00:14:30 +01:00
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
2001-06-30 19:26:12 +02:00
myopt . title = _ ( " List of functions " ) ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
2009-05-05 04:29:06 +02:00
myopt . translate_columns = translate_columns ;
1999-11-05 00:14:30 +01:00
2005-06-14 04:57:45 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
1999-11-05 00:14:30 +01:00
PQclear ( res ) ;
return true ;
1999-11-04 22:56:02 +01:00
}
/*
* Includes tab completion. It's not magic, but it's very cool. At any
rate
it's better than what used to be there.
* Does proper SQL "host variable" substitution as pointed out by Andreas
Zeugwetter (thanks): select * from :foo; Also some changes in how ':'
and ';' are treated (escape with \ to send to backend). This does
_not_
affect the '::' cast operator, but perhaps others that contain : or ;
(but there are none right now).
* To show description with a <something> listing, append '?' to command
name, e.g., \df?. This seemed to be the convenient and logical
solution.
Or append a '+' to see more useless information, e.g., \df+.
* Fixed fflush()'ing bug pointed out by Jan during the regression test
discussion.
* Added LastOid variable. This ought to take care of TODO item "Add a
function to return the last inserted oid, for use in psql scripts"
(under CLIENTS)
E.g.,
insert into foo values(...);
insert into bar values(..., :LastOid);
\echo $LastOid
* \d command shows constraints, rules, and triggers defined on the table
(in addition to indices)
* Various fixes, optimizations, corrections
* Documentation update as well
Note: This now requires snprintf(), which, if necessary, is taken from
src/backend/port. This is certainly a little weird, but it should
suffice
until a source tree cleanup is done.
Enjoy.
--
Peter Eisentraut Sernanders väg 10:115
1999-11-26 05:24:17 +01:00
* \ dT
* describe types
1999-11-04 22:56:02 +01:00
*/
bool
2009-01-06 22:10:30 +01:00
describeTypes ( const char * pattern , bool verbose , bool showSystem )
1999-11-04 22:56:02 +01:00
{
2002-04-24 07:24:00 +02:00
PQExpBufferData buf ;
1999-11-05 00:14:30 +01:00
PGresult * res ;
2000-01-14 23:18:03 +01:00
printQueryOpt myopt = pset . popt ;
1999-11-05 00:14:30 +01:00
2002-04-24 07:24:00 +02:00
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" SELECT n.nspname as \" %s \" , \n "
2005-10-15 04:49:52 +02:00
" pg_catalog.format_type(t.oid, NULL) AS \" %s \" , \n " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Schema " ) ,
gettext_noop ( " Name " ) ) ;
2000-04-12 19:17:23 +02:00
if ( verbose )
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" t.typname AS \" %s \" , \n "
" CASE WHEN t.typrelid != 0 \n "
" THEN CAST('tuple' AS pg_catalog.text) \n "
" WHEN t.typlen < 0 \n "
" THEN CAST('var' AS pg_catalog.text) \n "
" ELSE CAST(t.typlen AS pg_catalog.text) \n "
2008-07-03 05:37:17 +02:00
" END AS \" %s \" , \n " ,
gettext_noop ( " Internal name " ) ,
gettext_noop ( " Size " ) ) ;
if ( verbose & & pset . sversion > = 80300 )
2010-10-25 05:04:37 +02:00
{
2008-07-03 05:37:17 +02:00
appendPQExpBuffer ( & buf ,
2008-05-05 02:11:31 +02:00
" pg_catalog.array_to_string( \n "
2008-07-03 05:37:17 +02:00
" ARRAY( \n "
2008-05-05 02:11:31 +02:00
" SELECT e.enumlabel \n "
" FROM pg_catalog.pg_enum e \n "
2010-10-25 05:04:37 +02:00
" WHERE e.enumtypid = t.oid \n " ) ;
if ( pset . sversion > = 90100 )
appendPQExpBuffer ( & buf ,
" ORDER BY e.enumsortorder \n " ) ;
else
appendPQExpBuffer ( & buf ,
" ORDER BY e.oid \n " ) ;
appendPQExpBuffer ( & buf ,
2008-05-05 02:11:31 +02:00
" ), \n "
" E' \\ n' \n "
" ) AS \" %s \" , \n " ,
gettext_noop ( " Elements " ) ) ;
2010-10-25 05:04:37 +02:00
}
2011-12-19 23:05:19 +01:00
if ( verbose & & pset . sversion > = 90200 )
{
printACLColumn ( & buf , " t.typacl " ) ;
appendPQExpBuffer ( & buf , " , \n " ) ;
}
2008-07-03 05:37:17 +02:00
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf ,
2009-06-11 16:49:15 +02:00
" pg_catalog.obj_description(t.oid, 'pg_type') as \" %s \" \n " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Description " ) ) ;
2000-04-12 19:17:23 +02:00
2002-08-10 05:56:24 +02:00
appendPQExpBuffer ( & buf , " FROM pg_catalog.pg_type t \n "
2005-10-15 04:49:52 +02:00
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace \n " ) ;
2002-08-10 05:56:24 +02:00
2000-04-12 19:17:23 +02:00
/*
2008-07-03 05:37:17 +02:00
* do not include complex types ( typrelid ! = 0 ) unless they are standalone
* composite types
2000-04-12 19:17:23 +02:00
*/
2002-08-15 18:36:08 +02:00
appendPQExpBuffer ( & buf , " WHERE (t.typrelid = 0 " ) ;
2002-08-29 02:17:06 +02:00
appendPQExpBuffer ( & buf , " OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c "
2008-07-03 05:37:17 +02:00
" WHERE c.oid = t.typrelid)) \n " ) ;
2009-06-11 16:49:15 +02:00
2008-07-03 05:37:17 +02:00
/*
* do not include array types ( before 8.3 we have to use the assumption
* that their names start with underscore )
*/
if ( pset . sversion > = 80300 )
appendPQExpBuffer ( & buf , " AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid) \n " ) ;
else
appendPQExpBuffer ( & buf , " AND t.typname !~ '^_' \n " ) ;
1999-11-05 00:14:30 +01:00
2009-06-11 16:49:15 +02:00
if ( ! showSystem & & ! pattern )
appendPQExpBuffer ( & buf , " AND n.nspname <> 'pg_catalog' \n "
" AND n.nspname <> 'information_schema' \n " ) ;
2009-01-06 22:10:30 +01:00
2002-08-10 05:56:24 +02:00
/* Match name pattern against either internal or external name */
2006-10-10 01:30:33 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , true , false ,
" n.nspname " , " t.typname " ,
" pg_catalog.format_type(t.oid, NULL) " ,
" pg_catalog.pg_type_is_visible(t.oid) " ) ;
1999-11-05 00:14:30 +01:00
2002-08-10 05:56:24 +02:00
appendPQExpBuffer ( & buf , " ORDER BY 1, 2; " ) ;
2002-04-24 07:24:00 +02:00
2002-10-15 04:24:16 +02:00
res = PSQLexec ( buf . data , false ) ;
2002-04-24 07:24:00 +02:00
termPQExpBuffer ( & buf ) ;
1999-11-05 00:14:30 +01:00
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
2001-06-30 19:26:12 +02:00
myopt . title = _ ( " List of data types " ) ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
1999-11-05 00:14:30 +01:00
2005-06-14 04:57:45 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
1999-11-05 00:14:30 +01:00
PQclear ( res ) ;
return true ;
1999-11-04 22:56:02 +01:00
}
/* \do
*/
bool
2009-01-06 22:10:30 +01:00
describeOperators ( const char * pattern , bool showSystem )
1999-11-04 22:56:02 +01:00
{
2002-04-24 07:24:00 +02:00
PQExpBufferData buf ;
1999-11-05 00:14:30 +01:00
PGresult * res ;
2000-01-14 23:18:03 +01:00
printQueryOpt myopt = pset . popt ;
1999-11-05 00:14:30 +01:00
2002-04-24 07:24:00 +02:00
initPQExpBuffer ( & buf ) ;
2011-03-03 07:33:19 +01:00
/*
* Note : before Postgres 9.1 , we did not assign comments to any built - in
* operators , preferring to let the comment on the underlying function
* suffice . The coalesce ( ) on the obj_description ( ) calls below supports
* this convention by providing a fallback lookup of a comment on the
* operator ' s function . As of 9.1 there is a policy that every built - in
* operator should have a comment ; so the coalesce ( ) is no longer
* necessary so far as built - in operators are concerned . We keep it
* anyway , for now , because ( 1 ) third - party modules may still be following
* the old convention , and ( 2 ) we ' d need to do it anyway when talking to a
* pre - 9.1 server .
*/
2002-04-24 07:24:00 +02:00
printfPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" SELECT n.nspname as \" %s \" , \n "
" o.oprname AS \" %s \" , \n "
" CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \" %s \" , \n "
" CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \" %s \" , \n "
2005-10-15 04:49:52 +02:00
" pg_catalog.format_type(o.oprresult, NULL) AS \" %s \" , \n "
" coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'), \n "
" pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \" %s \" \n "
2002-09-04 22:31:48 +02:00
" FROM pg_catalog.pg_operator o \n "
2005-10-15 04:49:52 +02:00
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace \n " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Schema " ) ,
gettext_noop ( " Name " ) ,
gettext_noop ( " Left arg type " ) ,
gettext_noop ( " Right arg type " ) ,
gettext_noop ( " Result type " ) ,
gettext_noop ( " Description " ) ) ;
2002-08-10 05:56:24 +02:00
2009-06-11 16:49:15 +02:00
if ( ! showSystem & & ! pattern )
appendPQExpBuffer ( & buf , " WHERE n.nspname <> 'pg_catalog' \n "
" AND n.nspname <> 'information_schema' \n " ) ;
2009-01-06 22:10:30 +01:00
2009-04-02 17:15:32 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , ! showSystem & & ! pattern , true ,
2006-10-10 01:30:33 +02:00
" n.nspname " , " o.oprname " , NULL ,
" pg_catalog.pg_operator_is_visible(o.oid) " ) ;
1999-11-05 00:14:30 +01:00
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf , " ORDER BY 1, 2, 3, 4; " ) ;
1999-11-05 00:14:30 +01:00
2002-10-15 04:24:16 +02:00
res = PSQLexec ( buf . data , false ) ;
2002-04-24 07:24:00 +02:00
termPQExpBuffer ( & buf ) ;
1999-11-05 00:14:30 +01:00
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
2001-06-30 19:26:12 +02:00
myopt . title = _ ( " List of operators " ) ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
1999-11-05 00:14:30 +01:00
2005-06-14 04:57:45 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
1999-11-05 00:14:30 +01:00
PQclear ( res ) ;
return true ;
1999-11-04 22:56:02 +01:00
}
/*
* listAllDbs
*
* for \ l , \ list , and - l switch
*/
bool
2002-08-27 20:28:29 +02:00
listAllDbs ( bool verbose )
1999-11-04 22:56:02 +01:00
{
1999-11-05 00:14:30 +01:00
PGresult * res ;
2002-04-24 07:24:00 +02:00
PQExpBufferData buf ;
2000-01-14 23:18:03 +01:00
printQueryOpt myopt = pset . popt ;
1999-11-04 22:56:02 +01:00
2002-04-24 07:24:00 +02:00
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" SELECT d.datname as \" %s \" , \n "
2009-06-11 16:49:15 +02:00
" pg_catalog.pg_get_userbyid(d.datdba) as \" %s \" , \n "
" pg_catalog.pg_encoding_to_char(d.encoding) as \" %s \" , \n " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Name " ) ,
gettext_noop ( " Owner " ) ,
2008-09-23 11:20:39 +02:00
gettext_noop ( " Encoding " ) ) ;
if ( pset . sversion > = 80400 )
appendPQExpBuffer ( & buf ,
" d.datcollate as \" %s \" , \n "
" d.datctype as \" %s \" , \n " ,
2011-02-12 14:54:13 +01:00
gettext_noop ( " Collate " ) ,
2008-09-23 11:20:39 +02:00
gettext_noop ( " Ctype " ) ) ;
2008-12-31 19:07:47 +01:00
appendPQExpBuffer ( & buf , " " ) ;
printACLColumn ( & buf , " d.datacl " ) ;
2008-07-03 05:37:17 +02:00
if ( verbose & & pset . sversion > = 80200 )
2008-03-30 20:10:20 +02:00
appendPQExpBuffer ( & buf ,
" , \n CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT') \n "
" THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname)) \n "
" ELSE 'No Access' \n "
" END as \" %s \" " ,
gettext_noop ( " Size " ) ) ;
2008-07-03 05:37:17 +02:00
if ( verbose & & pset . sversion > = 80000 )
2006-04-27 01:15:45 +02:00
appendPQExpBuffer ( & buf ,
" , \n t.spcname as \" %s \" " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Tablespace " ) ) ;
2008-07-03 05:37:17 +02:00
if ( verbose & & pset . sversion > = 80200 )
2009-06-11 16:49:15 +02:00
appendPQExpBuffer ( & buf ,
2006-02-12 04:22:21 +01:00
" , \n pg_catalog.shobj_description(d.oid, 'pg_database') as \" %s \" " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Description " ) ) ;
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf ,
2008-07-03 05:37:17 +02:00
" \n FROM pg_catalog.pg_database d \n " ) ;
if ( verbose & & pset . sversion > = 80000 )
2006-04-27 01:15:45 +02:00
appendPQExpBuffer ( & buf ,
2006-10-04 02:30:14 +02:00
" JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid \n " ) ;
appendPQExpBuffer ( & buf , " ORDER BY 1; " ) ;
2002-10-15 04:24:16 +02:00
res = PSQLexec ( buf . data , false ) ;
2002-04-24 07:24:00 +02:00
termPQExpBuffer ( & buf ) ;
1999-11-05 00:14:30 +01:00
if ( ! res )
return false ;
1999-11-04 22:56:02 +01:00
1999-11-05 00:14:30 +01:00
myopt . nullPrint = NULL ;
2001-06-30 19:26:12 +02:00
myopt . title = _ ( " List of databases " ) ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
1999-11-04 22:56:02 +01:00
2005-06-14 04:57:45 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
1999-11-04 22:56:02 +01:00
1999-11-05 00:14:30 +01:00
PQclear ( res ) ;
return true ;
1999-11-04 22:56:02 +01:00
}
2001-06-30 19:26:12 +02:00
/*
2009-01-22 21:16:10 +01:00
* List Tables ' Grant / Revoke Permissions
1999-11-04 22:56:02 +01:00
* \ z ( now also \ dp - - perhaps more mnemonic )
*/
bool
2002-08-10 05:56:24 +02:00
permissionsList ( const char * pattern )
1999-11-04 22:56:02 +01:00
{
2002-04-24 07:24:00 +02:00
PQExpBufferData buf ;
1999-11-05 00:14:30 +01:00
PGresult * res ;
2000-01-14 23:18:03 +01:00
printQueryOpt myopt = pset . popt ;
2009-01-22 21:16:10 +01:00
static const bool translate_columns [ ] = { false , false , true , false , false } ;
1999-11-05 00:14:30 +01:00
2002-04-24 07:24:00 +02:00
initPQExpBuffer ( & buf ) ;
2002-08-10 05:56:24 +02:00
/*
2005-10-15 04:49:52 +02:00
* we ignore indexes and toast tables since they have no meaningful rights
2002-08-10 05:56:24 +02:00
*/
2002-04-24 07:24:00 +02:00
printfPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" SELECT n.nspname as \" %s \" , \n "
" c.relname as \" %s \" , \n "
2011-01-02 05:48:11 +01:00
" CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'S' THEN '%s' WHEN 'f' THEN '%s' END as \" %s \" , \n "
2008-12-31 19:07:47 +01:00
" " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Schema " ) ,
gettext_noop ( " Name " ) ,
2009-06-11 16:49:15 +02:00
gettext_noop ( " table " ) , gettext_noop ( " view " ) , gettext_noop ( " sequence " ) ,
2011-04-10 17:42:00 +02:00
gettext_noop ( " foreign table " ) ,
2008-07-03 05:37:17 +02:00
gettext_noop ( " Type " ) ) ;
2009-01-22 21:16:10 +01:00
2008-12-31 19:07:47 +01:00
printACLColumn ( & buf , " c.relacl " ) ;
2009-01-22 21:16:10 +01:00
if ( pset . sversion > = 80400 )
appendPQExpBuffer ( & buf ,
" , \n pg_catalog.array_to_string(ARRAY( \n "
" SELECT attname || E': \\ n ' || pg_catalog.array_to_string(attacl, E' \\ n ') \n "
" FROM pg_catalog.pg_attribute a \n "
" WHERE attrelid = c.oid AND NOT attisdropped AND attacl IS NOT NULL \n "
" ), E' \\ n') AS \" %s \" " ,
gettext_noop ( " Column access privileges " ) ) ;
2008-12-31 19:07:47 +01:00
appendPQExpBuffer ( & buf , " \n FROM pg_catalog.pg_class c \n "
2008-07-03 05:37:17 +02:00
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace \n "
2011-01-02 05:48:11 +01:00
" WHERE c.relkind IN ('r', 'v', 'S', 'f') \n " ) ;
2008-07-03 05:37:17 +02:00
2002-08-10 05:56:24 +02:00
/*
* Unless a schema pattern is specified , we suppress system and temp
2005-10-15 04:49:52 +02:00
* tables , since they normally aren ' t very interesting from a permissions
* point of view . You can see ' em by explicit request though , eg with \ z
* pg_catalog . *
2002-08-10 05:56:24 +02:00
*/
2006-10-10 01:30:33 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , true , false ,
" n.nspname " , " c.relname " , NULL ,
2005-10-15 04:49:52 +02:00
" n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid) " ) ;
2002-08-10 05:56:24 +02:00
appendPQExpBuffer ( & buf , " ORDER BY 1, 2; " ) ;
1999-11-04 22:56:02 +01:00
2002-10-15 04:24:16 +02:00
res = PSQLexec ( buf . data , false ) ;
1999-11-05 00:14:30 +01:00
if ( ! res )
2002-04-24 07:24:00 +02:00
{
termPQExpBuffer ( & buf ) ;
1999-11-05 00:14:30 +01:00
return false ;
2002-04-24 07:24:00 +02:00
}
1999-11-05 00:14:30 +01:00
2000-04-12 19:17:23 +02:00
myopt . nullPrint = NULL ;
2008-07-03 17:59:55 +02:00
printfPQExpBuffer ( & buf , _ ( " Access privileges " ) ) ;
2002-04-24 07:24:00 +02:00
myopt . title = buf . data ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
myopt . translate_columns = translate_columns ;
1999-11-04 22:56:02 +01:00
2005-06-14 04:57:45 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
1999-11-05 00:14:30 +01:00
2002-04-24 07:24:00 +02:00
termPQExpBuffer ( & buf ) ;
1999-11-05 00:14:30 +01:00
PQclear ( res ) ;
return true ;
1999-11-04 22:56:02 +01:00
}
2009-10-05 21:24:49 +02:00
/*
* \ ddp
*
* List DefaultACLs . The pattern can match either schema or role name .
*/
bool
listDefaultACLs ( const char * pattern )
{
PQExpBufferData buf ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
static const bool translate_columns [ ] = { false , false , true , false } ;
2010-02-17 05:19:41 +01:00
if ( pset . sversion < 90000 )
2009-10-05 21:24:49 +02:00
{
fprintf ( stderr , _ ( " The server (version %d.%d) does not support altering default privileges. \n " ) ,
pset . sversion / 10000 , ( pset . sversion / 100 ) % 100 ) ;
return true ;
}
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
2010-02-26 03:01:40 +01:00
" SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \" %s \" , \n "
2009-10-05 21:24:49 +02:00
" n.nspname AS \" %s \" , \n "
" CASE d.defaclobjtype WHEN 'r' THEN '%s' WHEN 'S' THEN '%s' WHEN 'f' THEN '%s' END AS \" %s \" , \n "
" " ,
gettext_noop ( " Owner " ) ,
gettext_noop ( " Schema " ) ,
gettext_noop ( " table " ) ,
gettext_noop ( " sequence " ) ,
gettext_noop ( " function " ) ,
gettext_noop ( " Type " ) ) ;
printACLColumn ( & buf , " d.defaclacl " ) ;
appendPQExpBuffer ( & buf , " \n FROM pg_catalog.pg_default_acl d \n "
2010-02-26 03:01:40 +01:00
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace \n " ) ;
2009-10-05 21:24:49 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , false , false ,
NULL ,
" n.nspname " ,
" pg_catalog.pg_get_userbyid(d.defaclrole) " ,
NULL ) ;
appendPQExpBuffer ( & buf , " ORDER BY 1, 2, 3; " ) ;
res = PSQLexec ( buf . data , false ) ;
if ( ! res )
{
termPQExpBuffer ( & buf ) ;
return false ;
}
myopt . nullPrint = NULL ;
printfPQExpBuffer ( & buf , _ ( " Default access privileges " ) ) ;
myopt . title = buf . data ;
myopt . translate_header = true ;
myopt . translate_columns = translate_columns ;
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
termPQExpBuffer ( & buf ) ;
PQclear ( res ) ;
return true ;
}
1999-11-04 22:56:02 +01:00
/*
* Get object comments
*
* \ dd [ foo ]
*
2011-08-11 17:16:29 +02:00
* Note : This command only lists comments for object types which do not have
* their comments displayed by their own backslash commands . The following
* types of objects will be displayed : constraint , operator class ,
* operator family , rule , and trigger .
*
1999-11-04 22:56:02 +01:00
*/
bool
2009-01-06 22:10:30 +01:00
objectDescription ( const char * pattern , bool showSystem )
1999-11-04 22:56:02 +01:00
{
2002-04-24 07:24:00 +02:00
PQExpBufferData buf ;
1999-11-05 00:14:30 +01:00
PGresult * res ;
2000-01-14 23:18:03 +01:00
printQueryOpt myopt = pset . popt ;
2008-07-15 00:00:04 +02:00
static const bool translate_columns [ ] = { false , false , true , false } ;
1999-11-05 00:14:30 +01:00
2002-04-24 07:24:00 +02:00
initPQExpBuffer ( & buf ) ;
2002-08-10 05:56:24 +02:00
appendPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" SELECT DISTINCT tt.nspname AS \" %s \" , tt.name AS \" %s \" , tt.object AS \" %s \" , d.description AS \" %s \" \n "
" FROM ( \n " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Schema " ) ,
gettext_noop ( " Name " ) ,
gettext_noop ( " Object " ) ,
gettext_noop ( " Description " ) ) ;
2001-06-30 19:26:12 +02:00
2011-08-11 17:16:29 +02:00
/* Constraint descriptions */
2002-08-10 05:56:24 +02:00
appendPQExpBuffer ( & buf ,
2011-08-11 17:16:29 +02:00
" SELECT pgc.oid as oid, pgc.tableoid AS tableoid, \n "
2002-09-04 22:31:48 +02:00
" n.nspname as nspname, \n "
2011-08-11 17:16:29 +02:00
" CAST(pgc.conname AS pg_catalog.text) as name, "
2002-09-04 22:31:48 +02:00
" CAST('%s' AS pg_catalog.text) as object \n "
2011-08-11 17:16:29 +02:00
" FROM pg_catalog.pg_constraint pgc \n "
" JOIN pg_catalog.pg_class c "
" ON c.oid = pgc.conrelid \n "
" LEFT JOIN pg_catalog.pg_namespace n "
" ON n.oid = c.relnamespace \n " ,
gettext_noop ( " constraint " ) ) ;
2009-01-06 22:10:30 +01:00
2009-06-11 16:49:15 +02:00
if ( ! showSystem & & ! pattern )
appendPQExpBuffer ( & buf , " WHERE n.nspname <> 'pg_catalog' \n "
" AND n.nspname <> 'information_schema' \n " ) ;
2011-08-11 17:16:29 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , ! showSystem & & ! pattern ,
false , " n.nspname " , " pgc.conname " , NULL ,
2006-10-10 01:30:33 +02:00
" pg_catalog.pg_table_is_visible(c.oid) " ) ;
2001-06-30 19:26:12 +02:00
2011-08-11 17:16:29 +02:00
/*
2011-11-12 05:33:44 +01:00
* pg_opclass . opcmethod only available in 8.3 +
2011-08-11 17:16:29 +02:00
*/
if ( pset . sversion > = 80300 )
{
/* Operator class descriptions */
appendPQExpBuffer ( & buf ,
" UNION ALL \n "
" SELECT o.oid as oid, o.tableoid as tableoid, \n "
" n.nspname as nspname, \n "
" CAST(o.opcname AS pg_catalog.text) as name, \n "
" CAST('%s' AS pg_catalog.text) as object \n "
" FROM pg_catalog.pg_opclass o \n "
" JOIN pg_catalog.pg_am am ON "
" o.opcmethod = am.oid \n "
" JOIN pg_catalog.pg_namespace n ON "
" n.oid = o.opcnamespace \n " ,
gettext_noop ( " operator class " ) ) ;
if ( ! showSystem & & ! pattern )
appendPQExpBuffer ( & buf , " AND n.nspname <> 'pg_catalog' \n "
2012-06-10 21:20:04 +02:00
" AND n.nspname <> 'information_schema' \n " ) ;
2011-08-11 17:16:29 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , true , false ,
" n.nspname " , " o.opcname " , NULL ,
" pg_catalog.pg_opclass_is_visible(o.oid) " ) ;
2011-11-12 05:33:44 +01:00
}
2011-08-11 17:16:29 +02:00
2011-11-12 05:33:44 +01:00
/*
* although operator family comments have been around since 8.3 ,
* pg_opfamily_is_visible is only available in 9.2 +
*/
if ( pset . sversion > = 90200 )
{
2011-08-11 17:16:29 +02:00
/* Operator family descriptions */
appendPQExpBuffer ( & buf ,
" UNION ALL \n "
2012-06-10 21:20:04 +02:00
" SELECT opf.oid as oid, opf.tableoid as tableoid, \n "
2011-08-11 17:16:29 +02:00
" n.nspname as nspname, \n "
" CAST(opf.opfname AS pg_catalog.text) AS name, \n "
" CAST('%s' AS pg_catalog.text) as object \n "
" FROM pg_catalog.pg_opfamily opf \n "
" JOIN pg_catalog.pg_am am "
" ON opf.opfmethod = am.oid \n "
" JOIN pg_catalog.pg_namespace n "
" ON opf.opfnamespace = n.oid \n " ,
gettext_noop ( " operator family " ) ) ;
if ( ! showSystem & & ! pattern )
appendPQExpBuffer ( & buf , " AND n.nspname <> 'pg_catalog' \n "
2012-06-10 21:20:04 +02:00
" AND n.nspname <> 'information_schema' \n " ) ;
2011-08-11 17:16:29 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , true , false ,
" n.nspname " , " opf.opfname " , NULL ,
" pg_catalog.pg_opfamily_is_visible(opf.oid) " ) ;
}
2011-03-03 07:33:19 +01:00
/* Rule descriptions (ignore rules for views) */
2002-08-10 05:56:24 +02:00
appendPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" UNION ALL \n "
" SELECT r.oid as oid, r.tableoid as tableoid, \n "
" n.nspname as nspname, \n "
" CAST(r.rulename AS pg_catalog.text) as name, "
" CAST('%s' AS pg_catalog.text) as object \n "
" FROM pg_catalog.pg_rewrite r \n "
2005-10-15 04:49:52 +02:00
" JOIN pg_catalog.pg_class c ON c.oid = r.ev_class \n "
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace \n "
2002-09-04 22:31:48 +02:00
" WHERE r.rulename != '_RETURN' \n " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " rule " ) ) ;
2009-01-06 22:10:30 +01:00
2009-06-11 16:49:15 +02:00
if ( ! showSystem & & ! pattern )
appendPQExpBuffer ( & buf , " AND n.nspname <> 'pg_catalog' \n "
" AND n.nspname <> 'information_schema' \n " ) ;
2009-01-06 22:10:30 +01:00
2006-10-10 01:30:33 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , true , false ,
" n.nspname " , " r.rulename " , NULL ,
" pg_catalog.pg_table_is_visible(c.oid) " ) ;
2001-06-30 19:26:12 +02:00
2011-03-03 07:33:19 +01:00
/* Trigger descriptions */
2002-08-10 05:56:24 +02:00
appendPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" UNION ALL \n "
" SELECT t.oid as oid, t.tableoid as tableoid, \n "
" n.nspname as nspname, \n "
" CAST(t.tgname AS pg_catalog.text) as name, "
" CAST('%s' AS pg_catalog.text) as object \n "
" FROM pg_catalog.pg_trigger t \n "
2005-10-15 04:49:52 +02:00
" JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid \n "
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace \n " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " trigger " ) ) ;
2009-04-02 19:38:26 +02:00
2009-06-11 16:49:15 +02:00
if ( ! showSystem & & ! pattern )
appendPQExpBuffer ( & buf , " WHERE n.nspname <> 'pg_catalog' \n "
" AND n.nspname <> 'information_schema' \n " ) ;
2009-01-06 22:10:30 +01:00
2009-04-02 17:15:32 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , ! showSystem & & ! pattern , false ,
2006-10-10 01:30:33 +02:00
" n.nspname " , " t.tgname " , NULL ,
" pg_catalog.pg_table_is_visible(c.oid) " ) ;
2002-08-10 05:56:24 +02:00
appendPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" ) AS tt \n "
2003-10-26 03:53:45 +01:00
" JOIN pg_catalog.pg_description d ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0) \n " ) ;
2002-08-10 05:56:24 +02:00
appendPQExpBuffer ( & buf , " ORDER BY 1, 2, 3; " ) ;
1999-11-05 00:14:30 +01:00
2002-10-15 04:24:16 +02:00
res = PSQLexec ( buf . data , false ) ;
2002-04-24 07:24:00 +02:00
termPQExpBuffer ( & buf ) ;
1999-11-05 00:14:30 +01:00
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
2001-06-30 19:26:12 +02:00
myopt . title = _ ( " Object descriptions " ) ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
myopt . translate_columns = translate_columns ;
1999-11-05 00:14:30 +01:00
2005-06-14 04:57:45 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
1999-11-05 00:14:30 +01:00
PQclear ( res ) ;
return true ;
1999-11-04 22:56:02 +01:00
}
/*
* describeTableDetails ( for \ d )
*
2002-08-10 05:56:24 +02:00
* This routine finds the tables to be displayed , and calls
* describeOneTableDetails for each one .
2004-04-22 19:38:16 +02:00
*
* verbose : if true , this is \ d +
1999-11-04 22:56:02 +01:00
*/
2002-08-10 05:56:24 +02:00
bool
2009-01-20 03:13:42 +01:00
describeTableDetails ( const char * pattern , bool verbose , bool showSystem )
1999-11-04 22:56:02 +01:00
{
2002-08-10 05:56:24 +02:00
PQExpBufferData buf ;
PGresult * res ;
int i ;
1999-11-05 00:14:30 +01:00
2002-08-10 05:56:24 +02:00
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" SELECT c.oid, \n "
" n.nspname, \n "
" c.relname \n "
" FROM pg_catalog.pg_class c \n "
2005-10-15 04:49:52 +02:00
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace \n " ) ;
2002-08-10 05:56:24 +02:00
2009-06-11 16:49:15 +02:00
if ( ! showSystem & & ! pattern )
appendPQExpBuffer ( & buf , " WHERE n.nspname <> 'pg_catalog' \n "
" AND n.nspname <> 'information_schema' \n " ) ;
2009-01-20 03:13:42 +01:00
2009-04-02 17:15:32 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , ! showSystem & & ! pattern , false ,
2006-10-10 01:30:33 +02:00
" n.nspname " , " c.relname " , NULL ,
" pg_catalog.pg_table_is_visible(c.oid) " ) ;
2002-08-10 05:56:24 +02:00
appendPQExpBuffer ( & buf , " ORDER BY 2, 3; " ) ;
2002-10-15 04:24:16 +02:00
res = PSQLexec ( buf . data , false ) ;
2002-08-10 05:56:24 +02:00
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
if ( PQntuples ( res ) = = 0 )
1999-11-05 00:14:30 +01:00
{
2006-08-29 17:19:51 +02:00
if ( ! pset . quiet )
2002-08-10 05:56:24 +02:00
fprintf ( stderr , _ ( " Did not find any relation named \" %s \" . \n " ) ,
pattern ) ;
PQclear ( res ) ;
return false ;
1999-11-05 00:14:30 +01:00
}
1999-11-04 22:56:02 +01:00
2002-08-10 05:56:24 +02:00
for ( i = 0 ; i < PQntuples ( res ) ; i + + )
{
const char * oid ;
const char * nspname ;
const char * relname ;
oid = PQgetvalue ( res , i , 0 ) ;
nspname = PQgetvalue ( res , i , 1 ) ;
relname = PQgetvalue ( res , i , 2 ) ;
1999-11-04 22:56:02 +01:00
2002-08-10 05:56:24 +02:00
if ( ! describeOneTableDetails ( nspname , relname , oid , verbose ) )
{
PQclear ( res ) ;
return false ;
}
2006-06-14 18:49:03 +02:00
if ( cancel_pressed )
{
PQclear ( res ) ;
return false ;
}
2002-08-10 05:56:24 +02:00
}
PQclear ( res ) ;
return true ;
}
/*
* describeOneTableDetails ( for \ d )
*
* Unfortunately , the information presented here is so complicated that it
* cannot be done in a single query . So we have to assemble the printed table
* by hand and pass it to the underlying printTable ( ) function .
*/
static bool
describeOneTableDetails ( const char * schemaname ,
const char * relationname ,
const char * oid ,
bool verbose )
1999-11-04 22:56:02 +01:00
{
2002-04-24 07:24:00 +02:00
PQExpBufferData buf ;
* Includes tab completion. It's not magic, but it's very cool. At any
rate
it's better than what used to be there.
* Does proper SQL "host variable" substitution as pointed out by Andreas
Zeugwetter (thanks): select * from :foo; Also some changes in how ':'
and ';' are treated (escape with \ to send to backend). This does
_not_
affect the '::' cast operator, but perhaps others that contain : or ;
(but there are none right now).
* To show description with a <something> listing, append '?' to command
name, e.g., \df?. This seemed to be the convenient and logical
solution.
Or append a '+' to see more useless information, e.g., \df+.
* Fixed fflush()'ing bug pointed out by Jan during the regression test
discussion.
* Added LastOid variable. This ought to take care of TODO item "Add a
function to return the last inserted oid, for use in psql scripts"
(under CLIENTS)
E.g.,
insert into foo values(...);
insert into bar values(..., :LastOid);
\echo $LastOid
* \d command shows constraints, rules, and triggers defined on the table
(in addition to indices)
* Various fixes, optimizations, corrections
* Documentation update as well
Note: This now requires snprintf(), which, if necessary, is taken from
src/backend/port. This is certainly a little weird, but it should
suffice
until a source tree cleanup is done.
Enjoy.
--
Peter Eisentraut Sernanders väg 10:115
1999-11-26 05:24:17 +01:00
PGresult * res = NULL ;
2000-01-14 23:18:03 +01:00
printTableOpt myopt = pset . popt . topt ;
2008-05-13 00:59:58 +02:00
printTableContent cont ;
2009-06-11 16:49:15 +02:00
bool printTableInitialized = false ;
1999-11-05 00:14:30 +01:00
int i ;
2002-09-04 22:31:48 +02:00
char * view_def = NULL ;
2012-04-06 21:02:35 +02:00
char * headers [ 9 ] ;
2008-07-15 05:16:03 +02:00
char * * seq_values = NULL ;
2008-05-13 00:59:58 +02:00
char * * modifiers = NULL ;
1999-11-05 00:14:30 +01:00
char * * ptr ;
2002-04-24 07:24:00 +02:00
PQExpBufferData title ;
2002-12-21 02:07:07 +01:00
PQExpBufferData tmpbuf ;
2009-07-07 18:28:38 +02:00
int cols ;
2002-12-21 02:07:07 +01:00
int numrows = 0 ;
2000-04-12 19:17:23 +02:00
struct
{
int16 checks ;
2004-04-22 19:38:16 +02:00
char relkind ;
bool hasindex ;
2000-04-12 19:17:23 +02:00
bool hasrules ;
2008-11-09 22:24:33 +01:00
bool hastriggers ;
2004-08-29 07:07:03 +02:00
bool hasoids ;
2004-07-12 22:41:13 +02:00
Oid tablespace ;
2008-12-19 15:39:58 +01:00
char * reloptions ;
2010-01-29 00:21:13 +01:00
char * reloftype ;
2010-12-29 12:48:53 +01:00
char relpersistence ;
2000-04-12 19:17:23 +02:00
} tableinfo ;
2002-12-21 02:07:07 +01:00
bool show_modifiers = false ;
2002-04-24 07:24:00 +02:00
bool retval ;
2000-04-12 19:17:23 +02:00
2002-04-24 07:24:00 +02:00
retval = false ;
1999-11-05 00:14:30 +01:00
2012-05-01 22:03:45 +02:00
myopt . default_footer = false ;
2005-10-27 15:34:47 +02:00
/* This output looks confusing in expanded mode. */
myopt . expanded = false ;
2002-04-24 07:24:00 +02:00
initPQExpBuffer ( & buf ) ;
initPQExpBuffer ( & title ) ;
2002-12-21 02:07:07 +01:00
initPQExpBuffer ( & tmpbuf ) ;
1999-11-04 22:56:02 +01:00
1999-11-05 00:14:30 +01:00
/* Get general table info */
2011-01-24 13:30:42 +01:00
if ( pset . sversion > = 90100 )
2010-12-29 12:48:53 +01:00
{
printfPQExpBuffer ( & buf ,
" SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
" c.relhastriggers, c.relhasoids, "
" %s, c.reltablespace, "
" CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
" c.relpersistence \n "
" FROM pg_catalog.pg_class c \n "
" LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid) \n "
2011-07-06 16:11:20 +02:00
" WHERE c.oid = '%s'; " ,
2010-12-29 12:48:53 +01:00
( verbose ?
" pg_catalog.array_to_string(c.reloptions || "
" array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ') \n "
: " '' " ) ,
oid ) ;
}
else if ( pset . sversion > = 90000 )
2009-12-07 06:22:23 +01:00
{
printfPQExpBuffer ( & buf ,
" SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
" c.relhastriggers, c.relhasoids, "
2010-03-11 22:29:32 +01:00
" %s, c.reltablespace, "
" CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END \n "
2009-12-07 06:22:23 +01:00
" FROM pg_catalog.pg_class c \n "
" LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid) \n "
2011-07-06 16:11:20 +02:00
" WHERE c.oid = '%s'; " ,
2009-12-07 06:22:23 +01:00
( verbose ?
" pg_catalog.array_to_string(c.reloptions || "
" array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ') \n "
: " '' " ) ,
oid ) ;
}
else if ( pset . sversion > = 80400 )
2009-02-11 20:12:04 +01:00
{
printfPQExpBuffer ( & buf ,
2009-06-11 16:49:15 +02:00
" SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
2009-02-11 20:12:04 +01:00
" c.relhastriggers, c.relhasoids, "
" %s, c.reltablespace \n "
" FROM pg_catalog.pg_class c \n "
2009-06-11 16:49:15 +02:00
" LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid) \n "
2011-07-06 16:11:20 +02:00
" WHERE c.oid = '%s'; " ,
2009-02-11 20:12:04 +01:00
( verbose ?
2009-06-11 16:49:15 +02:00
" pg_catalog.array_to_string(c.reloptions || "
" array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ') \n "
: " '' " ) ,
2009-02-11 20:12:04 +01:00
oid ) ;
}
else if ( pset . sversion > = 80200 )
{
printfPQExpBuffer ( & buf ,
2009-06-11 16:49:15 +02:00
" SELECT relchecks, relkind, relhasindex, relhasrules, "
2009-02-11 20:12:04 +01:00
" reltriggers <> 0, relhasoids, "
" %s, reltablespace \n "
2011-07-06 16:11:20 +02:00
" FROM pg_catalog.pg_class WHERE oid = '%s'; " ,
2009-02-11 20:12:04 +01:00
( verbose ?
2009-06-11 16:49:15 +02:00
" pg_catalog.array_to_string(reloptions, E', ') " : " '' " ) ,
2009-02-11 20:12:04 +01:00
oid ) ;
}
else if ( pset . sversion > = 80000 )
{
printfPQExpBuffer ( & buf ,
2009-06-11 16:49:15 +02:00
" SELECT relchecks, relkind, relhasindex, relhasrules, "
2009-02-11 20:12:04 +01:00
" reltriggers <> 0, relhasoids, "
" '', reltablespace \n "
2011-07-06 16:11:20 +02:00
" FROM pg_catalog.pg_class WHERE oid = '%s'; " ,
2009-02-11 20:12:04 +01:00
oid ) ;
}
else
{
printfPQExpBuffer ( & buf ,
2009-06-11 16:49:15 +02:00
" SELECT relchecks, relkind, relhasindex, relhasrules, "
2009-02-11 20:12:04 +01:00
" reltriggers <> 0, relhasoids, "
" '', '' \n "
2011-07-06 16:11:20 +02:00
" FROM pg_catalog.pg_class WHERE oid = '%s'; " ,
2009-02-11 20:12:04 +01:00
oid ) ;
}
2002-10-15 04:24:16 +02:00
res = PSQLexec ( buf . data , false ) ;
2000-04-12 19:17:23 +02:00
if ( ! res )
2002-04-24 07:24:00 +02:00
goto error_return ;
1999-11-05 00:14:30 +01:00
/* Did we get anything? */
if ( PQntuples ( res ) = = 0 )
{
2006-08-29 17:19:51 +02:00
if ( ! pset . quiet )
2003-07-23 10:47:41 +02:00
fprintf ( stderr , _ ( " Did not find any relation with OID %s. \n " ) ,
2002-08-10 05:56:24 +02:00
oid ) ;
2002-04-24 07:24:00 +02:00
goto error_return ;
1999-11-05 00:14:30 +01:00
}
2008-11-09 22:24:33 +01:00
tableinfo . checks = atoi ( PQgetvalue ( res , 0 , 0 ) ) ;
2004-04-22 19:38:16 +02:00
tableinfo . relkind = * ( PQgetvalue ( res , 0 , 1 ) ) ;
2008-11-09 22:24:33 +01:00
tableinfo . hasindex = strcmp ( PQgetvalue ( res , 0 , 2 ) , " t " ) = = 0 ;
tableinfo . hasrules = strcmp ( PQgetvalue ( res , 0 , 3 ) , " t " ) = = 0 ;
tableinfo . hastriggers = strcmp ( PQgetvalue ( res , 0 , 4 ) , " t " ) = = 0 ;
2004-04-22 19:38:16 +02:00
tableinfo . hasoids = strcmp ( PQgetvalue ( res , 0 , 5 ) , " t " ) = = 0 ;
2009-12-07 06:22:23 +01:00
tableinfo . reloptions = ( pset . sversion > = 80200 ) ?
2009-06-11 16:49:15 +02:00
strdup ( PQgetvalue ( res , 0 , 6 ) ) : 0 ;
2004-11-05 20:17:13 +01:00
tableinfo . tablespace = ( pset . sversion > = 80000 ) ?
2009-06-11 16:49:15 +02:00
atooid ( PQgetvalue ( res , 0 , 7 ) ) : 0 ;
2010-03-11 22:29:32 +01:00
tableinfo . reloftype = ( pset . sversion > = 90000 & & strcmp ( PQgetvalue ( res , 0 , 8 ) , " " ) ! = 0 ) ?
strdup ( PQgetvalue ( res , 0 , 8 ) ) : 0 ;
2010-12-29 12:48:53 +01:00
tableinfo . relpersistence = ( pset . sversion > = 90100 & & strcmp ( PQgetvalue ( res , 0 , 9 ) , " " ) ! = 0 ) ?
PQgetvalue ( res , 0 , 9 ) [ 0 ] : 0 ;
2000-04-12 19:17:23 +02:00
PQclear ( res ) ;
2008-11-03 20:08:56 +01:00
res = NULL ;
2009-06-11 16:49:15 +02:00
2008-07-15 05:16:03 +02:00
/*
2009-06-11 16:49:15 +02:00
* If it ' s a sequence , fetch its values and store into an array that will
* be used later .
2008-07-15 05:16:03 +02:00
*/
if ( tableinfo . relkind = = ' S ' )
{
2009-07-20 05:46:45 +02:00
printfPQExpBuffer ( & buf , " SELECT * FROM %s " , fmtId ( schemaname ) ) ;
2008-11-03 20:08:56 +01:00
/* must be separate because fmtId isn't reentrant */
2011-07-06 16:11:20 +02:00
appendPQExpBuffer ( & buf , " .%s; " , fmtId ( relationname ) ) ;
2009-06-11 16:49:15 +02:00
2009-07-20 05:46:45 +02:00
res = PSQLexec ( buf . data , false ) ;
if ( ! res )
2008-07-15 05:16:03 +02:00
goto error_return ;
2009-06-11 16:49:15 +02:00
2009-07-20 05:46:45 +02:00
seq_values = pg_malloc ( ( PQnfields ( res ) + 1 ) * sizeof ( * seq_values ) ) ;
2009-06-11 16:49:15 +02:00
2009-07-20 05:46:45 +02:00
for ( i = 0 ; i < PQnfields ( res ) ; i + + )
seq_values [ i ] = pg_strdup ( PQgetvalue ( res , 0 , i ) ) ;
seq_values [ i ] = NULL ;
2009-06-11 16:49:15 +02:00
2009-07-20 05:46:45 +02:00
PQclear ( res ) ;
res = NULL ;
2008-07-15 05:16:03 +02:00
}
1999-11-05 00:14:30 +01:00
2011-08-05 19:24:03 +02:00
/*
* Get column info
*
2011-11-04 15:57:43 +01:00
* You need to modify value of " firstvcol " which will be defined below if
2011-08-05 19:24:03 +02:00
* you are adding column ( s ) preceding to verbose - only columns .
*/
2003-05-28 18:04:02 +02:00
printfPQExpBuffer ( & buf , " SELECT a.attname, " ) ;
2003-02-24 04:54:06 +01:00
appendPQExpBuffer ( & buf , " \n pg_catalog.format_type(a.atttypid, a.atttypmod), "
2005-10-03 01:50:16 +02:00
" \n (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128) "
" \n FROM pg_catalog.pg_attrdef d "
2003-02-24 04:54:06 +01:00
" \n WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef), "
2011-04-18 00:09:22 +02:00
" \n a.attnotnull, a.attnum, " ) ;
2011-02-08 22:04:18 +01:00
if ( pset . sversion > = 90100 )
2011-04-18 00:09:22 +02:00
appendPQExpBuffer ( & buf , " \n (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type t \n "
" WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation) AS attcollation " ) ;
2011-02-08 22:04:18 +01:00
else
2011-04-18 00:09:22 +02:00
appendPQExpBuffer ( & buf , " \n NULL AS attcollation " ) ;
2009-07-06 19:01:42 +02:00
if ( tableinfo . relkind = = ' i ' )
2009-07-07 18:28:38 +02:00
appendPQExpBuffer ( & buf , " , \n pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef " ) ;
2011-08-05 19:24:03 +02:00
else
appendPQExpBuffer ( & buf , " , \n NULL AS indexdef " ) ;
if ( tableinfo . relkind = = ' f ' & & pset . sversion > = 90200 )
2011-08-25 18:47:30 +02:00
appendPQExpBuffer ( & buf , " , \n CASE WHEN attfdwoptions IS NULL THEN '' ELSE "
2012-06-10 21:20:04 +02:00
" '(' || array_to_string(ARRAY(SELECT quote_ident(option_name) || ' ' || quote_literal(option_value) FROM "
" pg_options_to_table(attfdwoptions)), ', ') || ')' END AS attfdwoptions " ) ;
2011-08-05 19:24:03 +02:00
else
appendPQExpBuffer ( & buf , " , \n NULL AS attfdwoptions " ) ;
2002-08-10 05:56:24 +02:00
if ( verbose )
2011-07-26 15:52:31 +02:00
{
appendPQExpBuffer ( & buf , " , \n a.attstorage " ) ;
2011-11-05 13:02:48 +01:00
appendPQExpBuffer ( & buf , " , \n CASE WHEN a.attstattarget=-1 THEN NULL ELSE a.attstattarget END AS attstattarget " ) ;
2012-06-10 21:20:04 +02:00
2011-07-26 15:52:31 +02:00
/*
* In 9.0 + , we have column comments for : relations , views , composite
* types , and foreign tables ( c . f . CommentObject ( ) in comment . c ) .
*/
if ( tableinfo . relkind = = ' r ' | | tableinfo . relkind = = ' v ' | |
tableinfo . relkind = = ' f ' | | tableinfo . relkind = = ' c ' )
appendPQExpBuffer ( & buf , " , pg_catalog.col_description(a.attrelid, a.attnum) " ) ;
}
2002-08-10 05:56:24 +02:00
appendPQExpBuffer ( & buf , " \n FROM pg_catalog.pg_attribute a " ) ;
appendPQExpBuffer ( & buf , " \n WHERE a.attrelid = '%s' AND a.attnum > 0 AND NOT a.attisdropped " , oid ) ;
2011-07-06 16:11:20 +02:00
appendPQExpBuffer ( & buf , " \n ORDER BY a.attnum; " ) ;
* Includes tab completion. It's not magic, but it's very cool. At any
rate
it's better than what used to be there.
* Does proper SQL "host variable" substitution as pointed out by Andreas
Zeugwetter (thanks): select * from :foo; Also some changes in how ':'
and ';' are treated (escape with \ to send to backend). This does
_not_
affect the '::' cast operator, but perhaps others that contain : or ;
(but there are none right now).
* To show description with a <something> listing, append '?' to command
name, e.g., \df?. This seemed to be the convenient and logical
solution.
Or append a '+' to see more useless information, e.g., \df+.
* Fixed fflush()'ing bug pointed out by Jan during the regression test
discussion.
* Added LastOid variable. This ought to take care of TODO item "Add a
function to return the last inserted oid, for use in psql scripts"
(under CLIENTS)
E.g.,
insert into foo values(...);
insert into bar values(..., :LastOid);
\echo $LastOid
* \d command shows constraints, rules, and triggers defined on the table
(in addition to indices)
* Various fixes, optimizations, corrections
* Documentation update as well
Note: This now requires snprintf(), which, if necessary, is taken from
src/backend/port. This is certainly a little weird, but it should
suffice
until a source tree cleanup is done.
Enjoy.
--
Peter Eisentraut Sernanders väg 10:115
1999-11-26 05:24:17 +01:00
2002-10-15 04:24:16 +02:00
res = PSQLexec ( buf . data , false ) ;
* Includes tab completion. It's not magic, but it's very cool. At any
rate
it's better than what used to be there.
* Does proper SQL "host variable" substitution as pointed out by Andreas
Zeugwetter (thanks): select * from :foo; Also some changes in how ':'
and ';' are treated (escape with \ to send to backend). This does
_not_
affect the '::' cast operator, but perhaps others that contain : or ;
(but there are none right now).
* To show description with a <something> listing, append '?' to command
name, e.g., \df?. This seemed to be the convenient and logical
solution.
Or append a '+' to see more useless information, e.g., \df+.
* Fixed fflush()'ing bug pointed out by Jan during the regression test
discussion.
* Added LastOid variable. This ought to take care of TODO item "Add a
function to return the last inserted oid, for use in psql scripts"
(under CLIENTS)
E.g.,
insert into foo values(...);
insert into bar values(..., :LastOid);
\echo $LastOid
* \d command shows constraints, rules, and triggers defined on the table
(in addition to indices)
* Various fixes, optimizations, corrections
* Documentation update as well
Note: This now requires snprintf(), which, if necessary, is taken from
src/backend/port. This is certainly a little weird, but it should
suffice
until a source tree cleanup is done.
Enjoy.
--
Peter Eisentraut Sernanders väg 10:115
1999-11-26 05:24:17 +01:00
if ( ! res )
2002-04-24 07:24:00 +02:00
goto error_return ;
2002-12-21 02:07:07 +01:00
numrows = PQntuples ( res ) ;
* Includes tab completion. It's not magic, but it's very cool. At any
rate
it's better than what used to be there.
* Does proper SQL "host variable" substitution as pointed out by Andreas
Zeugwetter (thanks): select * from :foo; Also some changes in how ':'
and ';' are treated (escape with \ to send to backend). This does
_not_
affect the '::' cast operator, but perhaps others that contain : or ;
(but there are none right now).
* To show description with a <something> listing, append '?' to command
name, e.g., \df?. This seemed to be the convenient and logical
solution.
Or append a '+' to see more useless information, e.g., \df+.
* Fixed fflush()'ing bug pointed out by Jan during the regression test
discussion.
* Added LastOid variable. This ought to take care of TODO item "Add a
function to return the last inserted oid, for use in psql scripts"
(under CLIENTS)
E.g.,
insert into foo values(...);
insert into bar values(..., :LastOid);
\echo $LastOid
* \d command shows constraints, rules, and triggers defined on the table
(in addition to indices)
* Various fixes, optimizations, corrections
* Documentation update as well
Note: This now requires snprintf(), which, if necessary, is taken from
src/backend/port. This is certainly a little weird, but it should
suffice
until a source tree cleanup is done.
Enjoy.
--
Peter Eisentraut Sernanders väg 10:115
1999-11-26 05:24:17 +01:00
2008-05-13 02:14:11 +02:00
/* Make title */
switch ( tableinfo . relkind )
{
case ' r ' :
2010-12-29 12:48:53 +01:00
if ( tableinfo . relpersistence = = ' u ' )
2011-02-23 01:54:32 +01:00
printfPQExpBuffer ( & title , _ ( " Unlogged table \" %s.%s \" " ) ,
2010-12-29 12:48:53 +01:00
schemaname , relationname ) ;
else
printfPQExpBuffer ( & title , _ ( " Table \" %s.%s \" " ) ,
schemaname , relationname ) ;
2008-05-13 02:14:11 +02:00
break ;
case ' v ' :
printfPQExpBuffer ( & title , _ ( " View \" %s.%s \" " ) ,
schemaname , relationname ) ;
break ;
case ' S ' :
printfPQExpBuffer ( & title , _ ( " Sequence \" %s.%s \" " ) ,
schemaname , relationname ) ;
break ;
case ' i ' :
2010-12-29 12:48:53 +01:00
if ( tableinfo . relpersistence = = ' u ' )
2011-02-23 01:54:32 +01:00
printfPQExpBuffer ( & title , _ ( " Unlogged index \" %s.%s \" " ) ,
2010-12-29 12:48:53 +01:00
schemaname , relationname ) ;
else
printfPQExpBuffer ( & title , _ ( " Index \" %s.%s \" " ) ,
schemaname , relationname ) ;
2008-05-13 02:14:11 +02:00
break ;
case ' s ' :
/* not used as of 8.2, but keep it for backwards compatibility */
printfPQExpBuffer ( & title , _ ( " Special relation \" %s.%s \" " ) ,
schemaname , relationname ) ;
break ;
case ' t ' :
printfPQExpBuffer ( & title , _ ( " TOAST table \" %s.%s \" " ) ,
schemaname , relationname ) ;
break ;
case ' c ' :
printfPQExpBuffer ( & title , _ ( " Composite type \" %s.%s \" " ) ,
schemaname , relationname ) ;
break ;
2011-01-02 05:48:11 +01:00
case ' f ' :
printfPQExpBuffer ( & title , _ ( " Foreign table \" %s.%s \" " ) ,
schemaname , relationname ) ;
break ;
2008-05-13 02:14:11 +02:00
default :
/* untranslated unknown relkind */
printfPQExpBuffer ( & title , " ?%c? \" %s.%s \" " ,
tableinfo . relkind , schemaname , relationname ) ;
break ;
}
2008-05-13 00:59:58 +02:00
/* Set the number of columns, and their names */
2008-07-15 00:51:48 +02:00
headers [ 0 ] = gettext_noop ( " Column " ) ;
headers [ 1 ] = gettext_noop ( " Type " ) ;
2009-07-07 18:28:38 +02:00
cols = 2 ;
2008-05-13 00:59:58 +02:00
2011-01-02 05:48:11 +01:00
if ( tableinfo . relkind = = ' r ' | | tableinfo . relkind = = ' v ' | |
2011-04-18 00:09:22 +02:00
tableinfo . relkind = = ' f ' | | tableinfo . relkind = = ' c ' )
2008-05-13 00:59:58 +02:00
{
show_modifiers = true ;
2008-07-15 00:51:48 +02:00
headers [ cols + + ] = gettext_noop ( " Modifiers " ) ;
2008-05-13 00:59:58 +02:00
modifiers = pg_malloc_zero ( ( numrows + 1 ) * sizeof ( * modifiers ) ) ;
}
2008-07-15 05:16:03 +02:00
if ( tableinfo . relkind = = ' S ' )
headers [ cols + + ] = gettext_noop ( " Value " ) ;
2009-06-11 16:49:15 +02:00
2009-07-06 19:01:42 +02:00
if ( tableinfo . relkind = = ' i ' )
headers [ cols + + ] = gettext_noop ( " Definition " ) ;
2011-08-05 19:24:03 +02:00
if ( tableinfo . relkind = = ' f ' & & pset . sversion > = 90200 )
2011-08-11 17:45:47 +02:00
headers [ cols + + ] = gettext_noop ( " FDW Options " ) ;
2011-08-05 19:24:03 +02:00
2008-05-13 00:59:58 +02:00
if ( verbose )
2008-07-15 00:51:48 +02:00
{
headers [ cols + + ] = gettext_noop ( " Storage " ) ;
2012-04-06 21:02:35 +02:00
if ( tableinfo . relkind = = ' r ' | | tableinfo . relkind = = ' f ' )
2011-11-05 13:02:48 +01:00
headers [ cols + + ] = gettext_noop ( " Stats target " ) ;
2011-07-26 15:52:31 +02:00
/* Column comments, if the relkind supports this feature. */
if ( tableinfo . relkind = = ' r ' | | tableinfo . relkind = = ' v ' | |
tableinfo . relkind = = ' c ' | | tableinfo . relkind = = ' f ' )
headers [ cols + + ] = gettext_noop ( " Description " ) ;
2008-07-15 00:51:48 +02:00
}
2009-06-11 16:49:15 +02:00
2008-05-13 00:59:58 +02:00
printTableInit ( & cont , & myopt , title . data , cols , numrows ) ;
2008-11-03 20:08:56 +01:00
printTableInitialized = true ;
2008-05-13 00:59:58 +02:00
for ( i = 0 ; i < cols ; i + + )
printTableAddHeader ( & cont , headers [ i ] , true , ' l ' ) ;
* Includes tab completion. It's not magic, but it's very cool. At any
rate
it's better than what used to be there.
* Does proper SQL "host variable" substitution as pointed out by Andreas
Zeugwetter (thanks): select * from :foo; Also some changes in how ':'
and ';' are treated (escape with \ to send to backend). This does
_not_
affect the '::' cast operator, but perhaps others that contain : or ;
(but there are none right now).
* To show description with a <something> listing, append '?' to command
name, e.g., \df?. This seemed to be the convenient and logical
solution.
Or append a '+' to see more useless information, e.g., \df+.
* Fixed fflush()'ing bug pointed out by Jan during the regression test
discussion.
* Added LastOid variable. This ought to take care of TODO item "Add a
function to return the last inserted oid, for use in psql scripts"
(under CLIENTS)
E.g.,
insert into foo values(...);
insert into bar values(..., :LastOid);
\echo $LastOid
* \d command shows constraints, rules, and triggers defined on the table
(in addition to indices)
* Various fixes, optimizations, corrections
* Documentation update as well
Note: This now requires snprintf(), which, if necessary, is taken from
src/backend/port. This is certainly a little weird, but it should
suffice
until a source tree cleanup is done.
Enjoy.
--
Peter Eisentraut Sernanders väg 10:115
1999-11-26 05:24:17 +01:00
/* Check if table is a view */
2009-11-03 11:34:47 +01:00
if ( tableinfo . relkind = = ' v ' & & verbose )
2000-04-12 19:17:23 +02:00
{
PGresult * result ;
2008-07-03 05:37:17 +02:00
printfPQExpBuffer ( & buf ,
2012-06-10 21:20:04 +02:00
" SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true); " ,
2008-07-03 05:37:17 +02:00
oid ) ;
2002-10-15 04:24:16 +02:00
result = PSQLexec ( buf . data , false ) ;
2000-04-12 19:17:23 +02:00
if ( ! result )
2002-04-24 07:24:00 +02:00
goto error_return ;
2000-04-12 19:17:23 +02:00
if ( PQntuples ( result ) > 0 )
2004-01-25 04:07:22 +01:00
view_def = pg_strdup ( PQgetvalue ( result , 0 , 0 ) ) ;
2002-08-10 05:56:24 +02:00
2000-04-12 19:17:23 +02:00
PQclear ( result ) ;
}
* Includes tab completion. It's not magic, but it's very cool. At any
rate
it's better than what used to be there.
* Does proper SQL "host variable" substitution as pointed out by Andreas
Zeugwetter (thanks): select * from :foo; Also some changes in how ':'
and ';' are treated (escape with \ to send to backend). This does
_not_
affect the '::' cast operator, but perhaps others that contain : or ;
(but there are none right now).
* To show description with a <something> listing, append '?' to command
name, e.g., \df?. This seemed to be the convenient and logical
solution.
Or append a '+' to see more useless information, e.g., \df+.
* Fixed fflush()'ing bug pointed out by Jan during the regression test
discussion.
* Added LastOid variable. This ought to take care of TODO item "Add a
function to return the last inserted oid, for use in psql scripts"
(under CLIENTS)
E.g.,
insert into foo values(...);
insert into bar values(..., :LastOid);
\echo $LastOid
* \d command shows constraints, rules, and triggers defined on the table
(in addition to indices)
* Various fixes, optimizations, corrections
* Documentation update as well
Note: This now requires snprintf(), which, if necessary, is taken from
src/backend/port. This is certainly a little weird, but it should
suffice
until a source tree cleanup is done.
Enjoy.
--
Peter Eisentraut Sernanders väg 10:115
1999-11-26 05:24:17 +01:00
/* Generate table cells to be printed */
2002-12-21 02:07:07 +01:00
for ( i = 0 ; i < numrows ; i + + )
1999-11-05 00:14:30 +01:00
{
2008-05-13 00:59:58 +02:00
/* Column */
2010-03-01 21:55:45 +01:00
printTableAddCell ( & cont , PQgetvalue ( res , i , 0 ) , false , false ) ;
2003-07-27 05:32:26 +02:00
1999-11-05 00:14:30 +01:00
/* Type */
2010-03-01 21:55:45 +01:00
printTableAddCell ( & cont , PQgetvalue ( res , i , 1 ) , false , false ) ;
2008-11-03 20:08:56 +01:00
2011-02-08 22:04:18 +01:00
/* Modifiers: collate, not null, default */
2002-12-21 02:07:07 +01:00
if ( show_modifiers )
2000-04-12 19:17:23 +02:00
{
2002-12-21 02:07:07 +01:00
resetPQExpBuffer ( & tmpbuf ) ;
2011-02-08 22:04:18 +01:00
if ( ! PQgetisnull ( res , i , 5 ) )
{
if ( tmpbuf . len > 0 )
appendPQExpBufferStr ( & tmpbuf , " " ) ;
appendPQExpBuffer ( & tmpbuf , _ ( " collate %s " ) ,
PQgetvalue ( res , i , 5 ) ) ;
}
2003-02-24 04:54:06 +01:00
if ( strcmp ( PQgetvalue ( res , i , 3 ) , " t " ) = = 0 )
2011-02-08 22:04:18 +01:00
{
if ( tmpbuf . len > 0 )
appendPQExpBufferStr ( & tmpbuf , " " ) ;
2008-05-13 00:59:58 +02:00
appendPQExpBufferStr ( & tmpbuf , _ ( " not null " ) ) ;
2011-02-08 22:04:18 +01:00
}
2000-04-12 19:17:23 +02:00
/* handle "default" here */
2003-02-24 04:54:06 +01:00
/* (note: above we cut off the 'default' string at 128) */
if ( strlen ( PQgetvalue ( res , i , 2 ) ) ! = 0 )
2000-04-12 19:17:23 +02:00
{
2002-12-21 02:07:07 +01:00
if ( tmpbuf . len > 0 )
appendPQExpBufferStr ( & tmpbuf , " " ) ;
2008-05-13 00:59:58 +02:00
/* translator: default values of column definitions */
appendPQExpBuffer ( & tmpbuf , _ ( " default %s " ) ,
2003-02-24 04:54:06 +01:00
PQgetvalue ( res , i , 2 ) ) ;
2000-04-12 19:17:23 +02:00
}
2002-12-21 02:07:07 +01:00
2008-05-13 00:59:58 +02:00
modifiers [ i ] = pg_strdup ( tmpbuf . data ) ;
2010-03-01 21:55:45 +01:00
printTableAddCell ( & cont , modifiers [ i ] , false , false ) ;
2000-04-12 19:17:23 +02:00
}
2008-11-03 20:08:56 +01:00
/* Value: for sequences only */
if ( tableinfo . relkind = = ' S ' )
2010-03-01 21:55:45 +01:00
printTableAddCell ( & cont , seq_values [ i ] , false , false ) ;
2008-11-03 20:08:56 +01:00
2009-07-07 18:28:38 +02:00
/* Expression for index column */
2009-07-06 19:01:42 +02:00
if ( tableinfo . relkind = = ' i ' )
2011-02-08 22:04:18 +01:00
printTableAddCell ( & cont , PQgetvalue ( res , i , 6 ) , false , false ) ;
2009-07-06 19:01:42 +02:00
2011-08-05 19:24:03 +02:00
/* FDW options for foreign table column, only for 9.2 or later */
if ( tableinfo . relkind = = ' f ' & & pset . sversion > = 90200 )
printTableAddCell ( & cont , PQgetvalue ( res , i , 7 ) , false , false ) ;
2008-07-15 00:51:48 +02:00
/* Storage and Description */
2002-08-10 05:56:24 +02:00
if ( verbose )
2008-07-15 00:51:48 +02:00
{
2011-08-05 19:24:03 +02:00
int firstvcol = 8 ;
2010-02-26 03:01:40 +01:00
char * storage = PQgetvalue ( res , i , firstvcol ) ;
2008-11-03 20:08:56 +01:00
2008-07-15 01:13:04 +02:00
/* these strings are literal in our syntax, so not translated. */
2009-06-11 16:49:15 +02:00
printTableAddCell ( & cont , ( storage [ 0 ] = = ' p ' ? " plain " :
( storage [ 0 ] = = ' m ' ? " main " :
( storage [ 0 ] = = ' x ' ? " extended " :
( storage [ 0 ] = = ' e ' ? " external " :
2008-07-15 00:51:48 +02:00
" ??? " ) ) ) ) ,
2010-03-01 21:55:45 +01:00
false , false ) ;
2011-11-05 13:02:48 +01:00
/* Statistics target, if the relkind supports this feature */
2012-04-06 21:02:35 +02:00
if ( tableinfo . relkind = = ' r ' | | tableinfo . relkind = = ' f ' )
2011-11-05 13:02:48 +01:00
{
printTableAddCell ( & cont , PQgetvalue ( res , i , firstvcol + 1 ) ,
false , false ) ;
}
2011-07-26 15:52:31 +02:00
/* Column comments, if the relkind supports this feature. */
if ( tableinfo . relkind = = ' r ' | | tableinfo . relkind = = ' v ' | |
tableinfo . relkind = = ' c ' | | tableinfo . relkind = = ' f ' )
2011-11-05 13:02:48 +01:00
printTableAddCell ( & cont , PQgetvalue ( res , i , firstvcol + 2 ) ,
2011-07-26 15:52:31 +02:00
false , false ) ;
2008-07-15 00:51:48 +02:00
}
1999-11-05 00:14:30 +01:00
}
1999-11-04 22:56:02 +01:00
1999-11-05 00:14:30 +01:00
/* Make footers */
2000-04-12 19:17:23 +02:00
if ( tableinfo . relkind = = ' i ' )
{
2001-08-06 00:13:46 +02:00
/* Footer information about an index */
2000-04-12 19:17:23 +02:00
PGresult * result ;
2002-09-04 22:31:48 +02:00
2002-04-24 07:24:00 +02:00
printfPQExpBuffer ( & buf ,
2009-06-11 16:49:15 +02:00
" SELECT i.indisunique, i.indisprimary, i.indisclustered, " ) ;
2008-07-03 05:37:17 +02:00
if ( pset . sversion > = 80200 )
2009-07-29 22:56:21 +02:00
appendPQExpBuffer ( & buf , " i.indisvalid, \n " ) ;
2008-07-03 05:37:17 +02:00
else
2009-07-29 22:56:21 +02:00
appendPQExpBuffer ( & buf , " true AS indisvalid, \n " ) ;
2010-02-17 05:19:41 +01:00
if ( pset . sversion > = 90000 )
2009-07-29 22:56:21 +02:00
appendPQExpBuffer ( & buf ,
" (NOT i.indimmediate) AND "
2010-07-06 21:19:02 +02:00
" EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
2010-03-11 05:36:43 +01:00
" WHERE conrelid = i.indrelid AND "
" conindid = i.indexrelid AND "
" contype IN ('p','u','x') AND "
" condeferrable) AS condeferrable, \n "
2009-07-29 22:56:21 +02:00
" (NOT i.indimmediate) AND "
2010-07-06 21:19:02 +02:00
" EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
2010-03-11 05:36:43 +01:00
" WHERE conrelid = i.indrelid AND "
" conindid = i.indexrelid AND "
" contype IN ('p','u','x') AND "
" condeferred) AS condeferred, \n " ) ;
2009-07-29 22:56:21 +02:00
else
appendPQExpBuffer ( & buf ,
" false AS condeferrable, false AS condeferred, \n " ) ;
appendPQExpBuffer ( & buf , " a.amname, c2.relname, "
2010-02-26 03:01:40 +01:00
" pg_catalog.pg_get_expr(i.indpred, i.indrelid, true) \n "
2002-08-10 05:56:24 +02:00
" FROM pg_catalog.pg_index i, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_am a \n "
2005-10-15 04:49:52 +02:00
" WHERE i.indexrelid = c.oid AND c.oid = '%s' AND c.relam = a.oid \n "
2011-07-06 16:11:20 +02:00
" AND i.indrelid = c2.oid; " ,
2002-08-10 05:56:24 +02:00
oid ) ;
2002-04-24 07:24:00 +02:00
2002-10-15 04:24:16 +02:00
result = PSQLexec ( buf . data , false ) ;
2002-04-24 07:24:00 +02:00
if ( ! result )
goto error_return ;
else if ( PQntuples ( result ) ! = 1 )
{
PQclear ( result ) ;
goto error_return ;
}
2000-04-12 19:17:23 +02:00
else
{
2001-10-25 07:50:21 +02:00
char * indisunique = PQgetvalue ( result , 0 , 0 ) ;
char * indisprimary = PQgetvalue ( result , 0 , 1 ) ;
2004-04-06 06:05:17 +02:00
char * indisclustered = PQgetvalue ( result , 0 , 2 ) ;
2006-08-25 06:06:58 +02:00
char * indisvalid = PQgetvalue ( result , 0 , 3 ) ;
2009-07-29 22:56:21 +02:00
char * deferrable = PQgetvalue ( result , 0 , 4 ) ;
char * deferred = PQgetvalue ( result , 0 , 5 ) ;
char * indamname = PQgetvalue ( result , 0 , 6 ) ;
char * indtable = PQgetvalue ( result , 0 , 7 ) ;
char * indpred = PQgetvalue ( result , 0 , 8 ) ;
2001-08-06 00:13:46 +02:00
2002-04-24 08:17:04 +02:00
if ( strcmp ( indisprimary , " t " ) = = 0 )
2004-10-12 23:54:45 +02:00
printfPQExpBuffer ( & tmpbuf , _ ( " primary key, " ) ) ;
2002-04-24 08:17:04 +02:00
else if ( strcmp ( indisunique , " t " ) = = 0 )
2004-10-12 23:54:45 +02:00
printfPQExpBuffer ( & tmpbuf , _ ( " unique, " ) ) ;
2002-04-24 08:17:04 +02:00
else
resetPQExpBuffer ( & tmpbuf ) ;
appendPQExpBuffer ( & tmpbuf , " %s, " , indamname ) ;
2002-08-10 05:56:24 +02:00
/* we assume here that index and table are in same schema */
appendPQExpBuffer ( & tmpbuf , _ ( " for table \" %s.%s \" " ) ,
schemaname , indtable ) ;
2002-04-24 08:17:04 +02:00
if ( strlen ( indpred ) )
2004-01-11 20:10:49 +01:00
appendPQExpBuffer ( & tmpbuf , _ ( " , predicate (%s) " ) , indpred ) ;
2002-04-24 08:17:04 +02:00
2004-04-06 06:05:17 +02:00
if ( strcmp ( indisclustered , " t " ) = = 0 )
2004-10-12 23:54:45 +02:00
appendPQExpBuffer ( & tmpbuf , _ ( " , clustered " ) ) ;
2004-04-06 06:05:17 +02:00
2006-08-25 06:06:58 +02:00
if ( strcmp ( indisvalid , " t " ) ! = 0 )
appendPQExpBuffer ( & tmpbuf , _ ( " , invalid " ) ) ;
2009-07-29 22:56:21 +02:00
if ( strcmp ( deferrable , " t " ) = = 0 )
appendPQExpBuffer ( & tmpbuf , _ ( " , deferrable " ) ) ;
if ( strcmp ( deferred , " t " ) = = 0 )
appendPQExpBuffer ( & tmpbuf , _ ( " , initially deferred " ) ) ;
2008-05-13 00:59:58 +02:00
printTableAddFooter ( & cont , tmpbuf . data ) ;
add_tablespace_footer ( & cont , tableinfo . relkind ,
tableinfo . tablespace , true ) ;
2000-04-12 19:17:23 +02:00
}
2001-08-21 18:36:06 +02:00
PQclear ( result ) ;
2000-04-12 19:17:23 +02:00
}
2000-10-25 22:36:52 +02:00
else if ( view_def )
1999-11-05 00:14:30 +01:00
{
2002-04-05 13:52:38 +02:00
PGresult * result = NULL ;
2008-05-13 00:59:58 +02:00
/* Footer information about a view */
printTableAddFooter ( & cont , _ ( " View definition: " ) ) ;
printTableAddFooter ( & cont , view_def ) ;
/* print rules */
2002-04-24 07:24:00 +02:00
if ( tableinfo . hasrules )
2002-04-05 13:52:38 +02:00
{
2002-04-24 07:24:00 +02:00
printfPQExpBuffer ( & buf ,
2003-12-01 23:11:06 +01:00
" SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)) \n "
2002-09-04 22:31:48 +02:00
" FROM pg_catalog.pg_rewrite r \n "
2011-07-06 16:11:20 +02:00
" WHERE r.ev_class = '%s' AND r.rulename != '_RETURN' ORDER BY 1; " ,
2002-09-04 22:31:48 +02:00
oid ) ;
2002-10-15 04:24:16 +02:00
result = PSQLexec ( buf . data , false ) ;
2002-04-05 13:52:38 +02:00
if ( ! result )
2002-04-24 07:24:00 +02:00
goto error_return ;
2002-04-05 13:52:38 +02:00
2008-05-13 00:59:58 +02:00
if ( PQntuples ( result ) > 0 )
2003-12-01 23:11:06 +01:00
{
2008-05-13 00:59:58 +02:00
printTableAddFooter ( & cont , _ ( " Rules: " ) ) ;
for ( i = 0 ; i < PQntuples ( result ) ; i + + )
{
const char * ruledef ;
2002-04-05 13:52:38 +02:00
2008-05-13 00:59:58 +02:00
/* Everything after "CREATE RULE" is echoed verbatim */
ruledef = PQgetvalue ( result , i , 1 ) ;
ruledef + = 12 ;
2003-12-01 23:11:06 +01:00
2008-05-13 00:59:58 +02:00
printfPQExpBuffer ( & buf , " %s " , ruledef ) ;
printTableAddFooter ( & cont , buf . data ) ;
}
2003-12-01 23:11:06 +01:00
}
PQclear ( result ) ;
2002-04-05 13:52:38 +02:00
}
1999-11-05 00:14:30 +01:00
}
2011-11-05 12:54:58 +01:00
else if ( tableinfo . relkind = = ' S ' )
{
/* Footer information about a sequence */
PGresult * result = NULL ;
/* Get the column that owns this sequence */
printfPQExpBuffer ( & buf , " SELECT pg_catalog.quote_ident(nspname) || '.' || "
" \n pg_catalog.quote_ident(relname) || '.' || "
" \n pg_catalog.quote_ident(attname) "
" \n FROM pg_catalog.pg_class c "
2012-06-10 21:20:04 +02:00
" \n INNER JOIN pg_catalog.pg_depend d ON c.oid=d.refobjid "
" \n INNER JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace "
2011-11-05 12:54:58 +01:00
" \n INNER JOIN pg_catalog.pg_attribute a ON ( "
" \n a.attrelid=c.oid AND "
" \n a.attnum=d.refobjsubid) "
2012-06-10 21:20:04 +02:00
" \n WHERE d.classid='pg_catalog.pg_class'::pg_catalog.regclass "
" \n AND d.refclassid='pg_catalog.pg_class'::pg_catalog.regclass "
2011-11-05 12:54:58 +01:00
" \n AND d.objid=%s "
" \n AND d.deptype='a' " ,
oid ) ;
result = PSQLexec ( buf . data , false ) ;
if ( ! result )
goto error_return ;
else if ( PQntuples ( result ) = = 1 )
{
printfPQExpBuffer ( & buf , _ ( " Owned by: %s " ) ,
PQgetvalue ( result , 0 , 0 ) ) ;
printTableAddFooter ( & cont , buf . data ) ;
}
2012-06-10 21:20:04 +02:00
2011-11-05 12:54:58 +01:00
/*
2012-06-10 21:20:04 +02:00
* If we get no rows back , don ' t show anything ( obviously ) . We should
* never get more than one row back , but if we do , just ignore it and
* don ' t print anything .
2011-11-05 12:54:58 +01:00
*/
PQclear ( result ) ;
}
2011-01-02 05:48:11 +01:00
else if ( tableinfo . relkind = = ' r ' | | tableinfo . relkind = = ' f ' )
1999-11-05 00:14:30 +01:00
{
2001-08-06 00:13:46 +02:00
/* Footer information about a table */
2008-05-13 00:59:58 +02:00
PGresult * result = NULL ;
int tuples = 0 ;
/* print indexes */
2002-04-24 07:24:00 +02:00
if ( tableinfo . hasindex )
2000-04-12 19:17:23 +02:00
{
2002-04-24 07:24:00 +02:00
printfPQExpBuffer ( & buf ,
2008-07-03 05:37:17 +02:00
" SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, " ) ;
2009-06-11 16:49:15 +02:00
if ( pset . sversion > = 80200 )
2008-07-03 05:37:17 +02:00
appendPQExpBuffer ( & buf , " i.indisvalid, " ) ;
2009-06-11 16:49:15 +02:00
else
2008-07-03 05:37:17 +02:00
appendPQExpBuffer ( & buf , " true as indisvalid, " ) ;
2010-03-11 22:29:32 +01:00
appendPQExpBuffer ( & buf , " pg_catalog.pg_get_indexdef(i.indexrelid, 0, true), \n " ) ;
2010-02-17 05:19:41 +01:00
if ( pset . sversion > = 90000 )
2009-07-29 22:56:21 +02:00
appendPQExpBuffer ( & buf ,
2010-07-06 21:19:02 +02:00
" pg_catalog.pg_get_constraintdef(con.oid, true), "
2010-03-11 22:29:32 +01:00
" contype, condeferrable, condeferred " ) ;
2009-07-29 22:56:21 +02:00
else
2010-03-11 22:29:32 +01:00
appendPQExpBuffer ( & buf ,
" null AS constraintdef, null AS contype, "
2010-07-06 21:19:02 +02:00
" false AS condeferrable, false AS condeferred " ) ;
2009-06-11 16:49:15 +02:00
if ( pset . sversion > = 80000 )
2008-07-03 05:37:17 +02:00
appendPQExpBuffer ( & buf , " , c2.reltablespace " ) ;
appendPQExpBuffer ( & buf ,
2010-03-11 22:29:32 +01:00
" \n FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i \n " ) ;
if ( pset . sversion > = 90000 )
appendPQExpBuffer ( & buf ,
" LEFT JOIN pg_catalog.pg_constraint con ON (conrelid = i.indrelid AND conindid = i.indexrelid AND contype IN ('p','u','x')) \n " ) ;
appendPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid \n "
2012-06-10 21:20:04 +02:00
" ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname; " ,
2002-09-04 22:31:48 +02:00
oid ) ;
2008-05-13 00:59:58 +02:00
result = PSQLexec ( buf . data , false ) ;
if ( ! result )
2002-04-24 07:24:00 +02:00
goto error_return ;
2000-04-12 19:17:23 +02:00
else
2008-05-13 00:59:58 +02:00
tuples = PQntuples ( result ) ;
if ( tuples > 0 )
{
printTableAddFooter ( & cont , _ ( " Indexes: " ) ) ;
for ( i = 0 ; i < tuples ; i + + )
{
/* untranslated index name */
printfPQExpBuffer ( & buf , " \" %s \" " ,
PQgetvalue ( result , i , 0 ) ) ;
2010-03-11 22:29:32 +01:00
/* If exclusion constraint, print the constraintdef */
if ( strcmp ( PQgetvalue ( result , i , 7 ) , " x " ) = = 0 )
{
appendPQExpBuffer ( & buf , " %s " ,
PQgetvalue ( result , i , 6 ) ) ;
}
else
{
const char * indexdef ;
const char * usingpos ;
/* Label as primary key or unique (but not both) */
if ( strcmp ( PQgetvalue ( result , i , 1 ) , " t " ) = = 0 )
appendPQExpBuffer ( & buf , " PRIMARY KEY, " ) ;
else if ( strcmp ( PQgetvalue ( result , i , 2 ) , " t " ) = = 0 )
2010-08-01 03:08:29 +02:00
{
if ( strcmp ( PQgetvalue ( result , i , 7 ) , " u " ) = = 0 )
appendPQExpBuffer ( & buf , " UNIQUE CONSTRAINT, " ) ;
else
appendPQExpBuffer ( & buf , " UNIQUE, " ) ;
}
2010-03-11 22:29:32 +01:00
/* Everything after "USING" is echoed verbatim */
indexdef = PQgetvalue ( result , i , 5 ) ;
usingpos = strstr ( indexdef , " USING " ) ;
if ( usingpos )
indexdef = usingpos + 7 ;
appendPQExpBuffer ( & buf , " %s " , indexdef ) ;
/* Need these for deferrable PK/UNIQUE indexes */
if ( strcmp ( PQgetvalue ( result , i , 8 ) , " t " ) = = 0 )
appendPQExpBuffer ( & buf , " DEFERRABLE " ) ;
if ( strcmp ( PQgetvalue ( result , i , 9 ) , " t " ) = = 0 )
appendPQExpBuffer ( & buf , " INITIALLY DEFERRED " ) ;
}
/* Add these for all cases */
2008-05-13 00:59:58 +02:00
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 */
2008-07-03 05:37:17 +02:00
if ( pset . sversion > = 80000 )
2009-06-11 16:49:15 +02:00
add_tablespace_footer ( & cont , ' i ' ,
2010-07-06 21:19:02 +02:00
atooid ( PQgetvalue ( result , i , 10 ) ) ,
2008-07-03 05:37:17 +02:00
false ) ;
2008-05-13 00:59:58 +02:00
}
}
PQclear ( result ) ;
2000-04-12 19:17:23 +02:00
}
2008-05-13 00:59:58 +02:00
/* print table (and column) check constraints */
2002-04-24 07:24:00 +02:00
if ( tableinfo . checks )
2000-04-12 19:17:23 +02:00
{
2002-04-24 07:24:00 +02:00
printfPQExpBuffer ( & buf ,
2012-04-21 04:46:20 +02:00
" SELECT r.conname, "
2005-10-20 07:15:09 +02:00
" pg_catalog.pg_get_constraintdef(r.oid, true) \n "
2002-09-04 22:31:48 +02:00
" FROM pg_catalog.pg_constraint r \n "
2012-04-21 04:46:20 +02:00
" WHERE r.conrelid = '%s' AND r.contype = 'c' \n "
" ORDER BY 1; " ,
oid ) ;
2008-05-13 00:59:58 +02:00
result = PSQLexec ( buf . data , false ) ;
if ( ! result )
2002-04-24 07:24:00 +02:00
goto error_return ;
2000-04-12 19:17:23 +02:00
else
2008-05-13 00:59:58 +02:00
tuples = PQntuples ( result ) ;
2000-04-12 19:17:23 +02:00
2008-05-13 00:59:58 +02:00
if ( tuples > 0 )
2007-03-20 00:38:32 +01:00
{
2008-05-13 00:59:58 +02:00
printTableAddFooter ( & cont , _ ( " Check constraints: " ) ) ;
for ( i = 0 ; i < tuples ; i + + )
{
/* untranslated contraint name and def */
2012-04-21 04:46:20 +02:00
printfPQExpBuffer ( & buf , " \" %s \" %s " ,
2008-05-13 00:59:58 +02:00
PQgetvalue ( result , i , 0 ) ,
2012-04-21 04:46:20 +02:00
PQgetvalue ( result , i , 1 ) ) ;
2000-04-12 19:17:23 +02:00
2008-05-13 00:59:58 +02:00
printTableAddFooter ( & cont , buf . data ) ;
}
2003-06-27 18:55:23 +02:00
}
2008-05-13 00:59:58 +02:00
PQclear ( result ) ;
2000-04-12 19:17:23 +02:00
}
2008-05-13 00:59:58 +02:00
/* print foreign-key constraints (there are none if no triggers) */
2008-11-09 22:24:33 +01:00
if ( tableinfo . hastriggers )
2002-08-17 01:01:21 +02:00
{
printfPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" SELECT conname, \n "
2011-06-09 20:32:50 +02:00
" pg_catalog.pg_get_constraintdef(r.oid, true) as condef \n "
2011-06-08 03:39:43 +02:00
" FROM pg_catalog.pg_constraint r \n "
2012-06-10 21:20:04 +02:00
" WHERE r.conrelid = '%s' AND r.contype = 'f' ORDER BY 1; " ,
2002-09-04 22:31:48 +02:00
oid ) ;
2008-05-13 00:59:58 +02:00
result = PSQLexec ( buf . data , false ) ;
if ( ! result )
2002-08-17 01:01:21 +02:00
goto error_return ;
else
2008-05-13 00:59:58 +02:00
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 ) ;
2002-08-17 01:01:21 +02:00
}
2008-05-13 00:59:58 +02:00
/* print incoming foreign-key references (none if no triggers) */
2008-11-09 22:24:33 +01:00
if ( tableinfo . hastriggers )
2008-03-30 19:50:11 +02:00
{
printfPQExpBuffer ( & buf ,
2009-06-11 16:49:15 +02:00
" SELECT conname, conrelid::pg_catalog.regclass, \n "
" pg_catalog.pg_get_constraintdef(c.oid, true) as condef \n "
2008-03-30 19:50:11 +02:00
" FROM pg_catalog.pg_constraint c \n "
2012-06-10 21:20:04 +02:00
" WHERE c.confrelid = '%s' AND c.contype = 'f' ORDER BY 1; " ,
2008-03-30 19:50:11 +02:00
oid ) ;
2008-05-13 00:59:58 +02:00
result = PSQLexec ( buf . data , false ) ;
if ( ! result )
2008-03-30 19:50:11 +02:00
goto error_return ;
else
2008-05-13 00:59:58 +02:00
tuples = PQntuples ( result ) ;
2008-03-30 19:50:11 +02:00
2008-05-13 00:59:58 +02:00
if ( tuples > 0 )
2003-03-27 17:57:39 +01:00
{
2008-05-13 00:59:58 +02:00
printTableAddFooter ( & cont , _ ( " Referenced by: " ) ) ;
for ( i = 0 ; i < tuples ; i + + )
2005-06-15 01:59:31 +02:00
{
2009-06-13 15:43:34 +02:00
printfPQExpBuffer ( & buf , " TABLE \" %s \" CONSTRAINT \" %s \" %s " ,
2008-05-13 00:59:58 +02:00
PQgetvalue ( result , i , 1 ) ,
2009-06-13 15:43:34 +02:00
PQgetvalue ( result , i , 0 ) ,
2008-05-13 00:59:58 +02:00
PQgetvalue ( result , i , 2 ) ) ;
printTableAddFooter ( & cont , buf . data ) ;
2005-06-15 01:59:31 +02:00
}
2003-03-27 17:57:39 +01:00
}
2008-05-13 00:59:58 +02:00
PQclear ( result ) ;
2000-04-12 19:17:23 +02:00
}
2008-05-13 00:59:58 +02:00
/* print rules */
if ( tableinfo . hasrules )
2003-08-04 02:43:34 +02:00
{
2008-07-03 05:37:17 +02:00
if ( pset . sversion > = 80300 )
2003-03-27 17:57:39 +01:00
{
2008-05-13 00:59:58 +02:00
printfPQExpBuffer ( & buf ,
" SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
2008-07-03 05:37:17 +02:00
" ev_enabled \n "
2008-05-13 00:59:58 +02:00
" FROM pg_catalog.pg_rewrite r \n "
2011-07-06 16:11:20 +02:00
" WHERE r.ev_class = '%s' ORDER BY 1; " ,
2008-05-13 00:59:58 +02:00
oid ) ;
2003-03-27 17:57:39 +01:00
}
2008-05-13 00:59:58 +02:00
else
2008-03-30 19:50:11 +02:00
{
2008-05-13 00:59:58 +02:00
printfPQExpBuffer ( & buf ,
" SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
2008-07-03 05:37:17 +02:00
" 'O'::char AS ev_enabled \n "
2008-05-13 00:59:58 +02:00
" FROM pg_catalog.pg_rewrite r \n "
2011-07-06 16:11:20 +02:00
" WHERE r.ev_class = '%s' ORDER BY 1; " ,
2008-05-13 00:59:58 +02:00
oid ) ;
2008-03-30 19:50:11 +02:00
}
2008-05-13 00:59:58 +02:00
result = PSQLexec ( buf . data , false ) ;
if ( ! result )
goto error_return ;
else
tuples = PQntuples ( result ) ;
2000-04-12 19:17:23 +02:00
2008-05-13 00:59:58 +02:00
if ( tuples > 0 )
2007-03-20 00:38:32 +01:00
{
2008-05-13 00:59:58 +02:00
bool have_heading ;
int category ;
2003-03-27 17:57:39 +01:00
2008-05-13 00:59:58 +02:00
for ( category = 0 ; category < 4 ; category + + )
2007-03-20 00:38:32 +01:00
{
2008-05-13 00:59:58 +02:00
have_heading = false ;
2007-03-20 00:38:32 +01:00
2008-05-13 00:59:58 +02:00
for ( i = 0 ; i < tuples ; i + + )
2007-03-20 00:38:32 +01:00
{
2008-05-13 00:59:58 +02:00
const char * ruledef ;
bool list_rule = false ;
2007-03-20 00:38:32 +01:00
switch ( category )
{
case 0 :
2008-05-13 00:59:58 +02:00
if ( * PQgetvalue ( result , i , 2 ) = = ' O ' )
list_rule = true ;
2007-03-20 00:38:32 +01:00
break ;
case 1 :
2008-05-13 00:59:58 +02:00
if ( * PQgetvalue ( result , i , 2 ) = = ' D ' )
list_rule = true ;
2007-03-20 00:38:32 +01:00
break ;
case 2 :
2008-05-13 00:59:58 +02:00
if ( * PQgetvalue ( result , i , 2 ) = = ' A ' )
list_rule = true ;
2007-03-20 00:38:32 +01:00
break ;
case 3 :
2008-05-13 00:59:58 +02:00
if ( * PQgetvalue ( result , i , 2 ) = = ' R ' )
list_rule = true ;
2007-03-20 00:38:32 +01:00
break ;
}
2008-05-13 00:59:58 +02:00
if ( ! list_rule )
continue ;
2007-03-20 00:38:32 +01:00
2008-05-13 00:59:58 +02:00
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 ) ;
}
2007-03-20 00:38:32 +01:00
}
2003-03-27 17:57:39 +01:00
}
2008-05-13 00:59:58 +02:00
PQclear ( result ) ;
2000-04-12 19:17:23 +02:00
}
2010-10-10 19:43:33 +02:00
}
/*
* Print triggers next , if any ( but only user - defined triggers ) . This
* could apply to either a table or a view .
*/
if ( tableinfo . hastriggers )
{
2011-04-10 17:42:00 +02:00
PGresult * result ;
int tuples ;
2000-04-12 19:17:23 +02:00
2011-04-10 17:42:00 +02:00
printfPQExpBuffer ( & buf ,
" SELECT t.tgname, "
" pg_catalog.pg_get_triggerdef(t.oid%s), "
" t.tgenabled \n "
" FROM pg_catalog.pg_trigger t \n "
" WHERE t.tgrelid = '%s' AND " ,
( pset . sversion > = 90000 ? " , true " : " " ) ,
oid ) ;
if ( pset . sversion > = 90000 )
appendPQExpBuffer ( & buf , " NOT t.tgisinternal " ) ;
else if ( pset . sversion > = 80300 )
appendPQExpBuffer ( & buf , " t.tgconstraint = 0 " ) ;
else
appendPQExpBuffer ( & buf ,
" (NOT tgisconstraint "
" OR NOT EXISTS "
" (SELECT 1 FROM pg_catalog.pg_depend d "
" JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
" WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f')) " ) ;
2011-07-06 16:11:20 +02:00
appendPQExpBuffer ( & buf , " \n ORDER BY 1; " ) ;
2008-07-03 05:37:17 +02:00
2011-04-10 17:42:00 +02:00
result = PSQLexec ( buf . data , false ) ;
if ( ! result )
goto error_return ;
else
tuples = PQntuples ( result ) ;
2008-05-13 00:59:58 +02:00
2011-04-10 17:42:00 +02:00
if ( tuples > 0 )
{
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 + + )
2003-03-27 17:57:39 +01:00
{
2011-04-10 17:42:00 +02:00
have_heading = false ;
for ( i = 0 ; i < tuples ; i + + )
2007-03-20 00:38:32 +01:00
{
2011-04-10 17:42:00 +02:00
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 :
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 )
2007-03-20 00:38:32 +01:00
{
switch ( category )
{
case 0 :
2011-04-10 17:42:00 +02:00
printfPQExpBuffer ( & buf , _ ( " Triggers: " ) ) ;
2007-03-20 00:38:32 +01:00
break ;
case 1 :
2011-04-10 17:42:00 +02:00
printfPQExpBuffer ( & buf , _ ( " Disabled triggers: " ) ) ;
2007-03-20 00:38:32 +01:00
break ;
case 2 :
2011-04-10 17:42:00 +02:00
printfPQExpBuffer ( & buf , _ ( " Triggers firing always: " ) ) ;
2007-03-20 00:38:32 +01:00
break ;
case 3 :
2011-04-10 17:42:00 +02:00
printfPQExpBuffer ( & buf , _ ( " Triggers firing on replica only: " ) ) ;
2007-03-20 00:38:32 +01:00
break ;
2008-05-13 00:59:58 +02:00
2007-03-20 00:38:32 +01:00
}
2008-05-13 00:59:58 +02:00
printTableAddFooter ( & cont , buf . data ) ;
2011-04-10 17:42:00 +02:00
have_heading = true ;
2008-05-13 00:59:58 +02:00
}
2011-04-10 17:42:00 +02:00
/* Everything after "TRIGGER" is echoed verbatim */
tgdef = PQgetvalue ( result , i , 1 ) ;
usingpos = strstr ( tgdef , " TRIGGER " ) ;
if ( usingpos )
tgdef = usingpos + 9 ;
printfPQExpBuffer ( & buf , " %s " , tgdef ) ;
printTableAddFooter ( & cont , buf . data ) ;
2007-03-20 00:38:32 +01:00
}
2007-01-20 22:17:30 +01:00
}
2011-04-10 17:42:00 +02:00
}
PQclear ( result ) ;
2010-10-10 19:43:33 +02:00
}
/*
* Finish printing the footer information about a table .
*/
2011-01-02 05:48:11 +01:00
if ( tableinfo . relkind = = ' r ' | | tableinfo . relkind = = ' f ' )
2010-10-10 19:43:33 +02:00
{
PGresult * result ;
int tuples ;
2007-01-20 22:17:30 +01:00
2011-01-02 05:48:11 +01:00
/* print foreign server name */
if ( tableinfo . relkind = = ' f ' )
{
2012-06-10 21:20:04 +02:00
char * ftoptions ;
2011-08-11 17:45:47 +02:00
2011-01-02 05:48:11 +01:00
/* Footer information about foreign table */
printfPQExpBuffer ( & buf ,
2011-08-11 17:45:47 +02:00
" SELECT s.srvname, \n "
2011-08-25 18:47:30 +02:00
" array_to_string(ARRAY(SELECT "
" quote_ident(option_name) || ' ' || "
" quote_literal(option_value) FROM "
2012-06-10 21:20:04 +02:00
" pg_options_to_table(ftoptions)), ', ') "
2011-01-02 05:48:11 +01:00
" FROM pg_catalog.pg_foreign_table f, \n "
" pg_catalog.pg_foreign_server s \n "
2011-07-06 16:11:20 +02:00
" WHERE f.ftrelid = %s AND s.oid = f.ftserver; " ,
2011-01-02 05:48:11 +01:00
oid ) ;
result = PSQLexec ( buf . data , false ) ;
if ( ! result )
goto error_return ;
else if ( PQntuples ( result ) ! = 1 )
{
PQclear ( result ) ;
goto error_return ;
}
2011-08-11 17:45:47 +02:00
/* Print server name */
2011-01-02 05:48:11 +01:00
printfPQExpBuffer ( & buf , " Server: %s " ,
2011-04-10 17:42:00 +02:00
PQgetvalue ( result , 0 , 0 ) ) ;
2011-01-02 05:48:11 +01:00
printTableAddFooter ( & cont , buf . data ) ;
2011-08-11 17:45:47 +02:00
/* Print per-table FDW options, if any */
ftoptions = PQgetvalue ( result , 0 , 1 ) ;
if ( ftoptions & & ftoptions [ 0 ] ! = ' \0 ' )
{
2011-08-25 18:47:30 +02:00
printfPQExpBuffer ( & buf , " FDW Options: (%s) " , ftoptions ) ;
2011-08-11 17:45:47 +02:00
printTableAddFooter ( & cont , buf . data ) ;
}
2011-01-02 05:48:11 +01:00
PQclear ( result ) ;
}
2008-05-13 00:59:58 +02:00
/* print inherited tables */
2011-07-06 16:11:20 +02:00
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 ) ;
2008-05-13 00:59:58 +02:00
result = PSQLexec ( buf . data , false ) ;
if ( ! result )
goto error_return ;
else
2003-07-25 23:42:26 +02:00
{
2007-11-15 22:14:46 +01:00
const char * s = _ ( " Inherits " ) ;
2012-03-08 01:25:59 +01:00
int sw = pg_wcswidth ( s , strlen ( s ) , pset . encoding ) ;
2003-07-25 23:42:26 +02:00
2012-03-08 01:25:59 +01:00
tuples = PQntuples ( result ) ;
2003-07-25 23:42:26 +02:00
2012-03-08 01:25:59 +01:00
for ( i = 0 ; i < tuples ; i + + )
{
if ( i = = 0 )
printfPQExpBuffer ( & buf , " %s: %s " ,
s , PQgetvalue ( result , i , 0 ) ) ;
else
printfPQExpBuffer ( & buf , " %*s %s " ,
sw , " " , PQgetvalue ( result , i , 0 ) ) ;
if ( i < tuples - 1 )
appendPQExpBuffer ( & buf , " , " ) ;
printTableAddFooter ( & cont , buf . data ) ;
}
PQclear ( result ) ;
2003-07-25 23:42:26 +02:00
}
2009-07-03 20:56:50 +02:00
/* print child tables */
2009-07-07 22:32:20 +02:00
if ( pset . sversion > = 80300 )
2009-07-07 23:45:05 +02:00
printfPQExpBuffer ( & buf , " SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhrelid AND i.inhparent = '%s' ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text; " , oid ) ;
2009-07-07 22:32:20 +02:00
else
printfPQExpBuffer ( & buf , " SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhrelid AND i.inhparent = '%s' ORDER BY c.relname; " , oid ) ;
2009-07-03 20:56:50 +02:00
result = PSQLexec ( buf . data , false ) ;
if ( ! result )
goto error_return ;
else
tuples = PQntuples ( result ) ;
if ( ! verbose )
{
/* print the number of child tables, if any */
if ( tuples > 0 )
{
printfPQExpBuffer ( & buf , _ ( " Number of child tables: %d (Use \\ d+ to list them.) " ) , tuples ) ;
printTableAddFooter ( & cont , buf . data ) ;
}
}
else
{
2009-07-07 18:28:38 +02:00
/* display the list of child tables */
const char * ct = _ ( " Child tables " ) ;
2012-03-08 01:25:59 +01:00
int ctw = pg_wcswidth ( ct , strlen ( ct ) , pset . encoding ) ;
2009-07-07 18:28:38 +02:00
2009-07-03 20:56:50 +02:00
for ( i = 0 ; i < tuples ; i + + )
2009-07-07 18:28:38 +02:00
{
if ( i = = 0 )
printfPQExpBuffer ( & buf , " %s: %s " ,
ct , PQgetvalue ( result , i , 0 ) ) ;
else
printfPQExpBuffer ( & buf , " %*s %s " ,
2012-03-08 01:25:59 +01:00
ctw , " " , PQgetvalue ( result , i , 0 ) ) ;
2009-07-07 18:28:38 +02:00
if ( i < tuples - 1 )
appendPQExpBuffer ( & buf , " , " ) ;
printTableAddFooter ( & cont , buf . data ) ;
}
2009-07-03 20:56:50 +02:00
}
PQclear ( result ) ;
2010-01-29 00:21:13 +01:00
/* Table type */
if ( tableinfo . reloftype )
{
printfPQExpBuffer ( & buf , _ ( " Typed table of type: %s " ) , tableinfo . reloftype ) ;
printTableAddFooter ( & cont , buf . data ) ;
}
2009-07-03 20:56:50 +02:00
/* OIDs and options */
2004-04-22 19:38:16 +02:00
if ( verbose )
{
2007-11-15 22:14:46 +01:00
const char * s = _ ( " Has OIDs " ) ;
2004-08-29 07:07:03 +02:00
2004-04-22 19:38:16 +02:00
printfPQExpBuffer ( & buf , " %s: %s " , s ,
( tableinfo . hasoids ? _ ( " yes " ) : _ ( " no " ) ) ) ;
2008-05-13 00:59:58 +02:00
printTableAddFooter ( & cont , buf . data ) ;
2008-12-19 15:39:58 +01:00
/* print reloptions */
if ( pset . sversion > = 80200 )
{
if ( tableinfo . reloptions & & tableinfo . reloptions [ 0 ] ! = ' \0 ' )
{
const char * t = _ ( " Options " ) ;
printfPQExpBuffer ( & buf , " %s: %s " , t ,
tableinfo . reloptions ) ;
printTableAddFooter ( & cont , buf . data ) ;
}
}
2004-04-22 19:38:16 +02:00
}
2008-05-13 00:59:58 +02:00
add_tablespace_footer ( & cont , tableinfo . relkind , tableinfo . tablespace ,
true ) ;
* Includes tab completion. It's not magic, but it's very cool. At any
rate
it's better than what used to be there.
* Does proper SQL "host variable" substitution as pointed out by Andreas
Zeugwetter (thanks): select * from :foo; Also some changes in how ':'
and ';' are treated (escape with \ to send to backend). This does
_not_
affect the '::' cast operator, but perhaps others that contain : or ;
(but there are none right now).
* To show description with a <something> listing, append '?' to command
name, e.g., \df?. This seemed to be the convenient and logical
solution.
Or append a '+' to see more useless information, e.g., \df+.
* Fixed fflush()'ing bug pointed out by Jan during the regression test
discussion.
* Added LastOid variable. This ought to take care of TODO item "Add a
function to return the last inserted oid, for use in psql scripts"
(under CLIENTS)
E.g.,
insert into foo values(...);
insert into bar values(..., :LastOid);
\echo $LastOid
* \d command shows constraints, rules, and triggers defined on the table
(in addition to indices)
* Various fixes, optimizations, corrections
* Documentation update as well
Note: This now requires snprintf(), which, if necessary, is taken from
src/backend/port. This is certainly a little weird, but it should
suffice
until a source tree cleanup is done.
Enjoy.
--
Peter Eisentraut Sernanders väg 10:115
1999-11-26 05:24:17 +01:00
}
1999-11-04 22:56:02 +01:00
2008-05-13 00:59:58 +02:00
printTable ( & cont , pset . queryFout , pset . logfile ) ;
printTableCleanup ( & cont ) ;
2002-04-24 07:24:00 +02:00
retval = true ;
error_return :
1999-11-04 22:56:02 +01:00
1999-11-05 00:14:30 +01:00
/* clean up */
2008-11-03 20:08:56 +01:00
if ( printTableInitialized )
printTableCleanup ( & cont ) ;
2002-04-24 07:24:00 +02:00
termPQExpBuffer ( & buf ) ;
termPQExpBuffer ( & title ) ;
2002-12-21 02:07:07 +01:00
termPQExpBuffer ( & tmpbuf ) ;
2009-06-11 16:49:15 +02:00
2008-07-18 06:20:24 +02:00
if ( seq_values )
2008-07-15 05:16:03 +02:00
{
for ( ptr = seq_values ; * ptr ; ptr + + )
free ( * ptr ) ;
free ( seq_values ) ;
}
2009-06-11 16:49:15 +02:00
2008-07-18 06:20:24 +02:00
if ( modifiers )
2002-04-24 07:24:00 +02:00
{
2008-05-13 00:59:58 +02:00
for ( ptr = modifiers ; * ptr ; ptr + + )
2002-04-24 07:24:00 +02:00
free ( * ptr ) ;
2008-05-13 00:59:58 +02:00
free ( modifiers ) ;
2002-04-24 07:24:00 +02:00
}
1999-11-04 22:56:02 +01:00
2002-08-10 05:56:24 +02:00
if ( view_def )
free ( view_def ) ;
2002-04-24 07:24:00 +02:00
if ( res )
PQclear ( res ) ;
1999-11-04 22:56:02 +01:00
2002-04-24 07:24:00 +02:00
return retval ;
1999-11-04 22:56:02 +01:00
}
2005-10-15 04:49:52 +02:00
/*
2008-05-13 00:59:58 +02:00
* 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 .
2005-06-15 01:59:31 +02:00
*/
2008-05-13 00:59:58 +02:00
static void
add_tablespace_footer ( printTableContent * const cont , char relkind ,
Oid tablespace , const bool newline )
2004-07-12 22:41:13 +02:00
{
/* relkinds for which we support tablespaces */
2004-08-29 07:07:03 +02:00
if ( relkind = = ' r ' | | relkind = = ' i ' )
2004-07-12 22:41:13 +02:00
{
/*
2005-10-15 04:49:52 +02:00
* We ignore the database default tablespace so that users not using
2008-07-03 05:37:17 +02:00
* tablespaces don ' t need to know about them . This case also covers
* pre - 8.0 servers , for which tablespace will always be 0.
2004-07-12 22:41:13 +02:00
*/
2004-08-29 07:07:03 +02:00
if ( tablespace ! = 0 )
2004-07-12 22:41:13 +02:00
{
2008-05-13 00:59:58 +02:00
PGresult * result = NULL ;
PQExpBufferData buf ;
2004-08-29 07:07:03 +02:00
2008-05-13 00:59:58 +02:00
initPQExpBuffer ( & buf ) ;
2008-07-03 05:37:17 +02:00
printfPQExpBuffer ( & buf ,
" SELECT spcname FROM pg_catalog.pg_tablespace \n "
2011-07-06 16:11:20 +02:00
" WHERE oid = '%u'; " , tablespace ) ;
2008-05-13 00:59:58 +02:00
result = PSQLexec ( buf . data , false ) ;
if ( ! result )
return ;
2004-07-12 22:41:13 +02:00
/* Should always be the case, but.... */
2008-05-13 00:59:58 +02:00
if ( PQntuples ( result ) > 0 )
2004-07-12 22:41:13 +02:00
{
2008-05-13 00:59:58 +02:00
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 ) ;
2009-06-11 16:49:15 +02:00
/*
* translator : before this string there ' s an index
* description like ' " foo_pkey " PRIMARY KEY , btree ( a ) '
*/
2008-05-13 00:59:58 +02:00
appendPQExpBuffer ( & buf , _ ( " , tablespace \" %s \" " ) ,
PQgetvalue ( result , 0 , 0 ) ) ;
printTableSetFooter ( cont , buf . data ) ;
}
2004-07-12 22:41:13 +02:00
}
2008-05-13 00:59:58 +02:00
PQclear ( result ) ;
termPQExpBuffer ( & buf ) ;
2004-07-12 22:41:13 +02:00
}
}
}
2001-05-09 19:29:10 +02:00
/*
2005-08-14 20:49:30 +02:00
* \ du or \ dg
2001-05-09 19:29:10 +02:00
*
2005-08-14 20:49:30 +02:00
* Describes roles . Any schema portion of the pattern is ignored .
2001-05-09 19:29:10 +02:00
*/
bool
2006-02-12 04:22:21 +01:00
describeRoles ( const char * pattern , bool verbose )
2001-05-09 19:29:10 +02:00
{
2002-04-24 07:24:00 +02:00
PQExpBufferData buf ;
2001-05-09 19:29:10 +02:00
PGresult * res ;
2008-05-13 02:23:17 +02:00
printTableContent cont ;
printTableOpt myopt = pset . popt . topt ;
int ncols = 3 ;
int nrows = 0 ;
int i ;
int conns ;
const char align = ' l ' ;
char * * attr ;
2001-10-25 07:50:21 +02:00
2012-05-01 22:03:45 +02:00
myopt . default_footer = false ;
2002-04-24 07:24:00 +02:00
initPQExpBuffer ( & buf ) ;
2008-07-03 05:37:17 +02:00
if ( pset . sversion > = 80100 )
{
printfPQExpBuffer ( & buf ,
2009-06-11 16:49:15 +02:00
" SELECT r.rolname, r.rolsuper, r.rolinherit, \n "
" r.rolcreaterole, r.rolcreatedb, r.rolcanlogin, \n "
2012-03-22 07:08:25 +01:00
" r.rolconnlimit, r.rolvaliduntil, \n "
2009-06-11 16:49:15 +02:00
" ARRAY(SELECT b.rolname \n "
" FROM pg_catalog.pg_auth_members m \n "
" JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid) \n "
" WHERE m.member = r.oid) as memberof " ) ;
2003-12-01 23:21:54 +01:00
2008-07-03 05:37:17 +02:00
if ( verbose & & pset . sversion > = 80200 )
{
appendPQExpBufferStr ( & buf , " \n , pg_catalog.shobj_description(r.oid, 'pg_authid') AS description " ) ;
ncols + + ;
}
2010-12-29 11:05:03 +01:00
if ( pset . sversion > = 90100 )
{
2011-04-10 17:42:00 +02:00
appendPQExpBufferStr ( & buf , " \n , r.rolreplication " ) ;
2010-12-29 11:05:03 +01:00
}
2006-02-12 04:22:21 +01:00
2008-07-03 05:37:17 +02:00
appendPQExpBufferStr ( & buf , " \n FROM pg_catalog.pg_roles r \n " ) ;
processSQLNamePattern ( pset . db , & buf , pattern , false , false ,
NULL , " r.rolname " , NULL , NULL ) ;
2009-06-11 16:49:15 +02:00
}
else
{
printfPQExpBuffer ( & buf ,
" SELECT u.usename AS rolname, \n "
" u.usesuper AS rolsuper, \n "
" true AS rolinherit, false AS rolcreaterole, \n "
" u.usecreatedb AS rolcreatedb, true AS rolcanlogin, \n "
2012-03-22 07:08:25 +01:00
" -1 AS rolconnlimit, "
" u.valuntil as rolvaliduntil, \n "
2009-06-11 16:49:15 +02:00
" ARRAY(SELECT g.groname FROM pg_catalog.pg_group g WHERE u.usesysid = ANY(g.grolist)) as memberof "
" \n FROM pg_catalog.pg_user u \n " ) ;
2008-07-03 05:37:17 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , false , false ,
NULL , " u.usename " , NULL , NULL ) ;
2009-06-11 16:49:15 +02:00
}
2003-12-01 23:21:54 +01:00
appendPQExpBuffer ( & buf , " ORDER BY 1; " ) ;
res = PSQLexec ( buf . data , false ) ;
if ( ! res )
return false ;
2008-05-13 02:23:17 +02:00
nrows = PQntuples ( res ) ;
attr = pg_malloc_zero ( ( nrows + 1 ) * sizeof ( * attr ) ) ;
2003-12-01 23:21:54 +01:00
2008-05-13 02:23:17 +02:00
printTableInit ( & cont , & myopt , _ ( " List of roles " ) , ncols , nrows ) ;
printTableAddHeader ( & cont , gettext_noop ( " Role name " ) , true , align ) ;
printTableAddHeader ( & cont , gettext_noop ( " Attributes " ) , true , align ) ;
printTableAddHeader ( & cont , gettext_noop ( " Member of " ) , true , align ) ;
2008-07-03 05:37:17 +02:00
if ( verbose & & pset . sversion > = 80200 )
2008-05-13 02:23:17 +02:00
printTableAddHeader ( & cont , gettext_noop ( " Description " ) , true , align ) ;
for ( i = 0 ; i < nrows ; i + + )
{
2010-03-01 21:55:45 +01:00
printTableAddCell ( & cont , PQgetvalue ( res , i , 0 ) , false , false ) ;
2008-05-13 02:23:17 +02:00
resetPQExpBuffer ( & buf ) ;
if ( strcmp ( PQgetvalue ( res , i , 1 ) , " t " ) = = 0 )
add_role_attribute ( & buf , _ ( " Superuser " ) ) ;
if ( strcmp ( PQgetvalue ( res , i , 2 ) , " t " ) ! = 0 )
add_role_attribute ( & buf , _ ( " No inheritance " ) ) ;
if ( strcmp ( PQgetvalue ( res , i , 3 ) , " t " ) = = 0 )
add_role_attribute ( & buf , _ ( " Create role " ) ) ;
if ( strcmp ( PQgetvalue ( res , i , 4 ) , " t " ) = = 0 )
add_role_attribute ( & buf , _ ( " Create DB " ) ) ;
if ( strcmp ( PQgetvalue ( res , i , 5 ) , " t " ) ! = 0 )
add_role_attribute ( & buf , _ ( " Cannot login " ) ) ;
2010-12-29 11:05:03 +01:00
if ( pset . sversion > = 90100 )
2012-03-22 07:08:25 +01:00
if ( strcmp ( PQgetvalue ( res , i , ( verbose ? 10 : 9 ) ) , " t " ) = = 0 )
2010-12-29 11:05:03 +01:00
add_role_attribute ( & buf , _ ( " Replication " ) ) ;
2008-05-13 02:23:17 +02:00
conns = atoi ( PQgetvalue ( res , i , 6 ) ) ;
if ( conns > = 0 )
{
if ( buf . len > 0 )
appendPQExpBufferStr ( & buf , " \n " ) ;
if ( conns = = 0 )
appendPQExpBuffer ( & buf , _ ( " No connections " ) ) ;
else
2009-06-04 21:17:39 +02:00
appendPQExpBuffer ( & buf , ngettext ( " %d connection " ,
" %d connections " ,
conns ) ,
conns ) ;
2008-05-13 02:23:17 +02:00
}
2012-03-22 07:08:25 +01:00
if ( strcmp ( PQgetvalue ( res , i , 7 ) , " " ) ! = 0 )
{
if ( buf . len > 0 )
appendPQExpBufferStr ( & buf , " \n " ) ;
appendPQExpBufferStr ( & buf , _ ( " Password valid until " ) ) ;
appendPQExpBufferStr ( & buf , PQgetvalue ( res , i , 7 ) ) ;
}
2008-05-13 02:23:17 +02:00
attr [ i ] = pg_strdup ( buf . data ) ;
2010-03-01 21:55:45 +01:00
printTableAddCell ( & cont , attr [ i ] , false , false ) ;
2008-05-13 02:23:17 +02:00
2012-03-22 07:08:25 +01:00
printTableAddCell ( & cont , PQgetvalue ( res , i , 8 ) , false , false ) ;
2008-05-13 02:23:17 +02:00
2008-07-03 05:37:17 +02:00
if ( verbose & & pset . sversion > = 80200 )
2012-03-22 07:08:25 +01:00
printTableAddCell ( & cont , PQgetvalue ( res , i , 9 ) , false , false ) ;
2008-05-13 02:23:17 +02:00
}
termPQExpBuffer ( & buf ) ;
printTable ( & cont , pset . queryFout , pset . logfile ) ;
printTableCleanup ( & cont ) ;
for ( i = 0 ; i < nrows ; i + + )
free ( attr [ i ] ) ;
free ( attr ) ;
2003-12-01 23:21:54 +01:00
PQclear ( res ) ;
return true ;
}
2009-06-12 18:17:29 +02:00
static void
2008-05-13 02:23:17 +02:00
add_role_attribute ( PQExpBuffer buf , const char * const str )
{
if ( buf - > len > 0 )
2009-11-11 22:07:41 +01:00
appendPQExpBufferStr ( buf , " , " ) ;
2008-05-13 02:23:17 +02:00
appendPQExpBufferStr ( buf , str ) ;
}
2009-10-08 00:14:26 +02:00
/*
* \ drds
*/
bool
listDbRoleSettings ( const char * pattern , const char * pattern2 )
{
2010-02-26 03:01:40 +01:00
PQExpBufferData buf ;
PGresult * res ;
2009-10-08 00:14:26 +02:00
printQueryOpt myopt = pset . popt ;
initPQExpBuffer ( & buf ) ;
2010-02-17 05:19:41 +01:00
if ( pset . sversion > = 90000 )
2009-10-08 00:14:26 +02:00
{
2010-02-26 03:01:40 +01:00
bool havewhere ;
2009-10-08 00:14:26 +02:00
printfPQExpBuffer ( & buf , " SELECT rolname AS role, datname AS database, \n "
2010-02-26 03:01:40 +01:00
" pg_catalog.array_to_string(setconfig, E' \\ n') AS settings \n "
2009-10-08 00:14:26 +02:00
" FROM pg_db_role_setting AS s \n "
2010-02-26 03:01:40 +01:00
" LEFT JOIN pg_database ON pg_database.oid = setdatabase \n "
2009-10-08 00:14:26 +02:00
" LEFT JOIN pg_roles ON pg_roles.oid = setrole \n " ) ;
havewhere = processSQLNamePattern ( pset . db , & buf , pattern , false , false ,
2010-02-26 03:01:40 +01:00
NULL , " pg_roles.rolname " , NULL , NULL ) ;
2009-10-08 00:14:26 +02:00
processSQLNamePattern ( pset . db , & buf , pattern2 , havewhere , false ,
NULL , " pg_database.datname " , NULL , NULL ) ;
2011-07-06 16:11:20 +02:00
appendPQExpBufferStr ( & buf , " ORDER BY role, database; " ) ;
2009-10-08 00:14:26 +02:00
}
else
{
fprintf ( pset . queryFout ,
2010-02-26 03:01:40 +01:00
_ ( " No per-database role settings support in this server version. \n " ) ) ;
2009-10-08 00:14:26 +02:00
return false ;
}
res = PSQLexec ( buf . data , false ) ;
if ( ! res )
return false ;
if ( PQntuples ( res ) = = 0 & & ! pset . quiet )
{
if ( pattern )
fprintf ( pset . queryFout , _ ( " No matching settings found. \n " ) ) ;
else
fprintf ( pset . queryFout , _ ( " No settings found. \n " ) ) ;
}
else
{
myopt . nullPrint = NULL ;
myopt . title = _ ( " List of settings " ) ;
myopt . translate_header = true ;
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
}
PQclear ( res ) ;
resetPQExpBuffer ( & buf ) ;
return true ;
}
2003-12-01 23:21:54 +01:00
1999-11-04 22:56:02 +01:00
/*
* listTables ( )
*
2009-04-04 02:44:30 +02:00
* handler for \ dt , \ di , etc .
1999-11-04 22:56:02 +01:00
*
2002-08-10 05:56:24 +02:00
* tabtypes is an array of characters , specifying what info is desired :
1999-11-04 22:56:02 +01:00
* t - tables
2001-06-30 19:26:12 +02:00
* i - indexes
1999-11-04 22:56:02 +01:00
* v - views
* s - sequences
2011-01-02 05:48:11 +01:00
* E - foreign table ( Note : different from ' f ' , the relkind value )
1999-11-04 22:56:02 +01:00
* ( any order of the above is fine )
2011-01-02 05:48:11 +01:00
* If tabtypes is empty , we default to \ dtvsE .
1999-11-04 22:56:02 +01:00
*/
bool
2009-01-06 22:10:30 +01:00
listTables ( const char * tabtypes , const char * pattern , bool verbose , bool showSystem )
1999-11-04 22:56:02 +01:00
{
2002-08-10 05:56:24 +02:00
bool showTables = strchr ( tabtypes , ' t ' ) ! = NULL ;
bool showIndexes = strchr ( tabtypes , ' i ' ) ! = NULL ;
bool showViews = strchr ( tabtypes , ' v ' ) ! = NULL ;
bool showSeq = strchr ( tabtypes , ' s ' ) ! = NULL ;
2011-01-02 05:48:11 +01:00
bool showForeign = strchr ( tabtypes , ' E ' ) ! = NULL ;
1999-11-05 00:14:30 +01:00
2002-04-24 07:24:00 +02:00
PQExpBufferData buf ;
1999-11-05 00:14:30 +01:00
PGresult * res ;
2000-01-14 23:18:03 +01:00
printQueryOpt myopt = pset . popt ;
2009-01-22 21:16:10 +01:00
static const bool translate_columns [ ] = { false , false , true , false , false , false , false } ;
1999-11-05 00:14:30 +01:00
2011-01-02 05:48:11 +01:00
if ( ! ( showTables | | showIndexes | | showViews | | showSeq | | showForeign ) )
showTables = showViews = showSeq = showForeign = true ;
2000-04-16 22:04:51 +02:00
2002-04-24 07:24:00 +02:00
initPQExpBuffer ( & buf ) ;
2000-04-16 22:04:51 +02:00
2006-05-28 04:27:08 +02:00
/*
* Note : as of Pg 8.2 , we no longer use relkind ' s ' , but we keep it here
* for backwards compatibility .
*/
2002-04-24 07:24:00 +02:00
printfPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" SELECT n.nspname as \" %s \" , \n "
" c.relname as \" %s \" , \n "
2011-01-02 05:48:11 +01:00
" CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' WHEN 's' THEN '%s' WHEN 'f' THEN '%s' END as \" %s \" , \n "
2008-07-03 05:37:17 +02:00
" pg_catalog.pg_get_userbyid(c.relowner) as \" %s \" " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Schema " ) ,
gettext_noop ( " Name " ) ,
2008-07-03 05:37:17 +02:00
gettext_noop ( " table " ) ,
gettext_noop ( " view " ) ,
gettext_noop ( " index " ) ,
gettext_noop ( " sequence " ) ,
gettext_noop ( " special " ) ,
2011-01-02 05:48:11 +01:00
gettext_noop ( " foreign table " ) ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Type " ) ,
gettext_noop ( " Owner " ) ) ;
2000-01-12 20:36:36 +01:00
2004-09-10 06:10:53 +02:00
if ( showIndexes )
appendPQExpBuffer ( & buf ,
" , \n c2.relname as \" %s \" " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Table " ) ) ;
2004-09-10 06:10:53 +02:00
2008-07-03 05:37:17 +02:00
if ( verbose )
2011-04-08 21:52:49 +02:00
{
/*
2011-04-10 17:42:00 +02:00
* As of PostgreSQL 9.0 , use pg_table_size ( ) to show a more acurate
* size of a table , including FSM , VM and TOAST tables .
2011-04-08 21:52:49 +02:00
*/
if ( pset . sversion > = 90000 )
appendPQExpBuffer ( & buf ,
" , \n pg_catalog.pg_size_pretty(pg_catalog.pg_table_size(c.oid)) as \" %s \" " ,
gettext_noop ( " Size " ) ) ;
else if ( pset . sversion > = 80100 )
appendPQExpBuffer ( & buf ,
" , \n pg_catalog.pg_size_pretty(pg_catalog.pg_relation_size(c.oid)) as \" %s \" " ,
gettext_noop ( " Size " ) ) ;
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf ,
2005-10-15 04:49:52 +02:00
" , \n pg_catalog.obj_description(c.oid, 'pg_class') as \" %s \" " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Description " ) ) ;
2011-04-08 21:52:49 +02:00
}
2002-08-10 05:56:24 +02:00
2005-08-14 21:20:45 +02:00
appendPQExpBuffer ( & buf ,
" \n FROM pg_catalog.pg_class c "
2005-10-15 04:49:52 +02:00
" \n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace " ) ;
2002-09-04 22:31:48 +02:00
if ( showIndexes )
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf ,
2005-10-15 04:49:52 +02:00
" \n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid "
" \n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid " ) ;
2002-04-24 07:24:00 +02:00
2005-08-14 21:20:45 +02:00
appendPQExpBuffer ( & buf , " \n WHERE c.relkind IN ( " ) ;
2001-06-30 19:26:12 +02:00
if ( showTables )
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf , " 'r', " ) ;
1999-11-05 00:14:30 +01:00
if ( showViews )
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf , " 'v', " ) ;
2001-06-30 19:26:12 +02:00
if ( showIndexes )
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf , " 'i', " ) ;
2001-06-30 19:26:12 +02:00
if ( showSeq )
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf , " 'S', " ) ;
2009-04-02 17:15:32 +02:00
if ( showSystem | | pattern )
2009-06-11 16:49:15 +02:00
appendPQExpBuffer ( & buf , " 's', " ) ; /* was RELKIND_SPECIAL in <=
* 8.1 */
2011-01-02 05:48:11 +01:00
if ( showForeign )
appendPQExpBuffer ( & buf , " 'f', " ) ;
2002-09-04 22:31:48 +02:00
appendPQExpBuffer ( & buf , " '' " ) ; /* dummy */
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf , " ) \n " ) ;
1999-11-05 00:14:30 +01:00
2009-06-11 16:49:15 +02:00
if ( ! showSystem & & ! pattern )
appendPQExpBuffer ( & buf , " AND n.nspname <> 'pg_catalog' \n "
" AND n.nspname <> 'information_schema' \n " ) ;
2009-04-04 02:41:11 +02:00
/*
* TOAST objects are suppressed unconditionally . Since we don ' t provide
* any way to select relkind ' t ' above , we would never show toast tables
* in any case ; it seems a bit confusing to allow their indexes to be
* shown . Use plain \ d if you really need to look at a TOAST table / index .
*/
appendPQExpBuffer ( & buf , " AND n.nspname !~ '^pg_toast' \n " ) ;
2002-09-22 22:44:22 +02:00
2006-10-10 01:30:33 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , true , false ,
" n.nspname " , " c.relname " , NULL ,
" pg_catalog.pg_table_is_visible(c.oid) " ) ;
1999-11-04 22:56:02 +01:00
2002-08-09 20:06:57 +02:00
appendPQExpBuffer ( & buf , " ORDER BY 1,2; " ) ;
1999-11-04 22:56:02 +01:00
2002-10-15 04:24:16 +02:00
res = PSQLexec ( buf . data , false ) ;
2002-04-24 07:24:00 +02:00
termPQExpBuffer ( & buf ) ;
1999-11-05 00:14:30 +01:00
if ( ! res )
return false ;
1999-11-04 22:56:02 +01:00
2006-08-29 17:19:51 +02:00
if ( PQntuples ( res ) = = 0 & & ! pset . quiet )
2000-04-12 19:17:23 +02:00
{
2002-08-10 05:56:24 +02:00
if ( pattern )
2001-06-30 19:26:12 +02:00
fprintf ( pset . queryFout , _ ( " No matching relations found. \n " ) ) ;
2000-04-12 19:17:23 +02:00
else
2001-06-30 19:26:12 +02:00
fprintf ( pset . queryFout , _ ( " No relations found. \n " ) ) ;
2000-04-12 19:17:23 +02:00
}
1999-11-05 00:14:30 +01:00
else
{
myopt . nullPrint = NULL ;
2001-06-30 19:26:12 +02:00
myopt . title = _ ( " List of relations " ) ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
myopt . translate_columns = translate_columns ;
1999-11-04 22:56:02 +01:00
2005-06-14 04:57:45 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
1999-11-05 00:14:30 +01:00
}
1999-11-04 22:56:02 +01:00
1999-11-05 00:14:30 +01:00
PQclear ( res ) ;
return true ;
1999-11-04 22:56:02 +01:00
}
2002-03-19 03:32:21 +01:00
2002-04-24 07:24:00 +02:00
2011-01-20 06:00:30 +01:00
/*
* \ dL
*
* Describes languages .
*/
bool
listLanguages ( const char * pattern , bool verbose , bool showSystem )
{
PQExpBufferData buf ;
2011-04-10 17:42:00 +02:00
PGresult * res ;
2011-01-20 06:00:30 +01:00
printQueryOpt myopt = pset . popt ;
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
" SELECT l.lanname AS \" %s \" , \n " ,
gettext_noop ( " Name " ) ) ;
if ( pset . sversion > = 80300 )
2011-04-10 17:42:00 +02:00
appendPQExpBuffer ( & buf ,
" pg_catalog.pg_get_userbyid(l.lanowner) as \" %s \" , \n " ,
gettext_noop ( " Owner " ) ) ;
2011-01-20 06:00:30 +01:00
appendPQExpBuffer ( & buf ,
2011-08-08 18:26:13 +02:00
" l.lanpltrusted AS \" %s \" " ,
gettext_noop ( " Trusted " ) ) ;
2011-01-20 06:00:30 +01:00
if ( verbose )
{
2011-04-10 17:42:00 +02:00
appendPQExpBuffer ( & buf ,
" , \n NOT l.lanispl AS \" %s \" , \n "
" l.lanplcallfoid::regprocedure AS \" %s \" , \n "
" l.lanvalidator::regprocedure AS \" %s \" , \n " ,
gettext_noop ( " Internal Language " ) ,
gettext_noop ( " Call Handler " ) ,
gettext_noop ( " Validator " ) ) ;
if ( pset . sversion > = 90000 )
appendPQExpBuffer ( & buf , " l.laninline::regprocedure AS \" %s \" , \n " ,
gettext_noop ( " Inline Handler " ) ) ;
printACLColumn ( & buf , " l.lanacl " ) ;
2011-01-20 06:00:30 +01:00
}
appendPQExpBuffer ( & buf ,
2011-08-08 18:26:13 +02:00
" , \n d.description AS \" %s \" "
2011-08-04 18:22:26 +02:00
" \n FROM pg_catalog.pg_language l \n "
" LEFT JOIN pg_catalog.pg_description d \n "
" ON d.classoid = l.tableoid AND d.objoid = l.oid \n "
2011-08-08 18:26:13 +02:00
" AND d.objsubid = 0 \n " ,
gettext_noop ( " Description " ) ) ;
2011-01-20 06:00:30 +01:00
2011-08-04 18:22:26 +02:00
if ( pattern )
processSQLNamePattern ( pset . db , & buf , pattern , false , false ,
NULL , " l.lanname " , NULL , NULL ) ;
2011-01-20 06:00:30 +01:00
if ( ! showSystem & & ! pattern )
2011-08-04 18:22:26 +02:00
appendPQExpBuffer ( & buf , " WHERE l.lanplcallfoid != 0 \n " ) ;
2011-01-20 06:00:30 +01:00
appendPQExpBuffer ( & buf , " ORDER BY 1; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
myopt . title = _ ( " List of languages " ) ;
myopt . translate_header = true ;
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
PQclear ( res ) ;
return true ;
}
2002-03-19 03:32:21 +01:00
/*
2002-08-10 05:56:24 +02:00
* \ dD
2002-03-19 03:32:21 +01:00
*
2002-08-10 05:56:24 +02:00
* Describes domains .
2002-03-19 03:32:21 +01:00
*/
bool
2011-08-08 18:26:13 +02:00
listDomains ( const char * pattern , bool verbose , bool showSystem )
2002-03-19 03:32:21 +01:00
{
2002-04-24 07:24:00 +02:00
PQExpBufferData buf ;
2002-03-19 03:32:21 +01:00
PGresult * res ;
printQueryOpt myopt = pset . popt ;
2002-04-24 07:24:00 +02:00
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" SELECT n.nspname as \" %s \" , \n "
" t.typname as \" %s \" , \n "
2011-06-09 20:32:50 +02:00
" pg_catalog.format_type(t.typbasetype, t.typtypmod) as \" %s \" , \n "
2011-04-18 00:09:22 +02:00
" TRIM(LEADING \n " ,
gettext_noop ( " Schema " ) ,
gettext_noop ( " Name " ) ,
gettext_noop ( " Type " ) ) ;
2011-08-11 17:16:29 +02:00
2011-04-18 00:09:22 +02:00
if ( pset . sversion > = 90100 )
appendPQExpBuffer ( & buf ,
" COALESCE((SELECT ' collate ' || c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type bt \n "
" WHERE c.oid = t.typcollation AND bt.oid = t.typbasetype AND t.typcollation <> bt.typcollation), '') || \n " ) ;
appendPQExpBuffer ( & buf ,
2011-06-09 20:32:50 +02:00
" CASE WHEN t.typnotnull THEN ' not null' ELSE '' END || \n "
2011-04-18 00:09:22 +02:00
" CASE WHEN t.typdefault IS NOT NULL THEN ' default ' || t.typdefault ELSE '' END \n "
2011-08-08 18:26:13 +02:00
" ) as \" %s \" , \n "
2009-02-23 16:59:55 +01:00
" pg_catalog.array_to_string(ARRAY( \n "
" SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM pg_catalog.pg_constraint r WHERE t.oid = r.contypid \n "
2011-08-08 18:26:13 +02:00
" ), ' ') as \" %s \" " ,
gettext_noop ( " Modifier " ) ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Check " ) ) ;
2002-08-10 05:56:24 +02:00
2011-08-08 18:26:13 +02:00
if ( verbose )
2011-12-19 23:05:19 +01:00
{
if ( pset . sversion > = 90200 )
{
appendPQExpBuffer ( & buf , " , \n " ) ;
printACLColumn ( & buf , " t.typacl " ) ;
}
2011-08-08 18:26:13 +02:00
appendPQExpBuffer ( & buf ,
" , \n d.description as \" %s \" " ,
gettext_noop ( " Description " ) ) ;
2011-12-19 23:05:19 +01:00
}
2011-08-08 18:26:13 +02:00
appendPQExpBuffer ( & buf ,
" \n FROM pg_catalog.pg_type t \n "
2012-06-10 21:20:04 +02:00
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace \n " ) ;
2011-08-08 18:26:13 +02:00
if ( verbose )
appendPQExpBuffer ( & buf ,
" LEFT JOIN pg_catalog.pg_description d "
" ON d.classoid = t.tableoid AND d.objoid = t.oid "
" AND d.objsubid = 0 \n " ) ;
appendPQExpBuffer ( & buf , " WHERE t.typtype = 'd' \n " ) ;
2009-06-11 16:49:15 +02:00
if ( ! showSystem & & ! pattern )
appendPQExpBuffer ( & buf , " AND n.nspname <> 'pg_catalog' \n "
" AND n.nspname <> 'information_schema' \n " ) ;
2009-01-06 22:10:30 +01:00
2006-10-10 01:30:33 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , true , false ,
" n.nspname " , " t.typname " , NULL ,
" pg_catalog.pg_type_is_visible(t.oid) " ) ;
2002-08-10 05:56:24 +02:00
appendPQExpBuffer ( & buf , " ORDER BY 1, 2; " ) ;
2002-03-19 03:32:21 +01:00
2002-10-15 04:24:16 +02:00
res = PSQLexec ( buf . data , false ) ;
2002-04-24 07:24:00 +02:00
termPQExpBuffer ( & buf ) ;
2002-03-19 03:32:21 +01:00
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
2002-04-24 07:24:00 +02:00
myopt . title = _ ( " List of domains " ) ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
2002-03-19 03:32:21 +01:00
2005-06-14 04:57:45 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
2002-03-19 03:32:21 +01:00
PQclear ( res ) ;
return true ;
}
2002-08-10 05:56:24 +02:00
2002-12-12 22:02:25 +01:00
/*
* \ dc
*
* Describes conversions .
*/
bool
2011-08-08 18:26:13 +02:00
listConversions ( const char * pattern , bool verbose , bool showSystem )
2002-12-12 22:02:25 +01:00
{
PQExpBufferData buf ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
2008-07-15 00:00:04 +02:00
static const bool translate_columns [ ] = { false , false , false , false , true } ;
2002-12-12 22:02:25 +01:00
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
" SELECT n.nspname AS \" %s \" , \n "
" c.conname AS \" %s \" , \n "
2005-10-15 04:49:52 +02:00
" pg_catalog.pg_encoding_to_char(c.conforencoding) AS \" %s \" , \n "
" pg_catalog.pg_encoding_to_char(c.contoencoding) AS \" %s \" , \n "
2002-12-12 22:02:25 +01:00
" CASE WHEN c.condefault THEN '%s' \n "
2011-08-08 18:26:13 +02:00
" ELSE '%s' END AS \" %s \" " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Schema " ) ,
gettext_noop ( " Name " ) ,
gettext_noop ( " Source " ) ,
gettext_noop ( " Destination " ) ,
gettext_noop ( " yes " ) , gettext_noop ( " no " ) ,
gettext_noop ( " Default? " ) ) ;
2002-12-12 22:02:25 +01:00
2011-08-08 18:26:13 +02:00
if ( verbose )
appendPQExpBuffer ( & buf ,
" , \n d.description AS \" %s \" " ,
gettext_noop ( " Description " ) ) ;
appendPQExpBuffer ( & buf ,
" \n FROM pg_catalog.pg_conversion c \n "
" JOIN pg_catalog.pg_namespace n "
" ON n.oid = c.connamespace \n " ) ;
if ( verbose )
appendPQExpBuffer ( & buf ,
" LEFT JOIN pg_catalog.pg_description d "
" ON d.classoid = c.tableoid \n "
" AND d.objoid = c.oid "
" AND d.objsubid = 0 \n " ) ;
appendPQExpBuffer ( & buf , " WHERE true \n " ) ;
2009-06-11 16:49:15 +02:00
if ( ! showSystem & & ! pattern )
2011-08-08 18:26:13 +02:00
appendPQExpBuffer ( & buf , " AND n.nspname <> 'pg_catalog' \n "
" AND n.nspname <> 'information_schema' \n " ) ;
2009-01-06 22:10:30 +01:00
2006-10-10 01:30:33 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , true , false ,
" n.nspname " , " c.conname " , NULL ,
" pg_catalog.pg_conversion_is_visible(c.oid) " ) ;
2002-12-12 22:02:25 +01:00
appendPQExpBuffer ( & buf , " ORDER BY 1, 2; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
myopt . title = _ ( " List of conversions " ) ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
myopt . translate_columns = translate_columns ;
2002-12-12 22:02:25 +01:00
2005-06-14 04:57:45 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
2002-12-12 22:02:25 +01:00
PQclear ( res ) ;
return true ;
}
/*
* \ dC
*
* Describes casts .
*/
bool
2011-08-04 18:22:26 +02:00
listCasts ( const char * pattern , bool verbose )
2002-12-12 22:02:25 +01:00
{
PQExpBufferData buf ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
2008-07-15 00:00:04 +02:00
static const bool translate_columns [ ] = { false , false , false , true } ;
2002-12-12 22:02:25 +01:00
initPQExpBuffer ( & buf ) ;
2009-06-11 16:49:15 +02:00
2007-12-12 22:41:47 +01:00
/*
2008-11-06 16:18:36 +01:00
* We need a left join to pg_proc for binary casts ; the others are just
* paranoia . Also note that we don ' t attempt to localize ' ( binary
* coercible ) ' , because there ' s too much risk of gettext translating a
* function name that happens to match some string in the PO database .
2007-12-12 22:41:47 +01:00
*/
2002-12-12 22:02:25 +01:00
printfPQExpBuffer ( & buf ,
2005-10-15 04:49:52 +02:00
" SELECT pg_catalog.format_type(castsource, NULL) AS \" %s \" , \n "
" pg_catalog.format_type(casttarget, NULL) AS \" %s \" , \n "
2009-06-11 16:49:15 +02:00
" CASE WHEN castfunc = 0 THEN '(binary coercible)' \n "
2002-12-12 22:02:25 +01:00
" ELSE p.proname \n "
" END as \" %s \" , \n "
" CASE WHEN c.castcontext = 'e' THEN '%s' \n "
" WHEN c.castcontext = 'a' THEN '%s' \n "
" ELSE '%s' \n "
2011-08-04 18:22:26 +02:00
" END as \" %s \" " ,
gettext_noop ( " Source type " ) ,
gettext_noop ( " Target type " ) ,
gettext_noop ( " Function " ) ,
gettext_noop ( " no " ) ,
gettext_noop ( " in assignment " ) ,
gettext_noop ( " yes " ) ,
gettext_noop ( " Implicit? " ) ) ;
if ( verbose )
appendPQExpBuffer ( & buf ,
" , \n d.description AS \" %s \" \n " ,
gettext_noop ( " Description " ) ) ;
appendPQExpBuffer ( & buf ,
2005-10-15 04:49:52 +02:00
" FROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p \n "
2003-01-07 21:56:07 +01:00
" ON c.castfunc = p.oid \n "
2008-11-06 16:18:36 +01:00
" LEFT JOIN pg_catalog.pg_type ts \n "
" ON c.castsource = ts.oid \n "
" LEFT JOIN pg_catalog.pg_namespace ns \n "
" ON ns.oid = ts.typnamespace \n "
" LEFT JOIN pg_catalog.pg_type tt \n "
" ON c.casttarget = tt.oid \n "
" LEFT JOIN pg_catalog.pg_namespace nt \n "
2011-08-04 18:22:26 +02:00
" ON nt.oid = tt.typnamespace \n " ) ;
if ( verbose )
appendPQExpBuffer ( & buf ,
" LEFT JOIN pg_catalog.pg_description d \n "
" ON d.classoid = c.tableoid AND d.objoid = "
" c.oid AND d.objsubid = 0 \n " ) ;
appendPQExpBuffer ( & buf , " WHERE ( (true " ) ;
2002-12-12 22:02:25 +01:00
2008-11-06 16:18:36 +01:00
/*
* Match name pattern against either internal or external name of either
* castsource or casttarget
*/
processSQLNamePattern ( pset . db , & buf , pattern , true , false ,
" ns.nspname " , " ts.typname " ,
" pg_catalog.format_type(ts.oid, NULL) " ,
" pg_catalog.pg_type_is_visible(ts.oid) " ) ;
appendPQExpBuffer ( & buf , " ) OR (true " ) ;
processSQLNamePattern ( pset . db , & buf , pattern , true , false ,
" nt.nspname " , " tt.typname " ,
" pg_catalog.format_type(tt.oid, NULL) " ,
" pg_catalog.pg_type_is_visible(tt.oid) " ) ;
2011-08-04 18:22:26 +02:00
appendPQExpBuffer ( & buf , " ) ) \n ORDER BY 1, 2; " ) ;
2008-11-06 16:18:36 +01:00
2002-12-12 22:02:25 +01:00
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
myopt . title = _ ( " List of casts " ) ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
myopt . translate_columns = translate_columns ;
2002-12-12 22:02:25 +01:00
2005-06-14 04:57:45 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
2002-12-12 22:02:25 +01:00
PQclear ( res ) ;
return true ;
}
2011-02-12 14:54:13 +01:00
/*
* \ dO
*
2011-04-09 20:08:41 +02:00
* Describes collations .
2011-02-12 14:54:13 +01:00
*/
bool
listCollations ( const char * pattern , bool verbose , bool showSystem )
{
PQExpBufferData buf ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
static const bool translate_columns [ ] = { false , false , false , false , false } ;
2012-05-10 09:11:38 +02:00
if ( pset . sversion < 90100 )
{
fprintf ( stderr , _ ( " The server (version %d.%d) does not support collations. \n " ) ,
pset . sversion / 10000 , ( pset . sversion / 100 ) % 100 ) ;
return true ;
}
2011-02-12 14:54:13 +01:00
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
" SELECT n.nspname AS \" %s \" , \n "
" c.collname AS \" %s \" , \n "
" c.collcollate AS \" %s \" , \n "
" c.collctype AS \" %s \" " ,
gettext_noop ( " Schema " ) ,
gettext_noop ( " Name " ) ,
gettext_noop ( " Collate " ) ,
gettext_noop ( " Ctype " ) ) ;
if ( verbose )
appendPQExpBuffer ( & buf ,
2011-04-10 17:42:00 +02:00
" , \n pg_catalog.obj_description(c.oid, 'pg_collation') AS \" %s \" " ,
2011-02-12 14:54:13 +01:00
gettext_noop ( " Description " ) ) ;
appendPQExpBuffer ( & buf ,
2011-04-10 17:42:00 +02:00
" \n FROM pg_catalog.pg_collation c, pg_catalog.pg_namespace n \n "
2011-02-12 14:54:13 +01:00
" WHERE n.oid = c.collnamespace \n " ) ;
if ( ! showSystem & & ! pattern )
appendPQExpBuffer ( & buf , " AND n.nspname <> 'pg_catalog' \n "
" AND n.nspname <> 'information_schema' \n " ) ;
2011-04-09 20:08:41 +02:00
/*
* Hide collations that aren ' t usable in the current database ' s encoding .
* If you think to change this , note that pg_collation_is_visible rejects
* unusable collations , so you will need to hack name pattern processing
* somehow to avoid inconsistent behavior .
*/
appendPQExpBuffer ( & buf , " AND c.collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding())) \n " ) ;
2011-02-12 14:54:13 +01:00
processSQLNamePattern ( pset . db , & buf , pattern , true , false ,
" n.nspname " , " c.collname " , NULL ,
" pg_catalog.pg_collation_is_visible(c.oid) " ) ;
appendPQExpBuffer ( & buf , " ORDER BY 1, 2; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
myopt . title = _ ( " List of collations " ) ;
myopt . translate_header = true ;
myopt . translate_columns = translate_columns ;
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
PQclear ( res ) ;
return true ;
}
2003-01-07 21:56:07 +01:00
/*
* \ dn
*
* Describes schemas ( namespaces )
*/
bool
2010-11-07 02:41:14 +01:00
listSchemas ( const char * pattern , bool verbose , bool showSystem )
2003-01-07 21:56:07 +01:00
{
PQExpBufferData buf ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
2004-08-29 07:07:03 +02:00
" SELECT n.nspname AS \" %s \" , \n "
2008-07-03 05:37:17 +02:00
" pg_catalog.pg_get_userbyid(n.nspowner) AS \" %s \" " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Name " ) ,
gettext_noop ( " Owner " ) ) ;
2004-08-29 07:07:03 +02:00
2004-07-13 18:48:16 +02:00
if ( verbose )
2008-12-31 19:07:47 +01:00
{
appendPQExpBuffer ( & buf , " , \n " ) ;
printACLColumn ( & buf , " n.nspacl " ) ;
2004-07-13 18:48:16 +02:00
appendPQExpBuffer ( & buf ,
2009-06-11 16:49:15 +02:00
" , \n pg_catalog.obj_description(n.oid, 'pg_namespace') AS \" %s \" " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Description " ) ) ;
2008-12-31 19:07:47 +01:00
}
2004-08-29 07:07:03 +02:00
2004-07-13 18:48:16 +02:00
appendPQExpBuffer ( & buf ,
2010-11-07 02:41:14 +01:00
" \n FROM pg_catalog.pg_namespace n \n " ) ;
2004-07-13 18:48:16 +02:00
2010-11-07 02:41:14 +01:00
if ( ! showSystem & & ! pattern )
appendPQExpBuffer ( & buf ,
2011-04-10 17:42:00 +02:00
" WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema' \n " ) ;
2010-11-07 02:41:14 +01:00
processSQLNamePattern ( pset . db , & buf , pattern ,
! showSystem & & ! pattern , false ,
2006-10-10 01:30:33 +02:00
NULL , " n.nspname " , NULL ,
NULL ) ;
2003-01-07 21:56:07 +01:00
appendPQExpBuffer ( & buf , " ORDER BY 1; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
myopt . title = _ ( " List of schemas " ) ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
2003-01-07 21:56:07 +01:00
2005-06-14 04:57:45 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
2003-01-07 21:56:07 +01:00
PQclear ( res ) ;
return true ;
}
2007-08-21 03:11:32 +02:00
/*
* \ dFp
* list text search parsers
*/
bool
listTSParsers ( const char * pattern , bool verbose )
{
PQExpBufferData buf ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
2008-07-03 05:37:17 +02:00
if ( pset . sversion < 80300 )
{
fprintf ( stderr , _ ( " The server (version %d.%d) does not support full text search. \n " ) ,
pset . sversion / 10000 , ( pset . sversion / 100 ) % 100 ) ;
return true ;
}
2007-08-21 03:11:32 +02:00
if ( verbose )
return listTSParsersVerbose ( pattern ) ;
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
" SELECT \n "
" n.nspname as \" %s \" , \n "
" p.prsname as \" %s \" , \n "
" pg_catalog.obj_description(p.oid, 'pg_ts_parser') as \" %s \" \n "
" FROM pg_catalog.pg_ts_parser p \n "
2007-11-15 22:14:46 +01:00
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace \n " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Schema " ) ,
gettext_noop ( " Name " ) ,
gettext_noop ( " Description " )
2007-08-21 03:11:32 +02:00
) ;
processSQLNamePattern ( pset . db , & buf , pattern , false , false ,
" n.nspname " , " p.prsname " , NULL ,
" pg_catalog.pg_ts_parser_is_visible(p.oid) " ) ;
appendPQExpBuffer ( & buf , " ORDER BY 1, 2; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
myopt . title = _ ( " List of text search parsers " ) ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
2007-08-21 03:11:32 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
PQclear ( res ) ;
return true ;
}
/*
* full description of parsers
*/
static bool
listTSParsersVerbose ( const char * pattern )
{
PQExpBufferData buf ;
PGresult * res ;
int i ;
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
" SELECT p.oid, \n "
" n.nspname, \n "
" p.prsname \n "
" FROM pg_catalog.pg_ts_parser p \n "
2007-11-15 22:14:46 +01:00
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace \n "
2007-08-21 03:11:32 +02:00
) ;
processSQLNamePattern ( pset . db , & buf , pattern , false , false ,
" n.nspname " , " p.prsname " , NULL ,
" pg_catalog.pg_ts_parser_is_visible(p.oid) " ) ;
appendPQExpBuffer ( & buf , " ORDER BY 1, 2; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
if ( PQntuples ( res ) = = 0 )
{
if ( ! pset . quiet )
fprintf ( stderr , _ ( " Did not find any text search parser named \" %s \" . \n " ) ,
pattern ) ;
PQclear ( res ) ;
return false ;
}
for ( i = 0 ; i < PQntuples ( res ) ; i + + )
{
const char * oid ;
const char * nspname = NULL ;
const char * prsname ;
oid = PQgetvalue ( res , i , 0 ) ;
if ( ! PQgetisnull ( res , i , 1 ) )
nspname = PQgetvalue ( res , i , 1 ) ;
prsname = PQgetvalue ( res , i , 2 ) ;
if ( ! describeOneTSParser ( oid , nspname , prsname ) )
{
PQclear ( res ) ;
return false ;
}
if ( cancel_pressed )
{
PQclear ( res ) ;
return false ;
}
}
PQclear ( res ) ;
return true ;
}
static bool
describeOneTSParser ( const char * oid , const char * nspname , const char * prsname )
{
PQExpBufferData buf ;
PGresult * res ;
char title [ 1024 ] ;
printQueryOpt myopt = pset . popt ;
2008-07-15 00:00:04 +02:00
static const bool translate_columns [ ] = { true , false , false } ;
2007-08-21 03:11:32 +02:00
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
" SELECT '%s' AS \" %s \" , \n "
" p.prsstart::pg_catalog.regproc AS \" %s \" , \n "
2007-11-15 22:14:46 +01:00
" pg_catalog.obj_description(p.prsstart, 'pg_proc') as \" %s \" \n "
2007-08-21 03:11:32 +02:00
" FROM pg_catalog.pg_ts_parser p \n "
" WHERE p.oid = '%s' \n "
" UNION ALL \n "
" SELECT '%s', \n "
" p.prstoken::pg_catalog.regproc, \n "
2007-11-15 22:14:46 +01:00
" pg_catalog.obj_description(p.prstoken, 'pg_proc') \n "
2007-08-21 03:11:32 +02:00
" FROM pg_catalog.pg_ts_parser p \n "
" WHERE p.oid = '%s' \n "
" UNION ALL \n "
" SELECT '%s', \n "
" p.prsend::pg_catalog.regproc, \n "
" pg_catalog.obj_description(p.prsend, 'pg_proc') \n "
" FROM pg_catalog.pg_ts_parser p \n "
" WHERE p.oid = '%s' \n "
" UNION ALL \n "
" SELECT '%s', \n "
" p.prsheadline::pg_catalog.regproc, \n "
2007-11-15 22:14:46 +01:00
" pg_catalog.obj_description(p.prsheadline, 'pg_proc') \n "
2007-08-21 03:11:32 +02:00
" FROM pg_catalog.pg_ts_parser p \n "
" WHERE p.oid = '%s' \n "
" UNION ALL \n "
" SELECT '%s', \n "
" p.prslextype::pg_catalog.regproc, \n "
2007-11-15 22:14:46 +01:00
" pg_catalog.obj_description(p.prslextype, 'pg_proc') \n "
2007-08-21 03:11:32 +02:00
" FROM pg_catalog.pg_ts_parser p \n "
2011-07-06 16:11:20 +02:00
" WHERE p.oid = '%s'; " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Start parse " ) ,
gettext_noop ( " Method " ) ,
gettext_noop ( " Function " ) ,
gettext_noop ( " Description " ) ,
2007-08-21 03:11:32 +02:00
oid ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Get next token " ) ,
oid ,
gettext_noop ( " End parse " ) ,
oid ,
gettext_noop ( " Get headline " ) ,
oid ,
gettext_noop ( " Get token types " ) ,
oid ) ;
2007-08-21 03:11:32 +02:00
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
if ( nspname )
sprintf ( title , _ ( " Text search parser \" %s.%s \" " ) , nspname , prsname ) ;
else
sprintf ( title , _ ( " Text search parser \" %s \" " ) , prsname ) ;
myopt . title = title ;
myopt . footers = NULL ;
2012-05-01 22:03:45 +02:00
myopt . topt . default_footer = false ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
myopt . translate_columns = translate_columns ;
2007-08-21 03:11:32 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
PQclear ( res ) ;
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
" SELECT t.alias as \" %s \" , \n "
" t.description as \" %s \" \n "
2007-11-15 22:14:46 +01:00
" FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t \n "
2007-08-21 03:11:32 +02:00
" ORDER BY 1; " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Token name " ) ,
gettext_noop ( " Description " ) ,
2007-08-21 03:11:32 +02:00
oid ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
if ( nspname )
sprintf ( title , _ ( " Token types for parser \" %s.%s \" " ) , nspname , prsname ) ;
else
sprintf ( title , _ ( " Token types for parser \" %s \" " ) , prsname ) ;
myopt . title = title ;
myopt . footers = NULL ;
2012-05-01 22:03:45 +02:00
myopt . topt . default_footer = true ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
myopt . translate_columns = NULL ;
2007-08-21 03:11:32 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
PQclear ( res ) ;
return true ;
}
/*
* \ dFd
* list text search dictionaries
*/
bool
listTSDictionaries ( const char * pattern , bool verbose )
{
PQExpBufferData buf ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
2008-07-03 05:37:17 +02:00
if ( pset . sversion < 80300 )
{
fprintf ( stderr , _ ( " The server (version %d.%d) does not support full text search. \n " ) ,
pset . sversion / 10000 , ( pset . sversion / 100 ) % 100 ) ;
return true ;
}
2007-08-21 03:11:32 +02:00
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
" SELECT \n "
" n.nspname as \" %s \" , \n "
" d.dictname as \" %s \" , \n " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Schema " ) ,
gettext_noop ( " Name " ) ) ;
2007-08-21 03:11:32 +02:00
if ( verbose )
{
appendPQExpBuffer ( & buf ,
" ( SELECT COALESCE(nt.nspname, '(null)')::pg_catalog.text || '.' || t.tmplname FROM \n "
" pg_catalog.pg_ts_template t \n "
" LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace \n "
" WHERE d.dicttemplate = t.oid ) AS \" %s \" , \n "
" d.dictinitoption as \" %s \" , \n " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Template " ) ,
gettext_noop ( " Init options " ) ) ;
2007-08-21 03:11:32 +02:00
}
appendPQExpBuffer ( & buf ,
" pg_catalog.obj_description(d.oid, 'pg_ts_dict') as \" %s \" \n " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Description " ) ) ;
2007-08-21 03:11:32 +02:00
appendPQExpBuffer ( & buf , " FROM pg_catalog.pg_ts_dict d \n "
2007-11-15 22:14:46 +01:00
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace \n " ) ;
2007-08-21 03:11:32 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , false , false ,
" n.nspname " , " d.dictname " , NULL ,
" pg_catalog.pg_ts_dict_is_visible(d.oid) " ) ;
appendPQExpBuffer ( & buf , " ORDER BY 1, 2; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
myopt . title = _ ( " List of text search dictionaries " ) ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
2007-08-21 03:11:32 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
PQclear ( res ) ;
return true ;
}
/*
* \ dFt
* list text search templates
*/
bool
listTSTemplates ( const char * pattern , bool verbose )
{
PQExpBufferData buf ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
2008-07-03 05:37:17 +02:00
if ( pset . sversion < 80300 )
{
fprintf ( stderr , _ ( " The server (version %d.%d) does not support full text search. \n " ) ,
pset . sversion / 10000 , ( pset . sversion / 100 ) % 100 ) ;
return true ;
}
2007-08-21 03:11:32 +02:00
initPQExpBuffer ( & buf ) ;
2007-08-22 04:25:34 +02:00
if ( verbose )
printfPQExpBuffer ( & buf ,
" SELECT \n "
" n.nspname AS \" %s \" , \n "
" t.tmplname AS \" %s \" , \n "
" t.tmplinit::pg_catalog.regproc AS \" %s \" , \n "
" t.tmpllexize::pg_catalog.regproc AS \" %s \" , \n "
2007-11-15 22:14:46 +01:00
" pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \" %s \" \n " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Schema " ) ,
gettext_noop ( " Name " ) ,
gettext_noop ( " Init " ) ,
gettext_noop ( " Lexize " ) ,
gettext_noop ( " Description " ) ) ;
2007-08-22 04:25:34 +02:00
else
printfPQExpBuffer ( & buf ,
" SELECT \n "
" n.nspname AS \" %s \" , \n "
" t.tmplname AS \" %s \" , \n "
2007-11-15 22:14:46 +01:00
" pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \" %s \" \n " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Schema " ) ,
gettext_noop ( " Name " ) ,
gettext_noop ( " Description " ) ) ;
2007-08-21 03:11:32 +02:00
appendPQExpBuffer ( & buf , " FROM pg_catalog.pg_ts_template t \n "
2007-11-15 22:14:46 +01:00
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace \n " ) ;
2007-08-21 03:11:32 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , false , false ,
" n.nspname " , " t.tmplname " , NULL ,
" pg_catalog.pg_ts_template_is_visible(t.oid) " ) ;
appendPQExpBuffer ( & buf , " ORDER BY 1, 2; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
myopt . title = _ ( " List of text search templates " ) ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
2007-08-21 03:11:32 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
PQclear ( res ) ;
return true ;
}
/*
* \ dF
* list text search configurations
*/
bool
listTSConfigs ( const char * pattern , bool verbose )
{
PQExpBufferData buf ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
2008-07-03 05:37:17 +02:00
if ( pset . sversion < 80300 )
{
fprintf ( stderr , _ ( " The server (version %d.%d) does not support full text search. \n " ) ,
pset . sversion / 10000 , ( pset . sversion / 100 ) % 100 ) ;
return true ;
}
2007-08-21 03:11:32 +02:00
if ( verbose )
return listTSConfigsVerbose ( pattern ) ;
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
" SELECT \n "
" n.nspname as \" %s \" , \n "
" c.cfgname as \" %s \" , \n "
" pg_catalog.obj_description(c.oid, 'pg_ts_config') as \" %s \" \n "
" FROM pg_catalog.pg_ts_config c \n "
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace \n " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Schema " ) ,
gettext_noop ( " Name " ) ,
gettext_noop ( " Description " )
2007-08-21 03:11:32 +02:00
) ;
processSQLNamePattern ( pset . db , & buf , pattern , false , false ,
" n.nspname " , " c.cfgname " , NULL ,
" pg_catalog.pg_ts_config_is_visible(c.oid) " ) ;
appendPQExpBuffer ( & buf , " ORDER BY 1, 2; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
myopt . title = _ ( " List of text search configurations " ) ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
2007-08-21 03:11:32 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
PQclear ( res ) ;
return true ;
}
static bool
listTSConfigsVerbose ( const char * pattern )
{
PQExpBufferData buf ;
PGresult * res ;
int i ;
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
" SELECT c.oid, c.cfgname, \n "
" n.nspname, \n "
" p.prsname, \n "
" np.nspname as pnspname \n "
" FROM pg_catalog.pg_ts_config c \n "
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace, \n "
" pg_catalog.pg_ts_parser p \n "
2007-11-15 22:14:46 +01:00
" LEFT JOIN pg_catalog.pg_namespace np ON np.oid = p.prsnamespace \n "
2007-08-21 03:11:32 +02:00
" WHERE p.oid = c.cfgparser \n "
) ;
processSQLNamePattern ( pset . db , & buf , pattern , true , false ,
" n.nspname " , " c.cfgname " , NULL ,
" pg_catalog.pg_ts_config_is_visible(c.oid) " ) ;
appendPQExpBuffer ( & buf , " ORDER BY 3, 2; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
if ( PQntuples ( res ) = = 0 )
{
if ( ! pset . quiet )
fprintf ( stderr , _ ( " Did not find any text search configuration named \" %s \" . \n " ) ,
pattern ) ;
PQclear ( res ) ;
return false ;
}
for ( i = 0 ; i < PQntuples ( res ) ; i + + )
{
const char * oid ;
const char * cfgname ;
const char * nspname = NULL ;
const char * prsname ;
const char * pnspname = NULL ;
oid = PQgetvalue ( res , i , 0 ) ;
cfgname = PQgetvalue ( res , i , 1 ) ;
if ( ! PQgetisnull ( res , i , 2 ) )
nspname = PQgetvalue ( res , i , 2 ) ;
prsname = PQgetvalue ( res , i , 3 ) ;
if ( ! PQgetisnull ( res , i , 4 ) )
pnspname = PQgetvalue ( res , i , 4 ) ;
if ( ! describeOneTSConfig ( oid , nspname , cfgname , pnspname , prsname ) )
{
PQclear ( res ) ;
return false ;
}
if ( cancel_pressed )
{
PQclear ( res ) ;
return false ;
}
}
PQclear ( res ) ;
return true ;
}
static bool
describeOneTSConfig ( const char * oid , const char * nspname , const char * cfgname ,
const char * pnspname , const char * prsname )
{
PQExpBufferData buf ,
title ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
" SELECT \n "
" ( SELECT t.alias FROM \n "
" pg_catalog.ts_token_type(c.cfgparser) AS t \n "
" WHERE t.tokid = m.maptokentype ) AS \" %s \" , \n "
" pg_catalog.btrim( \n "
2007-11-15 22:14:46 +01:00
" ARRAY( SELECT mm.mapdict::pg_catalog.regdictionary \n "
2007-08-21 03:11:32 +02:00
" FROM pg_catalog.pg_ts_config_map AS mm \n "
" WHERE mm.mapcfg = m.mapcfg AND mm.maptokentype = m.maptokentype \n "
" ORDER BY mapcfg, maptokentype, mapseqno \n "
" ) :: pg_catalog.text , \n "
" '{}') AS \" %s \" \n "
2007-11-15 22:14:46 +01:00
" FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m \n "
2007-08-21 03:11:32 +02:00
" WHERE c.oid = '%s' AND m.mapcfg = c.oid \n "
" GROUP BY m.mapcfg, m.maptokentype, c.cfgparser \n "
2011-07-06 16:11:20 +02:00
" ORDER BY 1; " ,
2007-12-12 22:41:47 +01:00
gettext_noop ( " Token " ) ,
gettext_noop ( " Dictionaries " ) ,
2007-08-21 03:11:32 +02:00
oid ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
initPQExpBuffer ( & title ) ;
if ( nspname )
2007-12-12 22:41:47 +01:00
appendPQExpBuffer ( & title , _ ( " Text search configuration \" %s.%s \" " ) ,
nspname , cfgname ) ;
2007-08-21 03:11:32 +02:00
else
2007-12-12 22:41:47 +01:00
appendPQExpBuffer ( & title , _ ( " Text search configuration \" %s \" " ) ,
cfgname ) ;
2007-08-21 03:11:32 +02:00
if ( pnspname )
2007-12-12 22:41:47 +01:00
appendPQExpBuffer ( & title , _ ( " \n Parser: \" %s.%s \" " ) ,
pnspname , prsname ) ;
2007-08-21 03:11:32 +02:00
else
2007-12-12 22:41:47 +01:00
appendPQExpBuffer ( & title , _ ( " \n Parser: \" %s \" " ) ,
prsname ) ;
2007-08-21 03:11:32 +02:00
myopt . nullPrint = NULL ;
myopt . title = title . data ;
myopt . footers = NULL ;
2012-05-01 22:03:45 +02:00
myopt . topt . default_footer = false ;
2008-07-15 00:00:04 +02:00
myopt . translate_header = true ;
2007-08-21 03:11:32 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
termPQExpBuffer ( & title ) ;
PQclear ( res ) ;
return true ;
}
2008-12-19 17:25:19 +01:00
/*
* \ dew
*
* Describes foreign - data wrappers
*/
bool
listForeignDataWrappers ( const char * pattern , bool verbose )
{
PQExpBufferData buf ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
2008-12-31 19:33:03 +01:00
if ( pset . sversion < 80400 )
{
fprintf ( stderr , _ ( " The server (version %d.%d) does not support foreign-data wrappers. \n " ) ,
pset . sversion / 10000 , ( pset . sversion / 100 ) % 100 ) ;
return true ;
}
2008-12-19 17:25:19 +01:00
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
2011-08-08 22:29:57 +02:00
" SELECT fdw.fdwname AS \" %s \" , \n "
2012-06-10 21:20:04 +02:00
" pg_catalog.pg_get_userbyid(fdw.fdwowner) AS \" %s \" , \n " ,
2008-12-19 17:25:19 +01:00
gettext_noop ( " Name " ) ,
2011-02-19 06:06:18 +01:00
gettext_noop ( " Owner " ) ) ;
if ( pset . sversion > = 90100 )
appendPQExpBuffer ( & buf ,
2011-08-08 22:29:57 +02:00
" fdw.fdwhandler::pg_catalog.regproc AS \" %s \" , \n " ,
2011-02-19 06:06:18 +01:00
gettext_noop ( " Handler " ) ) ;
appendPQExpBuffer ( & buf ,
2011-08-08 22:29:57 +02:00
" fdw.fdwvalidator::pg_catalog.regproc AS \" %s \" " ,
2009-02-24 11:06:36 +01:00
gettext_noop ( " Validator " ) ) ;
2008-12-19 17:25:19 +01:00
if ( verbose )
2008-12-31 19:07:47 +01:00
{
appendPQExpBuffer ( & buf , " , \n " ) ;
printACLColumn ( & buf , " fdwacl " ) ;
2008-12-19 17:25:19 +01:00
appendPQExpBuffer ( & buf ,
2011-08-25 18:47:30 +02:00
" , \n CASE WHEN fdwoptions IS NULL THEN '' ELSE "
" '(' || array_to_string(ARRAY(SELECT "
" quote_ident(option_name) || ' ' || "
" quote_literal(option_value) FROM "
" pg_options_to_table(fdwoptions)), ', ') || ')' "
" END AS \" %s \" " ,
2011-08-11 17:45:47 +02:00
gettext_noop ( " FDW Options " ) ) ;
2011-08-08 22:29:57 +02:00
if ( pset . sversion > = 90100 )
appendPQExpBuffer ( & buf ,
" , \n d.description AS \" %s \" " ,
gettext_noop ( " Description " ) ) ;
2008-12-31 19:07:47 +01:00
}
2008-12-19 17:25:19 +01:00
2011-08-08 22:29:57 +02:00
appendPQExpBuffer ( & buf , " \n FROM pg_catalog.pg_foreign_data_wrapper fdw \n " ) ;
if ( verbose & & pset . sversion > = 90100 )
appendPQExpBuffer ( & buf ,
" LEFT JOIN pg_catalog.pg_description d \n "
" ON d.classoid = fdw.tableoid "
" AND d.objoid = fdw.oid AND d.objsubid = 0 \n " ) ;
2008-12-19 17:25:19 +01:00
2008-12-31 19:07:47 +01:00
processSQLNamePattern ( pset . db , & buf , pattern , false , false ,
2008-12-19 17:25:19 +01:00
NULL , " fdwname " , NULL , NULL ) ;
appendPQExpBuffer ( & buf , " ORDER BY 1; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
myopt . title = _ ( " List of foreign-data wrappers " ) ;
myopt . translate_header = true ;
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
PQclear ( res ) ;
return true ;
}
/*
* \ des
*
2009-03-25 14:11:43 +01:00
* Describes foreign servers .
2008-12-19 17:25:19 +01:00
*/
bool
listForeignServers ( const char * pattern , bool verbose )
{
PQExpBufferData buf ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
2008-12-31 19:33:03 +01:00
if ( pset . sversion < 80400 )
{
2009-03-25 14:11:43 +01:00
fprintf ( stderr , _ ( " The server (version %d.%d) does not support foreign servers. \n " ) ,
2008-12-31 19:33:03 +01:00
pset . sversion / 10000 , ( pset . sversion / 100 ) % 100 ) ;
return true ;
}
2008-12-19 17:25:19 +01:00
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
" SELECT s.srvname AS \" %s \" , \n "
" pg_catalog.pg_get_userbyid(s.srvowner) AS \" %s \" , \n "
2008-12-31 19:07:47 +01:00
" f.fdwname AS \" %s \" " ,
2008-12-19 17:25:19 +01:00
gettext_noop ( " Name " ) ,
gettext_noop ( " Owner " ) ,
gettext_noop ( " Foreign-data wrapper " ) ) ;
if ( verbose )
2008-12-31 19:07:47 +01:00
{
appendPQExpBuffer ( & buf , " , \n " ) ;
printACLColumn ( & buf , " s.srvacl " ) ;
2008-12-19 17:25:19 +01:00
appendPQExpBuffer ( & buf ,
2008-12-31 19:07:47 +01:00
" , \n "
" s.srvtype AS \" %s \" , \n "
" s.srvversion AS \" %s \" , \n "
2011-08-25 18:47:30 +02:00
" CASE WHEN srvoptions IS NULL THEN '' ELSE "
" '(' || array_to_string(ARRAY(SELECT "
" quote_ident(option_name) || ' ' || "
" quote_literal(option_value) FROM "
" pg_options_to_table(srvoptions)), ', ') || ')' "
" END AS \" %s \" , \n "
2011-08-08 22:29:57 +02:00
" d.description AS \" %s \" " ,
2008-12-19 17:25:19 +01:00
gettext_noop ( " Type " ) ,
gettext_noop ( " Version " ) ,
2011-08-11 17:45:47 +02:00
gettext_noop ( " FDW Options " ) ,
2011-08-08 22:29:57 +02:00
gettext_noop ( " Description " ) ) ;
2008-12-31 19:07:47 +01:00
}
2008-12-19 17:25:19 +01:00
appendPQExpBuffer ( & buf ,
2009-06-11 16:49:15 +02:00
" \n FROM pg_catalog.pg_foreign_server s \n "
" JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid=s.srvfdw \n " ) ;
2008-12-19 17:25:19 +01:00
2011-08-08 22:29:57 +02:00
if ( verbose )
appendPQExpBuffer ( & buf ,
" LEFT JOIN pg_description d \n "
" ON d.classoid = s.tableoid AND d.objoid = s.oid "
" AND d.objsubid = 0 \n " ) ;
2008-12-31 19:07:47 +01:00
processSQLNamePattern ( pset . db , & buf , pattern , false , false ,
2008-12-19 17:25:19 +01:00
NULL , " s.srvname " , NULL , NULL ) ;
appendPQExpBuffer ( & buf , " ORDER BY 1; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
myopt . title = _ ( " List of foreign servers " ) ;
myopt . translate_header = true ;
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
PQclear ( res ) ;
return true ;
}
/*
* \ deu
*
* Describes user mappings .
*/
bool
listUserMappings ( const char * pattern , bool verbose )
{
PQExpBufferData buf ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
2008-12-31 19:33:03 +01:00
if ( pset . sversion < 80400 )
{
2009-03-25 14:11:43 +01:00
fprintf ( stderr , _ ( " The server (version %d.%d) does not support user mappings. \n " ) ,
2008-12-31 19:33:03 +01:00
pset . sversion / 10000 , ( pset . sversion / 100 ) % 100 ) ;
return true ;
}
2008-12-19 17:25:19 +01:00
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
" SELECT um.srvname AS \" %s \" , \n "
" um.usename AS \" %s \" " ,
gettext_noop ( " Server " ) ,
2009-03-25 14:11:43 +01:00
gettext_noop ( " User name " ) ) ;
2008-12-19 17:25:19 +01:00
if ( verbose )
appendPQExpBuffer ( & buf ,
2011-08-25 18:47:30 +02:00
" , \n CASE WHEN umoptions IS NULL THEN '' ELSE "
" '(' || array_to_string(ARRAY(SELECT "
" quote_ident(option_name) || ' ' || "
" quote_literal(option_value) FROM "
" pg_options_to_table(umoptions)), ', ') || ')' "
" END AS \" %s \" " ,
2011-08-11 17:45:47 +02:00
gettext_noop ( " FDW Options " ) ) ;
2008-12-19 17:25:19 +01:00
2008-12-31 19:07:47 +01:00
appendPQExpBuffer ( & buf , " \n FROM pg_catalog.pg_user_mappings um \n " ) ;
2008-12-19 17:25:19 +01:00
2008-12-31 19:07:47 +01:00
processSQLNamePattern ( pset . db , & buf , pattern , false , false ,
2008-12-19 17:25:19 +01:00
NULL , " um.srvname " , " um.usename " , NULL ) ;
appendPQExpBuffer ( & buf , " ORDER BY 1, 2; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
myopt . title = _ ( " List of user mappings " ) ;
myopt . translate_header = true ;
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
PQclear ( res ) ;
return true ;
}
2008-12-31 19:07:47 +01:00
2011-01-02 05:48:11 +01:00
/*
* \ det
*
* Describes foreign tables .
*/
bool
listForeignTables ( const char * pattern , bool verbose )
{
PQExpBufferData buf ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
if ( pset . sversion < 90100 )
{
2011-02-08 22:08:41 +01:00
fprintf ( stderr , _ ( " The server (version %d.%d) does not support foreign tables. \n " ) ,
2011-01-02 05:48:11 +01:00
pset . sversion / 10000 , ( pset . sversion / 100 ) % 100 ) ;
return true ;
}
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
" SELECT n.nspname AS \" %s \" , \n "
" c.relname AS \" %s \" , \n "
" s.srvname AS \" %s \" " ,
gettext_noop ( " Schema " ) ,
gettext_noop ( " Table " ) ,
gettext_noop ( " Server " ) ) ;
if ( verbose )
appendPQExpBuffer ( & buf ,
2011-08-25 18:47:30 +02:00
" , \n CASE WHEN ftoptions IS NULL THEN '' ELSE "
" '(' || array_to_string(ARRAY(SELECT "
" quote_ident(option_name) || ' ' || "
" quote_literal(option_value) FROM "
" pg_options_to_table(ftoptions)), ', ') || ')' "
" END AS \" %s \" , \n "
2011-08-08 22:29:57 +02:00
" d.description AS \" %s \" " ,
2011-08-11 17:45:47 +02:00
gettext_noop ( " FDW Options " ) ,
2011-08-08 22:29:57 +02:00
gettext_noop ( " Description " ) ) ;
2011-01-02 05:48:11 +01:00
2011-08-08 22:29:57 +02:00
appendPQExpBuffer ( & buf ,
" \n FROM pg_catalog.pg_foreign_table ft \n "
" INNER JOIN pg_catalog.pg_class c "
" ON c.oid = ft.ftrelid \n "
" INNER JOIN pg_catalog.pg_namespace n "
" ON n.oid = c.relnamespace \n "
" INNER JOIN pg_catalog.pg_foreign_server s "
" ON s.oid = ft.ftserver \n " ) ;
if ( verbose )
appendPQExpBuffer ( & buf ,
" LEFT JOIN pg_catalog.pg_description d \n "
" ON d.classoid = c.tableoid AND "
" d.objoid = c.oid AND d.objsubid = 0 \n " ) ;
2011-01-02 05:48:11 +01:00
2011-08-08 22:29:57 +02:00
processSQLNamePattern ( pset . db , & buf , pattern , false , false ,
2011-01-02 05:48:11 +01:00
NULL , " n.nspname " , " c.relname " , NULL ) ;
appendPQExpBuffer ( & buf , " ORDER BY 1, 2; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
myopt . title = _ ( " List of foreign tables " ) ;
myopt . translate_header = true ;
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
PQclear ( res ) ;
return true ;
}
2011-02-08 22:08:41 +01:00
/*
* \ dx
*
* Briefly describes installed extensions .
*/
bool
listExtensions ( const char * pattern )
{
PQExpBufferData buf ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
if ( pset . sversion < 90100 )
{
fprintf ( stderr , _ ( " The server (version %d.%d) does not support extensions. \n " ) ,
pset . sversion / 10000 , ( pset . sversion / 100 ) % 100 ) ;
return true ;
}
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
" SELECT e.extname AS \" %s \" , "
2011-04-10 17:42:00 +02:00
" e.extversion AS \" %s \" , n.nspname AS \" %s \" , c.description AS \" %s \" \n "
2011-02-08 22:08:41 +01:00
" FROM pg_catalog.pg_extension e "
2011-04-10 17:42:00 +02:00
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace "
" LEFT JOIN pg_catalog.pg_description c ON c.objoid = e.oid "
" AND c.classoid = 'pg_catalog.pg_extension'::pg_catalog.regclass \n " ,
2011-02-08 22:08:41 +01:00
gettext_noop ( " Name " ) ,
gettext_noop ( " Version " ) ,
gettext_noop ( " Schema " ) ,
gettext_noop ( " Description " ) ) ;
processSQLNamePattern ( pset . db , & buf , pattern ,
false , false ,
NULL , " e.extname " , NULL ,
NULL ) ;
appendPQExpBuffer ( & buf , " ORDER BY 1; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
myopt . title = _ ( " List of installed extensions " ) ;
myopt . translate_header = true ;
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
PQclear ( res ) ;
return true ;
}
/*
* \ dx +
*
* List contents of installed extensions .
*/
bool
listExtensionContents ( const char * pattern )
{
PQExpBufferData buf ;
PGresult * res ;
int i ;
if ( pset . sversion < 90100 )
{
fprintf ( stderr , _ ( " The server (version %d.%d) does not support extensions. \n " ) ,
pset . sversion / 10000 , ( pset . sversion / 100 ) % 100 ) ;
return true ;
}
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
" SELECT e.extname, e.oid \n "
" FROM pg_catalog.pg_extension e \n " ) ;
processSQLNamePattern ( pset . db , & buf , pattern ,
false , false ,
NULL , " e.extname " , NULL ,
NULL ) ;
appendPQExpBuffer ( & buf , " ORDER BY 1; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
if ( PQntuples ( res ) = = 0 )
{
if ( ! pset . quiet )
{
if ( pattern )
fprintf ( stderr , _ ( " Did not find any extension named \" %s \" . \n " ) ,
pattern ) ;
else
fprintf ( stderr , _ ( " Did not find any extensions. \n " ) ) ;
}
PQclear ( res ) ;
return false ;
}
for ( i = 0 ; i < PQntuples ( res ) ; i + + )
{
const char * extname ;
const char * oid ;
extname = PQgetvalue ( res , i , 0 ) ;
oid = PQgetvalue ( res , i , 1 ) ;
if ( ! listOneExtensionContents ( extname , oid ) )
{
PQclear ( res ) ;
return false ;
}
if ( cancel_pressed )
{
PQclear ( res ) ;
return false ;
}
}
PQclear ( res ) ;
return true ;
}
static bool
listOneExtensionContents ( const char * extname , const char * oid )
{
PQExpBufferData buf ;
PGresult * res ;
char title [ 1024 ] ;
printQueryOpt myopt = pset . popt ;
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
2011-04-10 17:42:00 +02:00
" SELECT pg_catalog.pg_describe_object(classid, objid, 0) AS \" %s \" \n "
2011-02-08 22:08:41 +01:00
" FROM pg_catalog.pg_depend \n "
" WHERE refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass AND refobjid = '%s' AND deptype = 'e' \n "
" ORDER BY 1; " ,
gettext_noop ( " Object Description " ) ,
oid ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
snprintf ( title , sizeof ( title ) , _ ( " Objects in extension \" %s \" " ) , extname ) ;
myopt . title = title ;
myopt . translate_header = true ;
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
PQclear ( res ) ;
return true ;
}
2008-12-31 19:07:47 +01:00
/*
* printACLColumn
*
* Helper function for consistently formatting ACL ( privilege ) columns .
2009-06-11 16:49:15 +02:00
* The proper targetlist entry is appended to buf . Note lack of any
2008-12-31 19:07:47 +01:00
* whitespace or comma decoration .
*/
static void
printACLColumn ( PQExpBuffer buf , const char * colname )
{
if ( pset . sversion > = 80100 )
appendPQExpBuffer ( buf ,
" pg_catalog.array_to_string(%s, E' \\ n') AS \" %s \" " ,
colname , gettext_noop ( " Access privileges " ) ) ;
else
appendPQExpBuffer ( buf ,
" pg_catalog.array_to_string(%s, ' \\ n') AS \" %s \" " ,
colname , gettext_noop ( " Access privileges " ) ) ;
}