2000-01-19 00:30:24 +01:00
/*
* psql - the PostgreSQL interactive terminal
*
2005-01-01 06:43:09 +01:00
* Copyright ( c ) 2000 - 2005 , PostgreSQL Global Development Group
2000-01-19 00:30:24 +01:00
*
2005-10-20 07:15:09 +02:00
* $ PostgreSQL : pgsql / src / bin / psql / describe . c , v 1.128 2005 / 10 / 20 05 : 15 : 09 tgl Exp $
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
# include "describe.h"
2000-02-16 14:15:26 +01:00
# include "libpq-fe.h"
2002-04-24 07:24:00 +02:00
# include "pqexpbuffer.h"
1999-11-04 22:56:02 +01:00
# include "common.h"
# include "settings.h"
# include "print.h"
# include "variables.h"
2002-08-10 05:56:24 +02:00
# include <ctype.h>
2003-07-27 05:32:26 +02:00
# ifdef WIN32
/*
* mbvalidate ( ) is used in function describeOneTableDetails ( ) to make sure
* all characters of the cells will be printed to the DOS console in a
* correct way
*/
# include "mbprint.h"
# endif
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 ) ;
2002-08-10 05:56:24 +02:00
static void processNamePattern ( PQExpBuffer buf , const char * pattern ,
2002-09-04 22:31:48 +02:00
bool have_where , bool force_escape ,
const char * schemavar , const char * namevar ,
const char * altnamevar , const char * visibilityrule ) ;
2002-08-10 05:56:24 +02:00
2005-10-15 04:49:52 +02:00
static bool add_tablespace_footer ( char relkind , Oid tablespace , char * * footers ,
int * count , PQExpBufferData buf , bool newline ) ;
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 .
*
2000-01-12 20:36:36 +01:00
* If you add something here , try to format the query 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
2002-08-10 05:56:24 +02:00
describeAggregates ( const char * pattern , bool verbose )
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 ) ;
1999-11-05 00:14:30 +01:00
/*
2005-10-15 04:49:52 +02:00
* There are two kinds of aggregates : ones that work on particular types
* and ones that work on all ( denoted by input type = " any " )
1999-11-05 00:14:30 +01: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 "
" p.proname AS \" %s \" , \n "
" CASE p.proargtypes[0] \n "
2005-10-15 04:49:52 +02:00
" WHEN 'pg_catalog. \" any \" '::pg_catalog.regtype \n "
2002-09-04 22:31:48 +02:00
" THEN CAST('%s' AS pg_catalog.text) \n "
2005-10-15 04:49:52 +02:00
" ELSE pg_catalog.format_type(p.proargtypes[0], NULL) \n "
2002-09-04 22:31:48 +02:00
" END AS \" %s \" , \n "
2005-10-15 04:49:52 +02: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 "
2005-10-15 04:49:52 +02: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 " ,
_ ( " Schema " ) , _ ( " Name " ) , _ ( " (all types) " ) ,
_ ( " Data type " ) , _ ( " 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
2002-08-10 05:56:24 +02:00
processNamePattern ( & 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
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 = _ ( " List of aggregate functions " ) ;
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
{
2004-10-12 23:54:45 +02:00
fprintf ( stderr , _ ( " The server version (%d) does not support tablespaces. \n " ) ,
2004-08-29 07:07:03 +02:00
pset . sversion ) ;
return true ;
2004-08-20 22:18:23 +02:00
}
2004-06-18 08:14:31 +02:00
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
" SELECT spcname AS \" %s \" , \n "
2005-10-15 04:49:52 +02:00
" pg_catalog.pg_get_userbyid(spcowner) AS \" %s \" , \n "
2004-07-15 05:56:06 +02:00
" spclocation AS \" %s \" " ,
2004-06-18 08:14:31 +02:00
_ ( " Name " ) , _ ( " Owner " ) , _ ( " Location " ) ) ;
2004-07-15 05:56:06 +02:00
if ( verbose )
appendPQExpBuffer ( & buf ,
2004-08-29 07:07:03 +02:00
" , \n spcacl as \" %s \" " ,
_ ( " Access privileges " ) ) ;
2004-07-15 05:56:06 +02:00
appendPQExpBuffer ( & buf ,
" \n FROM pg_catalog.pg_tablespace \n " ) ;
2004-06-18 08:14:31 +02:00
processNamePattern ( & buf , pattern , false , false ,
NULL , " spcname " , 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 tablespaces " ) ;
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
2002-08-10 05:56:24 +02:00
* Takes an optional regexp to select particular functions
1999-11-04 22:56:02 +01:00
*/
bool
2002-08-10 05:56:24 +02:00
describeFunctions ( const char * pattern , bool verbose )
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 ,
2004-09-10 06:10:53 +02:00
" SELECT n.nspname as \" %s \" , \n "
2003-08-04 02:43:34 +02:00
" p.proname as \" %s \" , \n "
2004-09-10 06:10:53 +02:00
" CASE WHEN p.proretset THEN 'setof ' ELSE '' END || \n "
2005-10-15 04:49:52 +02:00
" pg_catalog.format_type(p.prorettype, NULL) as \" %s \" , \n "
2004-09-10 06:10:53 +02:00
" pg_catalog.oidvectortypes(p.proargtypes) as \" %s \" " ,
2005-10-15 04:49:52 +02:00
_ ( " Schema " ) , _ ( " Name " ) , _ ( " Result data type " ) ,
2002-09-04 22:31:48 +02:00
_ ( " Argument data types " ) ) ;
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 ,
2005-08-14 21:20:45 +02:00
" , \n r.rolname 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 \" " ,
2002-09-04 22:31:48 +02:00
_ ( " Owner " ) , _ ( " Language " ) ,
_ ( " Source code " ) , _ ( " 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
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
" \n FROM pg_catalog.pg_proc p "
" \n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace \n " ) ;
2000-04-12 19:17:23 +02:00
else
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" \n FROM pg_catalog.pg_proc p "
2005-10-15 04:49:52 +02:00
" \n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace "
" \n LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang "
" \n LEFT JOIN pg_catalog.pg_roles r ON r.oid = p.proowner \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
2002-08-10 05:56:24 +02:00
/*
2005-10-15 04:49:52 +02:00
* we skip in / out funcs by excluding functions that take or return cstring
2002-08-10 05:56:24 +02:00
*/
appendPQExpBuffer ( & buf ,
2005-10-15 04:49:52 +02:00
" WHERE p.prorettype <> 'pg_catalog.cstring'::pg_catalog.regtype \n "
2005-04-01 07:30:38 +02:00
" AND (p.proargtypes[0] IS NULL \n "
" OR p.proargtypes[0] <> 'pg_catalog.cstring'::pg_catalog.regtype) \n "
2002-08-10 05:56:24 +02:00
" AND NOT p.proisagg \n " ) ;
processNamePattern ( & buf , pattern , true , false ,
" n.nspname " , " p.proname " , NULL ,
" pg_catalog.pg_function_is_visible(p.oid) " ) ;
2004-09-10 06:10:53 +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 functions " ) ;
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
2002-08-10 05:56:24 +02:00
describeTypes ( const char * pattern , bool verbose )
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 " ,
2002-09-04 22:31:48 +02:00
_ ( " Schema " ) , _ ( " 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 "
" END AS \" %s \" , \n " ,
_ ( " Internal name " ) , _ ( " Size " ) ) ;
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf ,
2005-10-15 04:49:52 +02:00
" pg_catalog.obj_description(t.oid, 'pg_type') as \" %s \" \n " ,
2002-09-04 22:31:48 +02:00
_ ( " 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
/*
2002-08-29 02:17:06 +02:00
* do not include array types ( start with underscore ) ; do not include
2005-10-15 04:49:52 +02:00
* 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 "
2002-09-04 22:31:48 +02:00
" WHERE c.oid = t.typrelid)) " ) ;
2002-08-15 18:36:08 +02:00
appendPQExpBuffer ( & buf , " AND t.typname !~ '^_' \n " ) ;
1999-11-05 00:14:30 +01:00
2002-08-10 05:56:24 +02:00
/* Match name pattern against either internal or external name */
processNamePattern ( & 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 " ) ;
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
2002-08-10 05:56:24 +02:00
describeOperators ( 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 ;
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 "
" 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 " ,
2002-09-04 22:31:48 +02:00
_ ( " Schema " ) , _ ( " Name " ) ,
_ ( " Left arg type " ) , _ ( " Right arg type " ) ,
_ ( " Result type " ) , _ ( " Description " ) ) ;
2002-08-10 05:56:24 +02:00
processNamePattern ( & buf , pattern , false , true ,
" 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 " ) ;
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 "
2005-08-14 21:20:45 +02:00
" r.rolname as \" %s \" " ,
2002-09-04 22:31:48 +02:00
_ ( " Name " ) , _ ( " Owner " ) ) ;
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf ,
2005-10-15 04:49:52 +02:00
" , \n pg_catalog.pg_encoding_to_char(d.encoding) as \" %s \" " ,
2002-09-04 22:31:48 +02:00
_ ( " Encoding " ) ) ;
2002-08-27 20:28:29 +02:00
if ( verbose )
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" , \n pg_catalog.obj_description(d.oid, 'pg_database') as \" %s \" " ,
_ ( " Description " ) ) ;
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf ,
2002-08-10 05:56:24 +02:00
" \n FROM pg_catalog.pg_database d "
2005-10-15 04:49:52 +02:00
" \n LEFT JOIN pg_catalog.pg_roles r ON d.datdba = r.oid \n "
2002-09-04 22:31:48 +02:00
" ORDER BY 1; " ) ;
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
1999-11-05 00:14:30 +01:00
myopt . nullPrint = NULL ;
2001-06-30 19:26:12 +02:00
myopt . title = _ ( " List of databases " ) ;
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
/*
* 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 ;
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 "
2004-06-18 08:14:31 +02:00
" CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'S' THEN '%s' END as \" %s \" , \n "
2002-09-04 22:31:48 +02:00
" c.relacl as \" %s \" \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-09-04 22:31:48 +02:00
" WHERE c.relkind IN ('r', 'v', 'S') \n " ,
2004-03-22 04:38:24 +01:00
_ ( " Schema " ) , _ ( " Name " ) , _ ( " table " ) , _ ( " view " ) , _ ( " sequence " ) , _ ( " Type " ) , _ ( " Access privileges " ) ) ;
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
*/
processNamePattern ( & 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 ;
2002-04-24 07:24:00 +02:00
printfPQExpBuffer ( & buf , _ ( " Access privileges for database \" %s \" " ) , PQdb ( pset . db ) ) ;
myopt . title = buf . data ;
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
}
/*
* Get object comments
*
* \ dd [ foo ]
*
* Note : This only lists things that actually have a description . For complete
* lists of things , there are other \ d ? commands .
*/
bool
2002-08-10 05:56:24 +02:00
objectDescription ( 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 ;
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 " ,
2005-10-15 04:49:52 +02:00
_ ( " Schema " ) , _ ( " Name " ) , _ ( " Object " ) , _ ( " Description " ) ) ;
2001-06-30 19:26:12 +02:00
2001-10-25 07:50:21 +02:00
/* Aggregate descriptions */
2002-08-10 05:56:24 +02:00
appendPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" SELECT p.oid as oid, p.tableoid as tableoid, \n "
" n.nspname as nspname, \n "
" CAST(p.proname AS pg_catalog.text) as name, "
" CAST('%s' AS pg_catalog.text) as object \n "
" FROM pg_catalog.pg_proc p \n "
2005-10-15 04:49:52 +02: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 " ,
_ ( " aggregate " ) ) ;
2002-08-10 05:56:24 +02:00
processNamePattern ( & buf , pattern , true , false ,
" n.nspname " , " p.proname " , NULL ,
" pg_catalog.pg_function_is_visible(p.oid) " ) ;
2001-06-30 19:26:12 +02:00
2001-10-25 07:50:21 +02:00
/* Function descriptions (except in/outs for datatypes) */
2002-08-10 05:56:24 +02:00
appendPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" UNION ALL \n "
" SELECT p.oid as oid, p.tableoid as tableoid, \n "
" n.nspname as nspname, \n "
" CAST(p.proname AS pg_catalog.text) as name, "
" CAST('%s' AS pg_catalog.text) as object \n "
" FROM pg_catalog.pg_proc p \n "
2005-10-15 04:49:52 +02:00
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace \n "
2002-09-04 22:31:48 +02:00
2005-10-15 04:49:52 +02:00
" WHERE p.prorettype <> 'pg_catalog.cstring'::pg_catalog.regtype \n "
2005-04-01 07:30:38 +02:00
" AND (p.proargtypes[0] IS NULL \n "
" OR p.proargtypes[0] <> 'pg_catalog.cstring'::pg_catalog.regtype) \n "
2002-09-04 22:31:48 +02:00
" AND NOT p.proisagg \n " ,
_ ( " function " ) ) ;
2002-08-10 05:56:24 +02:00
processNamePattern ( & buf , pattern , true , false ,
" n.nspname " , " p.proname " , NULL ,
" pg_catalog.pg_function_is_visible(p.oid) " ) ;
2001-06-30 19:26:12 +02:00
2002-05-13 19:45:30 +02:00
/* Operator descriptions (only if operator has its own comment) */
2002-08-10 05:56:24 +02:00
appendPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" UNION ALL \n "
" SELECT o.oid as oid, o.tableoid as tableoid, \n "
" n.nspname as nspname, \n "
" CAST(o.oprname AS pg_catalog.text) as name, "
" CAST('%s' AS pg_catalog.text) as object \n "
" 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 " ,
2002-09-04 22:31:48 +02:00
_ ( " operator " ) ) ;
2002-08-10 05:56:24 +02:00
processNamePattern ( & buf , pattern , false , false ,
" n.nspname " , " o.oprname " , NULL ,
" pg_catalog.pg_operator_is_visible(o.oid) " ) ;
2001-06-30 19:26:12 +02:00
2001-10-25 07:50:21 +02:00
/* Type description */
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 "
" pg_catalog.format_type(t.oid, NULL) as name, "
" CAST('%s' AS pg_catalog.text) as object \n "
" 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-09-04 22:31:48 +02:00
_ ( " data type " ) ) ;
2002-08-10 05:56:24 +02:00
processNamePattern ( & buf , pattern , false , false ,
2005-10-15 04:49:52 +02:00
" n.nspname " , " pg_catalog.format_type(t.oid, NULL) " , NULL ,
2002-08-10 05:56:24 +02:00
" pg_catalog.pg_type_is_visible(t.oid) " ) ;
2001-06-30 19:26:12 +02:00
2001-10-25 07:50:21 +02:00
/* Relation (tables, views, indexes, sequences) descriptions */
2002-08-10 05:56:24 +02:00
appendPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" UNION ALL \n "
" SELECT c.oid as oid, c.tableoid as tableoid, \n "
" n.nspname as nspname, \n "
" CAST(c.relname AS pg_catalog.text) as name, \n "
" CAST( \n "
" CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' END "
" AS pg_catalog.text) as object \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-09-04 22:31:48 +02:00
" WHERE c.relkind IN ('r', 'v', 'i', 'S') \n " ,
_ ( " table " ) , _ ( " view " ) , _ ( " index " ) , _ ( " sequence " ) ) ;
2002-08-10 05:56:24 +02:00
processNamePattern ( & buf , pattern , true , false ,
" n.nspname " , " c.relname " , NULL ,
" pg_catalog.pg_table_is_visible(c.oid) " ) ;
2001-06-30 19:26:12 +02:00
2001-10-25 07:50:21 +02:00
/* Rule description (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 " ,
_ ( " rule " ) ) ;
2002-08-10 05:56:24 +02:00
/* XXX not sure what to do about visibility rule here? */
processNamePattern ( & 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
2001-10-25 07:50:21 +02:00
/* Trigger description */
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 " ,
2002-09-04 22:31:48 +02:00
_ ( " trigger " ) ) ;
2002-08-10 05:56:24 +02:00
/* XXX not sure what to do about visibility rule here? */
processNamePattern ( & buf , pattern , false , false ,
" n.nspname " , " t.tgname " , NULL ,
" pg_catalog.pg_table_is_visible(c.oid) " ) ;
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 " ) ;
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
describeTableDetails ( const char * pattern , bool verbose )
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
processNamePattern ( & buf , pattern , false , false ,
" n.nspname " , " c.relname " , NULL ,
" pg_catalog.pg_table_is_visible(c.oid) " ) ;
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
{
2002-08-10 05:56:24 +02:00
if ( ! QUIET ( ) )
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 ;
}
}
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 ;
1999-11-05 00:14:30 +01:00
int i ;
2002-09-04 22:31:48 +02:00
char * view_def = NULL ;
In the spirit of TODO item
* Add use of 'const' for varibles in source tree
(which is misspelled, btw.)
I went through the front-end libpq code and did so. This affects in
particular the various accessor functions (such as PQdb() and
PQgetvalue()) as well as, by necessity, the internal helpers they use.
I have been really thorough in that regard, perhaps some people will find
it annoying that things like
char * foo = PQgetvalue(res, 0, 0)
will generate a warning. On the other hand it _should_ generate one. This
is no real compatibility break, although a few clients will have to be
fixed to suppress warnings. (Which again would be in the spirit of the
above TODO.)
In addition I replaced some int's by size_t's and removed some warnings
(and generated some new ones -- grmpf!). Also I rewrote PQoidStatus (so it
actually honors the const!) and supplied a new function PQoidValue that
returns a proper Oid type. This is only front-end stuff, none of the
communicaton stuff was touched.
The psql patch also adds some new consts to honor the new libpq situation,
as well as fixes a fatal condition that resulted when using the -V
(--version) option and there is no database listening.
So, to summarize, the psql you should definitely put in (with or without
the libpq). If you think I went too far with the const-mania in libpq, let
me know and I'll make adjustments. If you approve it, I will also update
the docs.
-Peter
--
Peter Eisentraut Sernanders vaeg 10:115
1999-11-11 01:10:14 +01:00
const char * headers [ 5 ] ;
1999-11-05 00:14:30 +01:00
char * * cells = NULL ;
char * * footers = NULL ;
char * * ptr ;
2002-04-24 07:24:00 +02:00
PQExpBufferData title ;
2002-12-21 02:07:07 +01:00
PQExpBufferData tmpbuf ;
int cols = 0 ;
int numrows = 0 ;
2000-04-12 19:17:23 +02:00
struct
{
int16 checks ;
int16 triggers ;
2004-04-22 19:38:16 +02:00
char relkind ;
bool hasindex ;
2000-04-12 19:17:23 +02:00
bool hasrules ;
2004-08-29 07:07:03 +02:00
bool hasoids ;
2004-07-12 22:41:13 +02:00
Oid tablespace ;
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
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 */
2002-04-24 07:24:00 +02:00
printfPQExpBuffer ( & buf ,
2005-10-15 04:49:52 +02:00
" SELECT relhasindex, relkind, relchecks, reltriggers, relhasrules, \n "
2004-08-29 07:07:03 +02:00
" relhasoids %s \n "
2002-08-10 05:56:24 +02:00
" FROM pg_catalog.pg_class WHERE oid = '%s' " ,
2004-11-05 20:17:13 +01:00
pset . sversion > = 80000 ? " , reltablespace " : " " ,
2002-08-10 05:56:24 +02: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 )
{
2000-01-14 23:18:03 +01:00
if ( ! 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
}
2000-04-12 19:17:23 +02:00
/* FIXME: check for null pointers here? */
tableinfo . checks = atoi ( PQgetvalue ( res , 0 , 2 ) ) ;
tableinfo . triggers = atoi ( PQgetvalue ( res , 0 , 3 ) ) ;
2004-04-22 19:38:16 +02:00
tableinfo . relkind = * ( PQgetvalue ( res , 0 , 1 ) ) ;
tableinfo . hasindex = strcmp ( PQgetvalue ( res , 0 , 0 ) , " t " ) = = 0 ;
2000-04-12 19:17:23 +02:00
tableinfo . hasrules = strcmp ( PQgetvalue ( res , 0 , 4 ) , " t " ) = = 0 ;
2004-04-22 19:38:16 +02:00
tableinfo . hasoids = strcmp ( PQgetvalue ( res , 0 , 5 ) , " t " ) = = 0 ;
2004-11-05 20:17:13 +01:00
tableinfo . tablespace = ( pset . sversion > = 80000 ) ?
2004-08-29 07:07:03 +02:00
atooid ( PQgetvalue ( res , 0 , 6 ) ) : 0 ;
2000-04-12 19:17:23 +02:00
PQclear ( res ) ;
1999-11-05 00:14:30 +01:00
2001-06-30 19:26:12 +02:00
headers [ 0 ] = _ ( " Column " ) ;
headers [ 1 ] = _ ( " Type " ) ;
* 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
cols = 2 ;
1999-11-05 00:14:30 +01:00
2000-10-25 22:36:52 +02:00
if ( tableinfo . relkind = = ' r ' | | tableinfo . relkind = = ' v ' )
2000-04-12 19:17:23 +02:00
{
2002-12-21 02:07:07 +01:00
show_modifiers = true ;
2000-04-12 19:17:23 +02:00
cols + + ;
2001-06-30 19:26:12 +02:00
headers [ cols - 1 ] = _ ( " Modifiers " ) ;
2000-04-12 19:17:23 +02:00
}
1999-11-05 00:14:30 +01:00
2002-08-10 05:56:24 +02:00
if ( verbose )
1999-11-05 00:14:30 +01:00
{
2000-04-12 19:17:23 +02:00
cols + + ;
2001-06-30 19:26:12 +02:00
headers [ cols - 1 ] = _ ( " Description " ) ;
1999-11-05 00:14:30 +01:00
}
2000-04-12 19:17:23 +02:00
headers [ cols ] = NULL ;
* 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-03-05 03:42:56 +01:00
/* Get column info (index requires additional checks) */
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), "
" \n a.attnotnull, a.attnum " ) ;
2002-08-10 05:56:24 +02:00
if ( verbose )
appendPQExpBuffer ( & buf , " , pg_catalog.col_description(a.attrelid, a.attnum) " ) ;
appendPQExpBuffer ( & buf , " \n FROM pg_catalog.pg_attribute a " ) ;
2002-03-05 03:42:56 +01:00
if ( tableinfo . relkind = = ' i ' )
2002-08-10 05:56:24 +02:00
appendPQExpBuffer ( & buf , " , pg_catalog.pg_index i " ) ;
appendPQExpBuffer ( & buf , " \n WHERE a.attrelid = '%s' AND a.attnum > 0 AND NOT a.attisdropped " , oid ) ;
2002-03-05 03:42:56 +01:00
if ( tableinfo . relkind = = ' i ' )
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf , " AND a.attrelid = i.indexrelid " ) ;
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
/* Check if table is a view */
2002-08-10 05:56:24 +02:00
if ( tableinfo . relkind = = ' v ' )
2000-04-12 19:17:23 +02:00
{
PGresult * result ;
2003-08-09 03:21:54 +02:00
printfPQExpBuffer ( & buf , " SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true) " , 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
/* note: initialize all cells[] to NULL in case of error exit */
2004-01-25 04:07:22 +01:00
cells = pg_malloc_zero ( ( numrows * cols + 1 ) * sizeof ( * cells ) ) ;
* 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-12-21 02:07:07 +01:00
for ( i = 0 ; i < numrows ; i + + )
1999-11-05 00:14:30 +01:00
{
/* Name */
2003-07-27 05:32:26 +02:00
# ifdef WIN32
2003-09-07 05:43:57 +02:00
cells [ i * cols + 0 ] = mbvalidate ( PQgetvalue ( res , i , 0 ) , myopt . encoding ) ;
2003-07-27 05:32:26 +02:00
# else
2000-04-12 19:17:23 +02:00
cells [ i * cols + 0 ] = PQgetvalue ( res , i , 0 ) ; /* don't free this
* afterwards */
2003-07-27 05:32:26 +02:00
# endif
1999-11-05 00:14:30 +01:00
/* Type */
2003-07-27 05:32:26 +02:00
# ifdef WIN32
2003-09-07 05:43:57 +02:00
cells [ i * cols + 1 ] = mbvalidate ( PQgetvalue ( res , i , 1 ) , myopt . encoding ) ;
2003-07-27 05:32:26 +02:00
# else
2000-07-07 21:24:43 +02:00
cells [ i * cols + 1 ] = PQgetvalue ( res , i , 1 ) ; /* don't free this
2001-03-22 05:01:46 +01:00
* either */
2003-07-27 05:32:26 +02:00
# endif
* 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
/* Extra: not null and 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 ) ;
2003-02-24 04:54:06 +01:00
if ( strcmp ( PQgetvalue ( res , i , 3 ) , " t " ) = = 0 )
2002-12-21 02:07:07 +01:00
appendPQExpBufferStr ( & tmpbuf , " not null " ) ;
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 , " " ) ;
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
2003-07-27 05:32:26 +02:00
# ifdef WIN32
2004-01-25 04:07:22 +01:00
cells [ i * cols + 2 ] = pg_strdup ( mbvalidate ( tmpbuf . data , myopt . encoding ) ) ;
2003-07-27 05:32:26 +02:00
# else
2004-01-25 04:07:22 +01:00
cells [ i * cols + 2 ] = pg_strdup ( tmpbuf . data ) ;
2003-07-27 05:32:26 +02:00
# endif
2000-04-12 19:17:23 +02:00
}
1999-11-05 00:14:30 +01:00
/* Description */
2002-08-10 05:56:24 +02:00
if ( verbose )
2003-07-27 05:32:26 +02:00
# ifdef WIN32
2003-09-07 05:43:57 +02:00
cells [ i * cols + cols - 1 ] = mbvalidate ( PQgetvalue ( res , i , 5 ) , myopt . encoding ) ;
2003-07-27 05:32:26 +02:00
# else
2000-07-07 21:24:43 +02:00
cells [ i * cols + cols - 1 ] = PQgetvalue ( res , i , 5 ) ;
2003-07-27 05:32:26 +02:00
# endif
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 title */
2000-04-12 19:17:23 +02:00
switch ( tableinfo . relkind )
{
case ' r ' :
2002-08-10 05:56:24 +02:00
printfPQExpBuffer ( & title , _ ( " Table \" %s.%s \" " ) ,
schemaname , relationname ) ;
2000-10-25 22:36:52 +02:00
break ;
case ' v ' :
2002-08-10 05:56:24 +02:00
printfPQExpBuffer ( & title , _ ( " View \" %s.%s \" " ) ,
schemaname , relationname ) ;
2000-04-12 19:17:23 +02:00
break ;
case ' S ' :
2002-08-10 05:56:24 +02:00
printfPQExpBuffer ( & title , _ ( " Sequence \" %s.%s \" " ) ,
schemaname , relationname ) ;
2000-04-12 19:17:23 +02:00
break ;
case ' i ' :
2002-08-10 05:56:24 +02:00
printfPQExpBuffer ( & title , _ ( " Index \" %s.%s \" " ) ,
schemaname , relationname ) ;
2000-04-12 19:17:23 +02:00
break ;
case ' s ' :
2002-08-10 05:56:24 +02:00
printfPQExpBuffer ( & title , _ ( " Special relation \" %s.%s \" " ) ,
schemaname , relationname ) ;
2000-04-12 19:17:23 +02:00
break ;
2001-08-09 05:32:16 +02:00
case ' t ' :
2002-08-10 05:56:24 +02:00
printfPQExpBuffer ( & title , _ ( " TOAST table \" %s.%s \" " ) ,
schemaname , relationname ) ;
2001-08-09 05:32:16 +02:00
break ;
2002-08-29 02:17:06 +02:00
case ' c ' :
printfPQExpBuffer ( & title , _ ( " Composite type \" %s.%s \" " ) ,
schemaname , relationname ) ;
break ;
2000-04-12 19:17:23 +02:00
default :
2002-08-10 05:56:24 +02:00
printfPQExpBuffer ( & title , _ ( " ?%c? \" %s.%s \" " ) ,
2005-10-15 04:49:52 +02:00
tableinfo . relkind , schemaname , relationname ) ;
2000-10-25 22:36:52 +02:00
break ;
2000-04-12 19:17:23 +02: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 ,
2004-08-29 07:07:03 +02:00
" SELECT i.indisunique, i.indisprimary, i.indisclustered, a.amname, c2.relname, \n "
2005-10-15 04:49:52 +02: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 "
2002-04-24 07:24:00 +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 ) ;
char * indamname = PQgetvalue ( result , 0 , 3 ) ;
char * indtable = PQgetvalue ( result , 0 , 4 ) ;
char * indpred = PQgetvalue ( result , 0 , 5 ) ;
2004-07-12 22:41:13 +02:00
int count_footers = 0 ;
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
2004-07-12 22:41:13 +02:00
footers = pg_malloc_zero ( 4 * sizeof ( * footers ) ) ;
footers [ count_footers + + ] = pg_strdup ( tmpbuf . data ) ;
2004-08-20 22:18:23 +02:00
add_tablespace_footer ( tableinfo . relkind , tableinfo . tablespace ,
2005-06-15 01:59:31 +02:00
footers , & count_footers , tmpbuf , true ) ;
2004-07-12 22:41:13 +02:00
footers [ count_footers ] = NULL ;
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 ;
int rule_count = 0 ;
int count_footers = 0 ;
2002-08-10 05:56:24 +02:00
/* count rules other than the view rule */
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 "
2005-10-15 04:49:52 +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
else
rule_count = PQntuples ( result ) ;
}
2001-08-06 00:13:46 +02:00
/* Footer information about a view */
2004-01-25 04:07:22 +01:00
footers = pg_malloc_zero ( ( rule_count + 3 ) * sizeof ( * footers ) ) ;
footers [ count_footers ] = pg_malloc ( 64 + strlen ( view_def ) ) ;
2002-04-05 13:52:38 +02:00
snprintf ( footers [ count_footers ] , 64 + strlen ( view_def ) ,
2003-08-09 03:21:54 +02:00
_ ( " View definition: \n %s " ) , view_def ) ;
2002-04-05 13:52:38 +02:00
count_footers + + ;
/* print rules */
2003-12-01 23:11:06 +01:00
if ( rule_count > 0 )
2002-04-05 13:52:38 +02:00
{
2003-12-01 23:11:06 +01:00
printfPQExpBuffer ( & buf , _ ( " Rules: " ) ) ;
2004-01-25 04:07:22 +01:00
footers [ count_footers + + ] = pg_strdup ( buf . data ) ;
2003-12-01 23:11:06 +01:00
for ( i = 0 ; i < rule_count ; i + + )
{
const char * ruledef ;
2002-04-05 13:52:38 +02:00
2003-12-01 23:11:06 +01:00
/* Everything after "CREATE RULE" is echoed verbatim */
ruledef = PQgetvalue ( result , i , 1 ) ;
ruledef + = 12 ;
2002-04-05 13:52:38 +02:00
2003-12-01 23:11:06 +01:00
printfPQExpBuffer ( & buf , " %s " , ruledef ) ;
2004-01-25 04:07:22 +01:00
footers [ count_footers + + ] = pg_strdup ( buf . data ) ;
2003-12-01 23:11:06 +01:00
}
PQclear ( result ) ;
2002-04-05 13:52:38 +02:00
}
footers [ count_footers ] = NULL ;
1999-11-05 00:14:30 +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
else if ( tableinfo . relkind = = ' r ' )
1999-11-05 00:14:30 +01:00
{
2001-08-06 00:13:46 +02:00
/* Footer information about a table */
2001-10-25 07:50:21 +02:00
PGresult * result1 = NULL ,
* result2 = NULL ,
* result3 = NULL ,
2002-08-17 01:01:21 +02:00
* result4 = NULL ,
2003-07-25 23:42:26 +02:00
* result5 = NULL ,
* result6 = NULL ;
2002-08-17 01:01:21 +02:00
int check_count = 0 ,
index_count = 0 ,
foreignkey_count = 0 ,
2001-10-25 07:50:21 +02:00
rule_count = 0 ,
2003-07-25 23:42:26 +02:00
trigger_count = 0 ,
2003-08-04 02:43:34 +02:00
inherits_count = 0 ;
2000-04-12 19:17:23 +02:00
int count_footers = 0 ;
* 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
2001-06-30 19:26:12 +02:00
/* count 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 ,
2004-08-29 07:07:03 +02:00
" SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, "
2005-10-15 04:49:52 +02:00
" pg_catalog.pg_get_indexdef(i.indexrelid, 0, true), c2.reltablespace \n "
2002-09-04 22:31:48 +02:00
" FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i \n "
" WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid \n "
2005-10-15 04:49:52 +02:00
" ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname " ,
2002-09-04 22:31:48 +02:00
oid ) ;
2002-10-15 04:24:16 +02:00
result1 = PSQLexec ( buf . data , false ) ;
2000-04-12 19:17:23 +02:00
if ( ! result1 )
2002-04-24 07:24:00 +02:00
goto error_return ;
2000-04-12 19:17:23 +02:00
else
index_count = PQntuples ( result1 ) ;
}
2002-07-12 20:43:19 +02:00
/* count 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 ,
2005-10-20 07:15:09 +02:00
" SELECT r.conname, "
" pg_catalog.pg_get_constraintdef(r.oid, true) \n "
2002-09-04 22:31:48 +02:00
" FROM pg_catalog.pg_constraint r \n "
2005-10-15 04:49:52 +02:00
" WHERE r.conrelid = '%s' AND r.contype = 'c' ORDER BY 1 " ,
2002-09-04 22:31:48 +02:00
oid ) ;
2002-10-15 04:24:16 +02:00
result2 = PSQLexec ( buf . data , false ) ;
2000-04-12 19:17:23 +02:00
if ( ! result2 )
2003-06-27 18:55:23 +02:00
{
PQclear ( result1 ) ;
2002-04-24 07:24:00 +02:00
goto error_return ;
2003-06-27 18:55:23 +02:00
}
2000-04-12 19:17:23 +02:00
else
2002-07-12 20:43:19 +02:00
check_count = PQntuples ( result2 ) ;
2000-04-12 19:17:23 +02:00
}
/* count rules */
2002-04-24 07:24:00 +02:00
if ( tableinfo . hasrules )
2000-04-12 19:17:23 +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 "
2005-03-17 00:52:18 +01:00
" WHERE r.ev_class = '%s' ORDER BY 1 " ,
2002-09-04 22:31:48 +02:00
oid ) ;
2002-10-15 04:24:16 +02:00
result3 = PSQLexec ( buf . data , false ) ;
2000-04-12 19:17:23 +02:00
if ( ! result3 )
2003-06-27 18:55:23 +02:00
{
PQclear ( result1 ) ;
PQclear ( result2 ) ;
2002-04-24 07:24:00 +02:00
goto error_return ;
2003-06-27 18:55:23 +02:00
}
2000-04-12 19:17:23 +02:00
else
rule_count = PQntuples ( result3 ) ;
}
2002-08-17 01:01:21 +02:00
/* count triggers (but ignore foreign-key triggers) */
2002-04-24 07:24:00 +02:00
if ( tableinfo . triggers )
2000-04-12 19:17:23 +02:00
{
2002-04-24 07:24:00 +02:00
printfPQExpBuffer ( & buf ,
2005-10-15 04:49:52 +02:00
" SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid) \n "
2002-09-04 22:31:48 +02:00
" FROM pg_catalog.pg_trigger t \n "
" WHERE t.tgrelid = '%s' "
2003-10-26 03:53:45 +01:00
" AND (not tgisconstraint "
2002-09-04 22:31:48 +02:00
" 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) "
2005-03-17 00:52:18 +01:00
" WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f')) "
" ORDER BY 1 " ,
2002-09-04 22:31:48 +02:00
oid ) ;
2002-10-15 04:24:16 +02:00
result4 = PSQLexec ( buf . data , false ) ;
2000-04-12 19:17:23 +02:00
if ( ! result4 )
2003-06-27 18:55:23 +02:00
{
PQclear ( result1 ) ;
PQclear ( result2 ) ;
PQclear ( result3 ) ;
2002-04-24 07:24:00 +02:00
goto error_return ;
2003-06-27 18:55:23 +02:00
}
2000-04-12 19:17:23 +02:00
else
trigger_count = PQntuples ( result4 ) ;
}
2002-09-04 22:31:48 +02:00
/* count foreign-key constraints (there are none if no triggers) */
2002-08-17 01:01:21 +02:00
if ( tableinfo . triggers )
{
printfPQExpBuffer ( & buf ,
2002-09-04 22:31:48 +02:00
" SELECT conname, \n "
2005-10-15 04:49:52 +02:00
" pg_catalog.pg_get_constraintdef(oid, true) as condef \n "
2002-09-04 22:31:48 +02:00
" FROM pg_catalog.pg_constraint r \n "
2005-10-15 04:49:52 +02:00
" WHERE r.conrelid = '%s' AND r.contype = 'f' ORDER BY 1 " ,
2002-09-04 22:31:48 +02:00
oid ) ;
2002-10-15 04:24:16 +02:00
result5 = PSQLexec ( buf . data , false ) ;
2002-08-17 01:01:21 +02:00
if ( ! result5 )
2003-06-27 18:55:23 +02:00
{
PQclear ( result1 ) ;
PQclear ( result2 ) ;
PQclear ( result3 ) ;
PQclear ( result4 ) ;
2002-08-17 01:01:21 +02:00
goto error_return ;
2003-06-27 18:55:23 +02:00
}
2002-08-17 01:01:21 +02:00
else
foreignkey_count = PQntuples ( result5 ) ;
}
2003-07-25 23:42:26 +02:00
/* count inherited tables */
printfPQExpBuffer ( & buf , " SELECT c.relname FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhparent AND i.inhrelid = '%s' ORDER BY inhseqno ASC " , oid ) ;
result6 = PSQLexec ( buf . data , false ) ;
if ( ! result6 )
goto error_return ;
else
inherits_count = PQntuples ( result6 ) ;
2004-07-12 22:41:13 +02:00
footers = pg_malloc_zero ( ( index_count + check_count + rule_count + trigger_count + foreignkey_count + inherits_count + 7 + 1 )
2004-01-25 04:07:22 +01:00
* sizeof ( * footers ) ) ;
2000-04-12 19:17:23 +02:00
2001-06-30 19:26:12 +02:00
/* print indexes */
2003-08-04 02:43:34 +02:00
if ( index_count > 0 )
{
2003-03-27 17:57:39 +01:00
printfPQExpBuffer ( & buf , _ ( " Indexes: " ) ) ;
2004-01-25 04:07:22 +01:00
footers [ count_footers + + ] = pg_strdup ( buf . data ) ;
2003-03-27 17:57:39 +01:00
for ( i = 0 ; i < index_count ; i + + )
{
const char * indexdef ;
const char * usingpos ;
2005-10-15 04:49:52 +02:00
PQExpBufferData tmpbuf ;
2002-09-04 22:31:48 +02:00
2003-07-23 10:47:41 +02:00
/* Output index name */
printfPQExpBuffer ( & buf , _ ( " \" %s \" " ) ,
2002-08-10 05:56:24 +02:00
PQgetvalue ( result1 , i , 0 ) ) ;
2000-04-12 19:17:23 +02:00
2003-03-27 17:57:39 +01:00
/* Label as primary key or unique (but not both) */
appendPQExpBuffer ( & buf ,
2005-10-15 04:49:52 +02:00
strcmp ( PQgetvalue ( result1 , i , 1 ) , " t " ) = = 0
2004-11-09 15:39:44 +01:00
? " PRIMARY KEY, " :
2005-10-15 04:49:52 +02:00
( strcmp ( PQgetvalue ( result1 , i , 2 ) , " t " ) = = 0
? " UNIQUE, "
: " " ) ) ;
2003-03-27 17:57:39 +01:00
/* Everything after "USING" is echoed verbatim */
2004-04-06 06:05:17 +02:00
indexdef = PQgetvalue ( result1 , i , 4 ) ;
2003-03-27 17:57:39 +01:00
usingpos = strstr ( indexdef , " USING " ) ;
if ( usingpos )
indexdef = usingpos + 7 ;
2002-08-10 05:56:24 +02:00
2003-03-27 17:57:39 +01:00
appendPQExpBuffer ( & buf , " %s " , indexdef ) ;
2001-06-30 19:26:12 +02:00
2004-04-06 06:05:17 +02:00
if ( strcmp ( PQgetvalue ( result1 , i , 3 ) , " t " ) = = 0 )
2004-11-09 15:39:44 +01:00
appendPQExpBuffer ( & buf , " CLUSTER " ) ;
2004-04-06 06:05:17 +02:00
2005-06-15 01:59:31 +02:00
/* Print tablespace of the index on the same line */
count_footers + = 1 ;
initPQExpBuffer ( & tmpbuf ) ;
2005-10-15 04:49:52 +02:00
if ( add_tablespace_footer ( ' i ' ,
atooid ( PQgetvalue ( result1 , i , 5 ) ) ,
footers , & count_footers , tmpbuf , false ) )
2005-06-15 01:59:31 +02:00
{
appendPQExpBuffer ( & buf , " , " ) ;
appendPQExpBuffer ( & buf , tmpbuf . data ) ;
2005-10-04 21:01:18 +02:00
2005-06-15 01:59:31 +02:00
count_footers - = 2 ;
}
else
count_footers - = 1 ;
termPQExpBuffer ( & tmpbuf ) ;
2005-10-04 21:01:18 +02:00
2004-01-25 04:07:22 +01:00
footers [ count_footers + + ] = pg_strdup ( buf . data ) ;
2003-03-27 17:57:39 +01:00
}
2001-05-28 04:01:22 +02:00
}
2002-07-12 20:43:19 +02:00
/* print check constraints */
2003-08-04 02:43:34 +02:00
if ( check_count > 0 )
{
2003-07-23 10:47:41 +02:00
printfPQExpBuffer ( & buf , _ ( " Check constraints: " ) ) ;
2004-01-25 04:07:22 +01:00
footers [ count_footers + + ] = pg_strdup ( buf . data ) ;
2003-03-27 17:57:39 +01:00
for ( i = 0 ; i < check_count ; i + + )
{
2003-10-17 02:57:04 +02:00
printfPQExpBuffer ( & buf , _ ( " \" %s \" %s " ) ,
2005-10-20 07:15:09 +02:00
PQgetvalue ( result2 , i , 0 ) ,
PQgetvalue ( result2 , i , 1 ) ) ;
2003-03-27 17:57:39 +01:00
2004-01-25 04:07:22 +01:00
footers [ count_footers + + ] = pg_strdup ( buf . data ) ;
2003-03-27 17:57:39 +01:00
}
2000-04-12 19:17:23 +02:00
}
2002-08-17 01:01:21 +02:00
/* print foreign key constraints */
2003-08-04 02:43:34 +02:00
if ( foreignkey_count > 0 )
{
2003-07-23 10:47:41 +02:00
printfPQExpBuffer ( & buf , _ ( " Foreign-key constraints: " ) ) ;
2004-01-25 04:07:22 +01:00
footers [ count_footers + + ] = pg_strdup ( buf . data ) ;
2003-03-27 17:57:39 +01:00
for ( i = 0 ; i < foreignkey_count ; i + + )
{
printfPQExpBuffer ( & buf , _ ( " \" %s \" %s " ) ,
2002-08-17 01:01:21 +02:00
PQgetvalue ( result5 , i , 0 ) ,
PQgetvalue ( result5 , i , 1 ) ) ;
2004-01-25 04:07:22 +01:00
footers [ count_footers + + ] = pg_strdup ( buf . data ) ;
2003-03-27 17:57:39 +01:00
}
2002-08-17 01:01:21 +02:00
}
2000-04-12 19:17:23 +02:00
/* print rules */
2003-08-04 02:43:34 +02:00
if ( rule_count > 0 )
{
2003-03-27 17:57:39 +01:00
printfPQExpBuffer ( & buf , _ ( " Rules: " ) ) ;
2004-01-25 04:07:22 +01:00
footers [ count_footers + + ] = pg_strdup ( buf . data ) ;
2003-03-27 17:57:39 +01:00
for ( i = 0 ; i < rule_count ; i + + )
{
const char * ruledef ;
2001-06-30 19:26:12 +02:00
2003-03-27 17:57:39 +01:00
/* Everything after "CREATE RULE" is echoed verbatim */
ruledef = PQgetvalue ( result3 , i , 1 ) ;
ruledef + = 12 ;
2000-04-12 19:17:23 +02:00
2003-03-27 17:57:39 +01:00
printfPQExpBuffer ( & buf , " %s " , ruledef ) ;
2004-01-25 04:07:22 +01:00
footers [ count_footers + + ] = pg_strdup ( buf . data ) ;
2003-03-27 17:57:39 +01:00
}
2000-04-12 19:17:23 +02:00
}
/* print triggers */
2003-08-04 02:43:34 +02:00
if ( trigger_count > 0 )
{
2003-03-27 17:57:39 +01:00
printfPQExpBuffer ( & buf , _ ( " Triggers: " ) ) ;
2004-01-25 04:07:22 +01:00
footers [ count_footers + + ] = pg_strdup ( buf . data ) ;
2003-03-27 17:57:39 +01:00
for ( i = 0 ; i < trigger_count ; i + + )
{
const char * tgdef ;
const char * usingpos ;
2001-06-30 19:26:12 +02:00
2003-03-27 17:57:39 +01:00
/* Everything after "TRIGGER" is echoed verbatim */
tgdef = PQgetvalue ( result4 , i , 1 ) ;
usingpos = strstr ( tgdef , " TRIGGER " ) ;
if ( usingpos )
tgdef = usingpos + 9 ;
2000-04-12 19:17:23 +02:00
2003-03-27 17:57:39 +01:00
printfPQExpBuffer ( & buf , " %s " , tgdef ) ;
2004-01-25 04:07:22 +01:00
footers [ count_footers + + ] = pg_strdup ( buf . data ) ;
2003-03-27 17:57:39 +01:00
}
2000-04-12 19:17:23 +02:00
}
2003-07-25 23:42:26 +02:00
/* print inherits */
for ( i = 0 ; i < inherits_count ; i + + )
{
char * s = _ ( " Inherits " ) ;
if ( i = = 0 )
printfPQExpBuffer ( & buf , " %s: %s " , s , PQgetvalue ( result6 , i , 0 ) ) ;
else
printfPQExpBuffer ( & buf , " %*s %s " , ( int ) strlen ( s ) , " " , PQgetvalue ( result6 , i , 0 ) ) ;
if ( i < inherits_count - 1 )
appendPQExpBuffer ( & buf , " , " ) ;
2004-01-25 04:07:22 +01:00
footers [ count_footers + + ] = pg_strdup ( buf . data ) ;
2003-07-25 23:42:26 +02:00
}
2004-04-22 19:38:16 +02:00
if ( verbose )
{
2004-10-12 23:54:45 +02:00
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 " ) ) ) ;
footers [ count_footers + + ] = pg_strdup ( buf . data ) ;
}
2004-07-12 22:41:13 +02:00
add_tablespace_footer ( tableinfo . relkind , tableinfo . tablespace ,
2005-06-15 01:59:31 +02:00
footers , & count_footers , buf , true ) ;
2000-04-12 19:17:23 +02:00
/* end of list marker */
footers [ count_footers ] = NULL ;
PQclear ( result1 ) ;
PQclear ( result2 ) ;
PQclear ( result3 ) ;
PQclear ( result4 ) ;
2002-08-17 01:01:21 +02:00
PQclear ( result5 ) ;
2003-07-25 23:42:26 +02:00
PQclear ( result6 ) ;
* 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
2002-04-24 07:24:00 +02:00
printTable ( title . data , headers ,
( const char * * ) cells , ( const char * * ) footers ,
2005-06-14 04:57:45 +02:00
" llll " , & myopt , pset . queryFout , pset . logfile ) ;
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 */
2002-04-24 07:24:00 +02:00
termPQExpBuffer ( & buf ) ;
termPQExpBuffer ( & title ) ;
2002-12-21 02:07:07 +01:00
termPQExpBuffer ( & tmpbuf ) ;
1999-11-04 22:56:02 +01:00
2002-04-24 07:24:00 +02:00
if ( cells )
1999-11-05 00:14:30 +01:00
{
2002-12-21 02:07:07 +01:00
for ( i = 0 ; i < numrows ; i + + )
{
if ( show_modifiers )
2002-04-24 07:24:00 +02:00
free ( cells [ i * cols + 2 ] ) ;
2002-12-21 02:07:07 +01:00
}
2002-04-24 07:24:00 +02:00
free ( cells ) ;
1999-11-05 00:14:30 +01:00
}
1999-11-04 22:56:02 +01:00
2002-04-24 07:24:00 +02:00
if ( footers )
{
for ( ptr = footers ; * ptr ; ptr + + )
free ( * ptr ) ;
free ( footers ) ;
}
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
/*
* Return true if the relation uses non default tablespace ;
* otherwise return false
2005-06-15 01:59:31 +02:00
*/
static bool
2004-08-29 07:07:03 +02:00
add_tablespace_footer ( char relkind , Oid tablespace , char * * footers ,
2005-06-15 01:59:31 +02:00
int * count , PQExpBufferData buf , 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
* tablespaces don ' t need to know about them .
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
{
PGresult * result1 = NULL ;
2004-08-29 07:07:03 +02:00
2004-07-12 22:41:13 +02:00
printfPQExpBuffer ( & buf , " SELECT spcname FROM pg_tablespace \n "
2004-08-29 07:07:03 +02:00
" WHERE oid = '%u'; " , tablespace ) ;
2004-07-12 22:41:13 +02:00
result1 = PSQLexec ( buf . data , false ) ;
2004-08-29 07:07:03 +02:00
if ( ! result1 )
2005-06-15 01:59:31 +02:00
return false ;
2004-07-12 22:41:13 +02:00
/* Should always be the case, but.... */
2004-08-29 07:07:03 +02:00
if ( PQntuples ( result1 ) > 0 )
2004-07-12 22:41:13 +02:00
{
2005-10-15 04:49:52 +02:00
printfPQExpBuffer ( & buf ,
newline ? _ ( " Tablespace: \" %s \" " ) : _ ( " tablespace \" %s \" " ) ,
PQgetvalue ( result1 , 0 , 0 ) ) ;
2005-10-04 21:01:18 +02:00
2004-07-12 22:41:13 +02:00
footers [ ( * count ) + + ] = pg_strdup ( buf . data ) ;
}
PQclear ( result1 ) ;
2005-10-04 21:01:18 +02:00
2005-06-15 01:59:31 +02:00
return true ;
2004-07-12 22:41:13 +02:00
}
}
2005-10-04 21:01:18 +02:00
2005-06-15 01:59:31 +02:00
return false ;
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
2005-08-14 20:49:30 +02:00
describeRoles ( const char * pattern )
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 ;
2001-06-30 19:26:12 +02:00
printQueryOpt myopt = pset . popt ;
2001-10-25 07:50:21 +02:00
2002-04-24 07:24:00 +02:00
initPQExpBuffer ( & buf ) ;
printfPQExpBuffer ( & buf ,
2005-08-14 20:49:30 +02:00
" SELECT r.rolname AS \" %s \" , \n "
2005-10-15 04:49:52 +02:00
" CASE WHEN r.rolsuper THEN '%s' ELSE '%s' END AS \" %s \" , \n "
" CASE WHEN r.rolcreaterole THEN '%s' ELSE '%s' END AS \" %s \" , \n "
" CASE WHEN r.rolcreatedb THEN '%s' ELSE '%s' END AS \" %s \" , \n "
" CASE WHEN r.rolconnlimit < 0 THEN CAST('%s' AS pg_catalog.text) \n "
2005-08-14 20:49:30 +02:00
" ELSE CAST(r.rolconnlimit AS pg_catalog.text) \n "
" END AS \" %s \" , \n "
" ARRAY(SELECT b.rolname FROM pg_catalog.pg_auth_members m JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid) WHERE m.member = r.oid) as \" %s \" \n "
" FROM pg_catalog.pg_roles r \n " ,
_ ( " Role name " ) ,
2005-10-15 04:49:52 +02:00
_ ( " yes " ) , _ ( " no " ) , _ ( " Superuser " ) ,
_ ( " yes " ) , _ ( " no " ) , _ ( " Create role " ) ,
_ ( " yes " ) , _ ( " no " ) , _ ( " Create DB " ) ,
_ ( " no limit " ) , _ ( " Connections " ) ,
2005-08-14 20:49:30 +02:00
_ ( " Member of " ) ) ;
2003-12-01 23:21:54 +01:00
processNamePattern ( & buf , pattern , false , false ,
2005-08-14 20:49:30 +02:00
NULL , " r.rolname " , NULL , NULL ) ;
2003-12-01 23:21:54 +01:00
appendPQExpBuffer ( & buf , " ORDER BY 1; " ) ;
res = PSQLexec ( buf . data , false ) ;
termPQExpBuffer ( & buf ) ;
if ( ! res )
return false ;
myopt . nullPrint = NULL ;
2005-08-14 20:49:30 +02:00
myopt . title = _ ( " List of roles " ) ;
2003-12-01 23:21:54 +01:00
2005-06-14 04:57:45 +02:00
printQuery ( res , & myopt , pset . queryFout , pset . logfile ) ;
2003-12-01 23:21:54 +01:00
PQclear ( res ) ;
return true ;
}
1999-11-04 22:56:02 +01:00
/*
* listTables ( )
*
* handler for \ d , \ dt , etc .
*
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
2002-09-22 22:44:22 +02:00
* S - system tables ( pg_catalog )
1999-11-04 22:56:02 +01:00
* ( any order of the above is fine )
*/
bool
2002-08-10 05:56:24 +02:00
listTables ( const char * tabtypes , const char * pattern , bool verbose )
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 ;
bool showSystem = strchr ( tabtypes , ' S ' ) ! = 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 ;
1999-11-05 00:14:30 +01:00
2002-09-22 22:44:22 +02:00
if ( ! ( showTables | | showIndexes | | showViews | | showSeq ) )
2000-04-16 22:04:51 +02:00
showTables = showViews = showSeq = true ;
2002-04-24 07:24:00 +02:00
initPQExpBuffer ( & buf ) ;
2000-04-16 22:04:51 +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 "
" CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' WHEN 's' THEN '%s' END as \" %s \" , \n "
2005-08-14 21:20:45 +02:00
" r.rolname as \" %s \" " ,
2002-09-04 22:31:48 +02:00
_ ( " Schema " ) , _ ( " Name " ) ,
_ ( " table " ) , _ ( " view " ) , _ ( " index " ) , _ ( " sequence " ) ,
_ ( " special " ) , _ ( " Type " ) , _ ( " 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 \" " ,
_ ( " Table " ) ) ;
2002-08-10 05:56:24 +02:00
if ( verbose )
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 \" " ,
2002-09-04 22:31:48 +02:00
_ ( " Description " ) ) ;
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_roles r ON r.oid = c.relowner "
" \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', " ) ;
1999-11-05 00:14:30 +01:00
if ( showSystem & & showTables )
2002-04-24 07:24:00 +02:00
appendPQExpBuffer ( & buf , " 's', " ) ;
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
2002-08-10 05:56:24 +02:00
/*
2002-09-22 22:44:22 +02:00
* If showSystem is specified , show only system objects ( those in
2005-10-15 04:49:52 +02:00
* pg_catalog ) . Otherwise , suppress system objects , including those in
* pg_catalog and pg_toast . ( We don ' t want to hide temp tables though . )
2002-08-10 05:56:24 +02:00
*/
2001-06-30 19:26:12 +02:00
if ( showSystem )
2002-09-22 22:44:22 +02:00
appendPQExpBuffer ( & buf , " AND n.nspname = 'pg_catalog' \n " ) ;
2001-06-30 19:26:12 +02:00
else
2002-09-22 22:44:22 +02:00
appendPQExpBuffer ( & buf , " AND n.nspname NOT IN ('pg_catalog', 'pg_toast') \n " ) ;
processNamePattern ( & 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
2000-01-14 23:18:03 +01:00
if ( PQntuples ( res ) = = 0 & & ! 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 " ) ;
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
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
2002-08-10 05:56:24 +02:00
listDomains ( const char * pattern )
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 "
2005-10-15 04:49:52 +02:00
" pg_catalog.format_type(t.typbasetype, t.typtypmod) as \" %s \" , \n "
2002-09-04 22:31:48 +02:00
" CASE WHEN t.typnotnull AND t.typdefault IS NOT NULL THEN 'not null default '||t.typdefault \n "
2005-10-15 04:49:52 +02:00
" WHEN t.typnotnull AND t.typdefault IS NULL THEN 'not null' \n "
2002-09-04 22:31:48 +02:00
" WHEN NOT t.typnotnull AND t.typdefault IS NOT NULL THEN 'default '||t.typdefault \n "
" ELSE '' \n "
2005-04-06 07:23:32 +02:00
" END as \" %s \" , \n "
2005-10-15 04:49:52 +02:00
" pg_catalog.pg_get_constraintdef(r.oid, true) as \" %s \" \n "
2002-09-04 22:31:48 +02:00
" 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 "
" LEFT JOIN pg_catalog.pg_constraint r ON t.oid = r.contypid \n "
2002-09-04 22:31:48 +02:00
" WHERE t.typtype = 'd' \n " ,
_ ( " Schema " ) ,
_ ( " Name " ) ,
_ ( " Type " ) ,
2005-04-06 07:23:32 +02:00
_ ( " Modifier " ) ,
_ ( " Check " ) ) ;
2002-08-10 05:56:24 +02:00
processNamePattern ( & buf , pattern , true , false ,
" n.nspname " , " t.typname " , NULL ,
" pg_catalog.pg_type_is_visible(t.oid) " ) ;
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 " ) ;
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
listConversions ( const char * pattern )
{
PQExpBufferData buf ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
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 "
2003-01-07 21:56:07 +01:00
" ELSE '%s' END AS \" %s \" \n "
2005-10-15 04:49:52 +02:00
" FROM pg_catalog.pg_conversion c, pg_catalog.pg_namespace n \n "
2002-12-12 22:02:25 +01:00
" WHERE n.oid = c.connamespace \n " ,
_ ( " Schema " ) ,
_ ( " Name " ) ,
_ ( " Source " ) ,
2003-01-07 21:56:07 +01:00
_ ( " Destination " ) ,
_ ( " yes " ) ,
_ ( " no " ) ,
_ ( " Default? " ) ) ;
2002-12-12 22:02:25 +01:00
processNamePattern ( & buf , pattern , true , false ,
" n.nspname " , " c.conname " , NULL ,
" pg_catalog.pg_conversion_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 conversions " ) ;
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
listCasts ( const char * pattern )
{
PQExpBufferData buf ;
PGresult * res ;
printQueryOpt myopt = pset . popt ;
initPQExpBuffer ( & buf ) ;
/* NEED LEFT JOIN FOR BINARY CASTS */
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 "
2003-01-07 21:56:07 +01:00
" CASE WHEN castfunc = 0 THEN '%s' \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 "
" END as \" %s \" \n "
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 "
" ORDER BY 1, 2 " ,
2003-07-23 10:47:41 +02:00
_ ( " Source type " ) ,
_ ( " Target type " ) ,
_ ( " (binary compatible) " ) ,
2002-12-12 22:02:25 +01:00
_ ( " Function " ) ,
2003-01-07 21:56:07 +01:00
_ ( " no " ) ,
_ ( " in assignment " ) ,
_ ( " yes " ) ,
_ ( " Implicit? " ) ) ;
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 " ) ;
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 ;
}
2003-01-07 21:56:07 +01:00
/*
* \ dn
*
* Describes schemas ( namespaces )
*/
bool
2004-07-13 18:48:16 +02:00
listSchemas ( const char * pattern , bool verbose )
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 "
2005-08-14 21:20:45 +02:00
" r.rolname AS \" %s \" " ,
2004-08-29 07:07:03 +02:00
_ ( " Name " ) , _ ( " Owner " ) ) ;
2004-07-13 18:48:16 +02:00
if ( verbose )
appendPQExpBuffer ( & buf ,
2004-08-29 07:07:03 +02:00
" , \n n.nspacl as \" %s \" , "
2005-10-15 04:49:52 +02:00
" pg_catalog.obj_description(n.oid, 'pg_namespace') as \" %s \" " ,
2004-08-29 07:07:03 +02:00
_ ( " Access privileges " ) , _ ( " Description " ) ) ;
2004-07-13 18:48:16 +02:00
appendPQExpBuffer ( & buf ,
2005-10-15 04:49:52 +02:00
" \n FROM pg_catalog.pg_namespace n LEFT JOIN pg_catalog.pg_roles r \n "
2005-08-14 21:20:45 +02:00
" ON n.nspowner=r.oid \n "
2005-07-18 21:09:09 +02:00
" WHERE (n.nspname !~ '^pg_temp_' OR \n "
2005-10-15 04:49:52 +02:00
" n.nspname = (pg_catalog.current_schemas(true))[1]) \n " ) ; /* temp schema is first */
2004-07-13 18:48:16 +02:00
2003-12-24 00:13:14 +01:00
processNamePattern ( & buf , pattern , true , false ,
2003-01-07 21:56:07 +01:00
NULL , " n.nspname " , 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 schemas " ) ;
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 ;
}
2002-08-10 05:56:24 +02:00
/*
* processNamePattern
*
* Scan a wildcard - pattern option and generate appropriate WHERE clauses
* to limit the set of objects returned . The WHERE clauses are appended
* to buf .
*
* pattern : user - specified pattern option to a \ d command , or NULL if none .
* have_where : true if caller already emitted WHERE .
* force_escape : always quote regexp special characters , even outside quotes .
* schemavar : name of WHERE variable to match against a schema - name pattern .
* Can be NULL if no schema .
* namevar : name of WHERE variable to match against an object - name pattern .
* altnamevar : NULL , or name of an alternate variable to match against name .
* visibilityrule : clause to use if we want to restrict to visible objects
2002-09-04 22:31:48 +02:00
* ( for example , " pg_catalog.pg_table_is_visible(p.oid) " ) . Can be NULL .
2002-08-10 05:56:24 +02:00
*/
static void
processNamePattern ( PQExpBuffer buf , const char * pattern ,
bool have_where , bool force_escape ,
const char * schemavar , const char * namevar ,
const char * altnamevar , const char * visibilityrule )
{
PQExpBufferData schemabuf ;
PQExpBufferData namebuf ;
bool inquotes ;
const char * cp ;
int i ;
# define WHEREAND() \
( appendPQExpBuffer ( buf , have_where ? " AND " : " WHERE " ) , have_where = true )
if ( pattern = = NULL )
{
/* Default: select all visible objects */
if ( visibilityrule )
{
WHEREAND ( ) ;
appendPQExpBuffer ( buf , " %s \n " , visibilityrule ) ;
}
return ;
}
initPQExpBuffer ( & schemabuf ) ;
initPQExpBuffer ( & namebuf ) ;
/*
2005-10-15 04:49:52 +02:00
* Parse the pattern , converting quotes and lower - casing unquoted letters ;
* we assume this was NOT done by scan_option . Also , adjust shell - style
* wildcard characters into regexp notation .
2002-08-10 05:56:24 +02:00
*/
inquotes = false ;
cp = pattern ;
while ( * cp )
{
if ( * cp = = ' " ' )
{
if ( inquotes & & cp [ 1 ] = = ' " ' )
{
/* emit one quote */
appendPQExpBufferChar ( & namebuf , ' " ' ) ;
cp + + ;
}
inquotes = ! inquotes ;
cp + + ;
}
else if ( ! inquotes & & isupper ( ( unsigned char ) * cp ) )
{
appendPQExpBufferChar ( & namebuf ,
2004-05-07 02:24:59 +02:00
pg_tolower ( ( unsigned char ) * cp ) ) ;
2002-08-10 05:56:24 +02:00
cp + + ;
}
else if ( ! inquotes & & * cp = = ' * ' )
{
appendPQExpBuffer ( & namebuf , " .* " ) ;
cp + + ;
}
else if ( ! inquotes & & * cp = = ' ? ' )
{
appendPQExpBufferChar ( & namebuf , ' . ' ) ;
cp + + ;
}
else if ( ! inquotes & & * cp = = ' . ' )
{
/* Found schema/name separator, move current pattern to schema */
resetPQExpBuffer ( & schemabuf ) ;
appendPQExpBufferStr ( & schemabuf , namebuf . data ) ;
resetPQExpBuffer ( & namebuf ) ;
cp + + ;
}
else
{
/*
* Ordinary data character , transfer to pattern
*
2005-10-15 04:49:52 +02:00
* Inside double quotes , or at all times if parsing an operator name ,
* quote regexp special characters with a backslash to avoid
* regexp errors . Outside quotes , however , let them pass through
* as - is ; this lets knowledgeable users build regexp expressions
* that are more powerful than shell - style patterns .
2002-08-10 05:56:24 +02:00
*/
if ( ( inquotes | | force_escape ) & &
strchr ( " |*+?()[]{}.^$ \\ " , * cp ) )
appendPQExpBuffer ( & namebuf , " \\ \\ " ) ;
/* Ensure chars special to string literals are passed properly */
2005-07-02 19:01:59 +02:00
if ( SQL_STR_DOUBLE ( * cp ) )
appendPQExpBufferChar ( & namebuf , * cp ) ;
2002-08-10 05:56:24 +02:00
i = PQmblen ( cp , pset . encoding ) ;
while ( i - - )
{
appendPQExpBufferChar ( & namebuf , * cp ) ;
cp + + ;
}
}
}
/*
* Now decide what we need to emit .
*/
2005-07-18 19:40:14 +02:00
if ( namebuf . len > 0 )
{
/* We have a name pattern, so constrain the namevar(s) */
appendPQExpBufferChar ( & namebuf , ' $ ' ) ;
/* Optimize away ".*$", and possibly the whole pattern */
if ( namebuf . len > = 3 & &
strcmp ( namebuf . data + ( namebuf . len - 3 ) , " .*$ " ) = = 0 )
namebuf . data [ namebuf . len - 3 ] = ' \0 ' ;
if ( namebuf . data [ 0 ] )
{
WHEREAND ( ) ;
if ( altnamevar )
appendPQExpBuffer ( buf ,
" (%s ~ '^%s' \n "
" OR %s ~ '^%s') \n " ,
namevar , namebuf . data ,
altnamevar , namebuf . data ) ;
else
appendPQExpBuffer ( buf ,
" %s ~ '^%s' \n " ,
namevar , namebuf . data ) ;
}
}
2002-08-10 05:56:24 +02:00
if ( schemabuf . len > 0 )
{
/* We have a schema pattern, so constrain the schemavar */
appendPQExpBufferChar ( & schemabuf , ' $ ' ) ;
/* Optimize away ".*$", and possibly the whole pattern */
if ( schemabuf . len > = 3 & &
2002-09-04 22:31:48 +02:00
strcmp ( schemabuf . data + ( schemabuf . len - 3 ) , " .*$ " ) = = 0 )
schemabuf . data [ schemabuf . len - 3 ] = ' \0 ' ;
2002-08-10 05:56:24 +02:00
if ( schemabuf . data [ 0 ] & & schemavar )
{
WHEREAND ( ) ;
appendPQExpBuffer ( buf , " %s ~ '^%s' \n " ,
schemavar , schemabuf . data ) ;
}
}
else
{
/* No schema pattern given, so select only visible objects */
if ( visibilityrule )
{
WHEREAND ( ) ;
appendPQExpBuffer ( buf , " %s \n " , visibilityrule ) ;
}
}
termPQExpBuffer ( & schemabuf ) ;
termPQExpBuffer ( & namebuf ) ;
# undef WHEREAND
}