1996-07-09 06:22:35 +00:00
/*-------------------------------------------------------------------------
*
1999-02-13 23:22:53 +00:00
* pg_dump . c
2001-04-22 21:34:13 +00:00
* pg_dump is a utility for dumping out a postgres database
2001-03-22 04:01:46 +00:00
* into a script file .
2001-02-18 18:34:02 +00:00
*
2002-06-20 20:29:54 +00:00
* Portions Copyright ( c ) 1996 - 2002 , PostgreSQL Global Development Group
2001-02-18 18:34:02 +00:00
* Portions Copyright ( c ) 1994 , Regents of the University of California
1996-07-09 06:22:35 +00:00
*
1997-09-07 05:04:48 +00:00
* pg_dump will read the system catalogs in a database and
* dump out a script that reproduces
* the schema of the database in terms of
* user - defined types
* user - defined functions
* tables
2001-06-27 21:21:37 +00:00
* indexes
1997-09-07 05:04:48 +00:00
* aggregates
* operators
2001-08-12 19:02:39 +00:00
* privileges
1996-07-09 06:22:35 +00:00
*
1997-04-12 09:24:23 +00:00
* the output script is SQL that is understood by PostgreSQL
1996-07-09 06:22:35 +00:00
*
*
* IDENTIFICATION
2002-08-16 23:01:21 +00:00
* $ Header : / cvsroot / pgsql / src / bin / pg_dump / pg_dump . c , v 1.284 2002 / 08 / 16 23 : 01 : 19 tgl Exp $
2001-05-12 01:03:59 +00:00
*
2000-07-21 11:40:08 +00:00
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1996-07-09 06:22:35 +00:00
*/
2001-02-10 02:31:31 +00:00
/*
* Although this is not a backend module , we must include postgres . h anyway
* so that we can include a bunch of backend include files . pg_dump has
* never pretended to be very independent of the backend anyhow . . .
*/
# include "postgres.h"
1997-09-07 05:04:48 +00:00
# include <unistd.h> /* for getopt() */
1998-02-18 15:33:37 +00:00
# include <ctype.h>
2001-06-27 21:21:37 +00:00
# ifdef ENABLE_NLS
# include <locale.h>
# endif
1999-10-23 03:13:33 +00:00
# ifdef HAVE_GETOPT_H
# include <getopt.h>
# endif
# ifdef HAVE_TERMIOS_H
# include <termios.h>
# endif
2001-06-27 21:21:37 +00:00
# ifndef HAVE_STRDUP
# include "strdup.h"
# endif
1999-10-23 03:13:33 +00:00
# include "access/attnum.h"
1996-07-31 06:09:46 +00:00
# include "access/htup.h"
2001-02-10 02:31:31 +00:00
# include "catalog/pg_class.h"
2002-04-05 00:31:36 +00:00
# include "catalog/pg_proc.h"
1997-10-02 13:57:07 +00:00
# include "catalog/pg_trigger.h"
1999-10-23 03:13:33 +00:00
# include "catalog/pg_type.h"
1999-07-15 15:21:54 +00:00
1996-07-09 06:22:35 +00:00
# include "libpq-fe.h"
2001-02-10 02:31:31 +00:00
# include "libpq/libpq-fs.h"
1996-07-09 06:22:35 +00:00
# include "pg_dump.h"
2000-07-04 14:25:28 +00:00
# include "pg_backup.h"
2001-06-27 21:21:37 +00:00
# include "pg_backup_archiver.h"
1996-07-09 06:22:35 +00:00
2002-05-10 22:36:27 +00:00
2001-03-22 04:01:46 +00:00
typedef enum _formatLiteralOptions
{
2001-10-28 06:26:15 +00:00
CONV_ALL = 0 ,
PASS_LFTAB = 3 /* NOTE: 1 and 2 are reserved in case we
2001-03-22 04:01:46 +00:00
* want to make a mask . */
/* We could make this a bit mask for control chars, but I don't */
/* see any value in making it more complex...the current code */
/* only checks for 'opts == CONV_ALL' anyway. */
2001-02-13 01:31:54 +00:00
} formatLiteralOptions ;
2002-05-10 22:36:27 +00:00
typedef struct _dumpContext
{
TableInfo * tblinfo ;
int tblidx ;
bool oids ;
} DumpContext ;
static void help ( const char * progname ) ;
static int parse_version ( const char * versionString ) ;
static NamespaceInfo * findNamespace ( const char * nsoid , const char * objoid ) ;
static void dumpClasses ( const TableInfo * tblinfo , const int numTables ,
Archive * fout , const bool oids ) ;
static void dumpComment ( Archive * fout , const char * target ,
const char * namespace , const char * owner ,
const char * oid , const char * classname , int subid ,
const char * ( ( * deps ) [ ] ) ) ;
static void dumpOneBaseType ( Archive * fout , TypeInfo * tinfo ,
FuncInfo * g_finfo , int numFuncs ,
TypeInfo * g_tinfo , int numTypes ) ;
2002-04-05 11:51:13 +00:00
static void dumpOneDomain ( Archive * fout , TypeInfo * tinfo ) ;
2002-08-15 16:36:08 +00:00
static void dumpOneCompositeType ( Archive * fout , TypeInfo * tinfo ) ;
2002-05-10 22:36:27 +00:00
static void dumpOneTable ( Archive * fout , TableInfo * tbinfo ,
TableInfo * g_tblinfo ) ;
static void dumpOneSequence ( Archive * fout , TableInfo * tbinfo ,
const bool schemaOnly , const bool dataOnly ) ;
2002-05-19 10:08:25 +00:00
static void dumpTableACL ( Archive * fout , TableInfo * tbinfo ) ;
static void dumpFuncACL ( Archive * fout , FuncInfo * finfo ) ;
static void dumpAggACL ( Archive * fout , AggInfo * finfo ) ;
static void dumpACL ( Archive * fout , const char * type , const char * name ,
2002-07-04 15:35:07 +00:00
const char * tag , const char * nspname ,
2002-07-04 03:04:55 +00:00
const char * usename , const char * acl , const char * objoid ) ;
2002-05-19 10:08:25 +00:00
2002-08-16 23:01:21 +00:00
static void dumpConstraints ( Archive * fout , TableInfo * tblinfo , int numTables ) ;
2002-05-10 22:36:27 +00:00
static void dumpTriggers ( Archive * fout , TableInfo * tblinfo , int numTables ) ;
static void dumpRules ( Archive * fout , TableInfo * tblinfo , int numTables ) ;
static void formatStringLiteral ( PQExpBuffer buf , const char * str ,
const formatLiteralOptions opts ) ;
2002-07-04 03:04:55 +00:00
static char * format_function_signature ( FuncInfo * finfo , bool honor_quotes ) ;
2002-05-10 22:36:27 +00:00
static void dumpOneFunc ( Archive * fout , FuncInfo * finfo ) ;
static void dumpOneOpr ( Archive * fout , OprInfo * oprinfo ,
OprInfo * g_oprinfo , int numOperators ) ;
static const char * convertRegProcReference ( const char * proc ) ;
static const char * convertOperatorReference ( const char * opr ,
OprInfo * g_oprinfo , int numOperators ) ;
2002-07-30 21:56:04 +00:00
static void dumpOneOpclass ( Archive * fout , OpclassInfo * opcinfo ) ;
2002-05-10 22:36:27 +00:00
static void dumpOneAgg ( Archive * fout , AggInfo * agginfo ) ;
2001-04-25 07:03:20 +00:00
static Oid findLastBuiltinOid_V71 ( const char * ) ;
static Oid findLastBuiltinOid_V70 ( void ) ;
2000-07-04 14:25:28 +00:00
static void setMaxOid ( Archive * fout ) ;
2002-05-10 22:36:27 +00:00
static void selectSourceSchema ( const char * schemaName ) ;
static char * getFormattedTypeName ( const char * oid , OidOptions opts ) ;
static char * myFormatType ( const char * typname , int32 typmod ) ;
static const char * fmtQualifiedId ( const char * schema , const char * id ) ;
2002-04-05 11:51:13 +00:00
1998-12-05 22:09:57 +00:00
static void AddAcl ( char * aclbuf , const char * keyword ) ;
2002-05-19 10:08:25 +00:00
static char * GetPrivileges ( Archive * AH , const char * s , const char * type ) ;
1997-12-26 08:45:27 +00:00
2001-03-22 04:01:46 +00:00
static int dumpBlobs ( Archive * AH , char * , void * ) ;
static int dumpDatabase ( Archive * AH ) ;
2001-04-22 21:34:13 +00:00
static const char * getAttrName ( int attrnum , TableInfo * tblInfo ) ;
2002-07-18 04:43:51 +00:00
static const char * fmtCopyColumnList ( const TableInfo * ti ) ;
2000-07-21 11:40:08 +00:00
1999-05-25 16:15:34 +00:00
extern char * optarg ;
1997-09-08 02:41:22 +00:00
extern int optind ,
1999-05-25 16:15:34 +00:00
opterr ;
1996-07-09 06:22:35 +00:00
/* global decls */
1997-09-08 02:41:22 +00:00
bool g_verbose ; /* User wants verbose narration of our
1999-05-25 16:15:34 +00:00
* activities . */
2001-03-22 04:01:46 +00:00
Archive * g_fout ; /* the script file */
1999-05-25 16:15:34 +00:00
PGconn * g_conn ; /* the database connection */
2002-05-10 22:36:27 +00:00
/* various user-settable parameters */
1999-05-25 16:15:34 +00:00
bool force_quotes ; /* User wants to suppress double-quotes */
1999-05-26 16:06:45 +00:00
bool dumpData ; /* dump data using proper insert strings */
bool attrNames ; /* put attr names into insert strings */
bool schemaOnly ;
bool dataOnly ;
1999-05-27 16:29:05 +00:00
bool aclsSkip ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
/* obsolete as of 7.3: */
static Oid g_last_builtin_oid ; /* value of the last builtin oid */
static char * selectTablename = NULL ; /* name of a single table to dump */
1999-05-25 16:15:34 +00:00
char g_opaque_type [ 10 ] ; /* name for the opaque type */
1996-07-09 06:22:35 +00:00
/* placeholders for the delimiters for comments */
1997-09-08 02:41:22 +00:00
char g_comment_start [ 10 ] ;
char g_comment_end [ 10 ] ;
1996-07-09 06:22:35 +00:00
2002-05-10 22:36:27 +00:00
/* these are to avoid passing around info for findNamespace() */
static NamespaceInfo * g_namespaces ;
static int g_numNamespaces ;
1996-07-09 06:22:35 +00:00
2002-05-10 22:36:27 +00:00
int
main ( int argc , char * * argv )
2001-03-22 04:01:46 +00:00
{
2002-05-10 22:36:27 +00:00
int c ;
const char * filename = NULL ;
const char * format = " p " ;
const char * dbname = NULL ;
const char * pghost = NULL ;
const char * pgport = NULL ;
const char * username = NULL ;
bool oids = false ;
2001-03-22 04:01:46 +00:00
TableInfo * tblinfo ;
2002-05-10 22:36:27 +00:00
int numTables ;
bool force_password = false ;
int compressLevel = - 1 ;
bool ignore_version = false ;
int plainText = 0 ;
int outputClean = 0 ;
int outputCreate = 0 ;
int outputBlobs = 0 ;
int outputNoOwner = 0 ;
int outputNoReconnect = 0 ;
static int use_setsessauth = 0 ;
static int disable_triggers = 0 ;
char * outputSuperuser = NULL ;
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
RestoreOptions * ropt ;
1999-12-16 20:10:02 +00:00
# ifdef HAVE_GETOPT_LONG
2002-05-10 22:36:27 +00:00
static struct option long_options [ ] = {
{ " data-only " , no_argument , NULL , ' a ' } ,
{ " blobs " , no_argument , NULL , ' b ' } ,
{ " clean " , no_argument , NULL , ' c ' } ,
{ " create " , no_argument , NULL , ' C ' } ,
{ " file " , required_argument , NULL , ' f ' } ,
{ " format " , required_argument , NULL , ' F ' } ,
{ " inserts " , no_argument , NULL , ' d ' } ,
{ " attribute-inserts " , no_argument , NULL , ' D ' } ,
{ " column-inserts " , no_argument , NULL , ' D ' } ,
{ " host " , required_argument , NULL , ' h ' } ,
{ " ignore-version " , no_argument , NULL , ' i ' } ,
{ " no-reconnect " , no_argument , NULL , ' R ' } ,
{ " no-quotes " , no_argument , NULL , ' n ' } ,
{ " quotes " , no_argument , NULL , ' N ' } ,
{ " oids " , no_argument , NULL , ' o ' } ,
{ " no-owner " , no_argument , NULL , ' O ' } ,
{ " port " , required_argument , NULL , ' p ' } ,
{ " schema-only " , no_argument , NULL , ' s ' } ,
{ " superuser " , required_argument , NULL , ' S ' } ,
{ " table " , required_argument , NULL , ' t ' } ,
{ " password " , no_argument , NULL , ' W ' } ,
{ " username " , required_argument , NULL , ' U ' } ,
{ " verbose " , no_argument , NULL , ' v ' } ,
{ " no-privileges " , no_argument , NULL , ' x ' } ,
{ " no-acl " , no_argument , NULL , ' x ' } ,
{ " compress " , required_argument , NULL , ' Z ' } ,
{ " help " , no_argument , NULL , ' ? ' } ,
{ " version " , no_argument , NULL , ' V ' } ,
1996-07-09 06:22:35 +00:00
2002-05-10 22:36:27 +00:00
/*
* the following options don ' t have an equivalent short option
* letter , but are available as ' - X long - name '
*/
{ " use-set-session-authorization " , no_argument , & use_setsessauth , 1 } ,
{ " disable-triggers " , no_argument , & disable_triggers , 1 } ,
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
{ NULL , 0 , NULL , 0 }
} ;
int optindex ;
# endif
2000-08-01 15:51:45 +00:00
2002-05-10 22:36:27 +00:00
# ifdef ENABLE_NLS
setlocale ( LC_ALL , " " ) ;
bindtextdomain ( " pg_dump " , LOCALEDIR ) ;
textdomain ( " pg_dump " ) ;
# endif
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
g_verbose = false ;
force_quotes = true ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
strcpy ( g_comment_start , " -- " ) ;
g_comment_end [ 0 ] = ' \0 ' ;
strcpy ( g_opaque_type , " opaque " ) ;
2000-08-01 15:51:45 +00:00
2002-05-10 22:36:27 +00:00
dataOnly = schemaOnly = dumpData = attrNames = false ;
2000-07-21 11:40:08 +00:00
2002-05-10 22:36:27 +00:00
if ( ! strrchr ( argv [ 0 ] , ' / ' ) )
progname = argv [ 0 ] ;
1997-09-07 05:04:48 +00:00
else
2002-05-10 22:36:27 +00:00
progname = strrchr ( argv [ 0 ] , ' / ' ) + 1 ;
2000-07-21 11:40:08 +00:00
2002-05-10 22:36:27 +00:00
/* Set default options based on progname */
if ( strcmp ( progname , " pg_backup " ) = = 0 )
1997-09-07 05:04:48 +00:00
{
2002-05-10 22:36:27 +00:00
format = " c " ;
outputBlobs = true ;
1997-09-07 05:04:48 +00:00
}
2002-05-10 22:36:27 +00:00
if ( argc > 1 )
1997-09-07 05:04:48 +00:00
{
2002-05-10 22:36:27 +00:00
if ( strcmp ( argv [ 1 ] , " --help " ) = = 0 | | strcmp ( argv [ 1 ] , " -? " ) = = 0 )
1997-09-07 05:04:48 +00:00
{
2002-05-10 22:36:27 +00:00
help ( progname ) ;
exit ( 0 ) ;
1997-09-07 05:04:48 +00:00
}
2002-05-10 22:36:27 +00:00
if ( strcmp ( argv [ 1 ] , " --version " ) = = 0 | | strcmp ( argv [ 1 ] , " -V " ) = = 0 )
1997-09-07 05:04:48 +00:00
{
2002-05-10 22:36:27 +00:00
puts ( " pg_dump (PostgreSQL) " PG_VERSION ) ;
exit ( 0 ) ;
1997-09-07 05:04:48 +00:00
}
}
2000-08-01 15:51:45 +00:00
2002-05-10 22:36:27 +00:00
# ifdef HAVE_GETOPT_LONG
while ( ( c = getopt_long ( argc , argv , " abcCdDf:F:h:inNoOp:RsS:t:uU:vWxX:zZ:V? " , long_options , & optindex ) ) ! = - 1 )
# else
while ( ( c = getopt ( argc , argv , " abcCdDf:F:h:inNoOp:RsS:t:uU:vWxX:zZ:V?- " ) ) ! = - 1 )
# endif
1996-12-27 23:12:57 +00:00
2002-05-10 22:36:27 +00:00
{
switch ( c )
{
case ' a ' : /* Dump data only */
dataOnly = true ;
break ;
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
case ' b ' : /* Dump blobs */
outputBlobs = true ;
break ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
case ' c ' : /* clean (i.e., drop) schema prior to
* create */
outputClean = 1 ;
break ;
2001-04-25 07:03:20 +00:00
2002-05-10 22:36:27 +00:00
case ' C ' : /* Create DB */
2001-10-25 05:50:21 +00:00
2002-05-10 22:36:27 +00:00
outputCreate = 1 ;
break ;
2001-08-27 20:33:07 +00:00
2002-05-10 22:36:27 +00:00
case ' d ' : /* dump data as proper insert strings */
dumpData = true ;
break ;
2001-08-27 20:33:07 +00:00
2002-05-10 22:36:27 +00:00
case ' D ' : /* dump data as proper insert strings with
* attr names */
dumpData = true ;
attrNames = true ;
break ;
2001-10-25 05:50:21 +00:00
2002-05-10 22:36:27 +00:00
case ' f ' :
filename = optarg ;
break ;
2001-08-27 20:33:07 +00:00
2002-05-10 22:36:27 +00:00
case ' F ' :
format = optarg ;
break ;
2001-08-27 20:33:07 +00:00
2002-05-10 22:36:27 +00:00
case ' h ' : /* server host */
pghost = optarg ;
break ;
2001-08-27 20:33:07 +00:00
2002-05-10 22:36:27 +00:00
case ' i ' : /* ignore database version mismatch */
ignore_version = true ;
break ;
1996-12-27 23:12:57 +00:00
2002-05-10 22:36:27 +00:00
case ' n ' : /* Do not force double-quotes on
* identifiers */
force_quotes = false ;
break ;
2001-01-04 01:23:47 +00:00
2002-05-10 22:36:27 +00:00
case ' N ' : /* Force double-quotes on identifiers */
force_quotes = true ;
break ;
2001-01-04 01:23:47 +00:00
2002-05-10 22:36:27 +00:00
case ' o ' : /* Dump oids */
oids = true ;
break ;
2001-03-22 04:01:46 +00:00
1998-02-26 04:46:47 +00:00
2002-05-10 22:36:27 +00:00
case ' O ' : /* Don't reconnect to match owner */
outputNoOwner = 1 ;
break ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
case ' p ' : /* server port */
pgport = optarg ;
break ;
1998-02-26 04:46:47 +00:00
2002-05-10 22:36:27 +00:00
case ' R ' : /* No reconnect */
outputNoReconnect = 1 ;
break ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
case ' s ' : /* dump schema only */
schemaOnly = true ;
break ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
case ' S ' : /* Username for superuser in plain text
* output */
outputSuperuser = strdup ( optarg ) ;
break ;
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
case ' t ' : /* Dump data for this table only */
{
int i ;
1998-07-19 05:24:51 +00:00
2002-05-10 22:36:27 +00:00
selectTablename = strdup ( optarg ) ;
/*
* quoted string ? Then strip quotes and preserve
* case . . .
*/
if ( selectTablename [ 0 ] = = ' " ' )
{
char * endptr ;
endptr = selectTablename + strlen ( selectTablename ) - 1 ;
if ( * endptr = = ' " ' )
* endptr = ' \0 ' ;
strcpy ( selectTablename , & selectTablename [ 1 ] ) ;
}
else
{
/* otherwise, convert table name to lowercase... */
for ( i = 0 ; selectTablename [ i ] ; i + + )
if ( isupper ( ( unsigned char ) selectTablename [ i ] ) )
selectTablename [ i ] = tolower ( ( unsigned char ) selectTablename [ i ] ) ;
/*
* ' * ' is a special case meaning ALL tables , but
* only if unquoted
*/
if ( strcmp ( selectTablename , " * " ) = = 0 )
selectTablename [ 0 ] = ' \0 ' ;
}
}
break ;
case ' u ' :
force_password = true ;
username = simple_prompt ( " User name: " , 100 , true ) ;
break ;
case ' U ' :
username = optarg ;
break ;
case ' v ' : /* verbose */
g_verbose = true ;
break ;
case ' W ' :
force_password = true ;
break ;
case ' x ' : /* skip ACL dump */
aclsSkip = true ;
break ;
/*
* Option letters were getting scarce , so I invented this
* new scheme : ' - X feature ' turns on some feature . Compare
* to the - f option in GCC . You should also add an
* equivalent GNU - style option - - feature . Features that
* require arguments should use ' - X feature = foo ' .
*/
case ' X ' :
if ( strcmp ( optarg , " use-set-session-authorization " ) = = 0 )
use_setsessauth = 1 ;
else if ( strcmp ( optarg , " disable-triggers " ) = = 0 )
disable_triggers = 1 ;
else
{
fprintf ( stderr ,
gettext ( " %s: invalid -X option -- %s \n " ) ,
progname , optarg ) ;
fprintf ( stderr , gettext ( " Try '%s --help' for more information. \n " ) , progname ) ;
exit ( 1 ) ;
}
break ;
case ' Z ' : /* Compression Level */
compressLevel = atoi ( optarg ) ;
break ;
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
# ifndef HAVE_GETOPT_LONG
case ' - ' :
fprintf ( stderr ,
gettext ( " %s was compiled without support for long options. \n "
" Use --help for help on invocation options. \n " ) ,
progname ) ;
exit ( 1 ) ;
break ;
# else
/* This covers the long options equivalent to -X xxx. */
case 0 :
break ;
# endif
default :
fprintf ( stderr , gettext ( " Try '%s --help' for more information. \n " ) , progname ) ;
exit ( 1 ) ;
1997-04-02 04:17:27 +00:00
}
1997-09-07 05:04:48 +00:00
}
1996-12-27 23:12:57 +00:00
2002-05-10 22:36:27 +00:00
if ( optind < ( argc - 1 ) )
{
fprintf ( stderr ,
gettext ( " %s: too many command line options (first is '%s') \n "
" Try '%s --help' for more information. \n " ) ,
progname , argv [ optind + 1 ] , progname ) ;
exit ( 1 ) ;
}
2001-08-12 19:02:39 +00:00
2002-08-10 16:57:32 +00:00
/* Get database name from command line */
2002-05-10 22:36:27 +00:00
if ( optind < argc )
dbname = argv [ optind ] ;
2001-08-12 19:02:39 +00:00
2002-05-10 22:36:27 +00:00
if ( dataOnly & & schemaOnly )
{
write_msg ( NULL , " The options \" schema only \" (-s) and \" data only \" (-a) cannot be used together. \n " ) ;
exit ( 1 ) ;
}
2001-08-12 19:02:39 +00:00
2002-05-10 22:36:27 +00:00
if ( outputBlobs & & selectTablename ! = NULL & & strlen ( selectTablename ) > 0 )
{
write_msg ( NULL , " Large object output is not supported for a single table. \n " ) ;
write_msg ( NULL , " Use all tables or a full dump instead. \n " ) ;
exit ( 1 ) ;
}
2001-08-12 19:02:39 +00:00
2002-05-10 22:36:27 +00:00
if ( dumpData = = true & & oids = = true )
2001-08-12 19:02:39 +00:00
{
2002-05-10 22:36:27 +00:00
write_msg ( NULL , " INSERT (-d, -D) and OID (-o) options cannot be used together. \n " ) ;
write_msg ( NULL , " (The INSERT command cannot set oids.) \n " ) ;
2001-08-12 19:02:39 +00:00
exit ( 1 ) ;
}
2002-05-10 22:36:27 +00:00
if ( outputBlobs = = true & & ( format [ 0 ] = = ' p ' | | format [ 0 ] = = ' P ' ) )
{
write_msg ( NULL , " large object output is not supported for plain text dump files. \n " ) ;
write_msg ( NULL , " (Use a different output format.) \n " ) ;
exit ( 1 ) ;
}
2001-08-12 19:02:39 +00:00
2002-05-10 22:36:27 +00:00
/* open the output file */
switch ( format [ 0 ] )
{
2001-08-12 19:02:39 +00:00
2002-05-10 22:36:27 +00:00
case ' c ' :
case ' C ' :
g_fout = CreateArchive ( filename , archCustom , compressLevel ) ;
break ;
2001-08-12 19:02:39 +00:00
2002-05-10 22:36:27 +00:00
case ' f ' :
case ' F ' :
g_fout = CreateArchive ( filename , archFiles , compressLevel ) ;
break ;
2001-08-12 19:02:39 +00:00
2002-05-10 22:36:27 +00:00
case ' p ' :
case ' P ' :
plainText = 1 ;
g_fout = CreateArchive ( filename , archNull , 0 ) ;
break ;
2000-07-21 11:40:08 +00:00
2002-05-10 22:36:27 +00:00
case ' t ' :
case ' T ' :
g_fout = CreateArchive ( filename , archTar , compressLevel ) ;
break ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
default :
write_msg ( NULL , " invalid output format '%s' specified \n " , format ) ;
exit ( 1 ) ;
}
2001-08-22 20:23:24 +00:00
2002-05-10 22:36:27 +00:00
if ( g_fout = = NULL )
{
write_msg ( NULL , " could not open output file %s for writing \n " , filename ) ;
exit ( 1 ) ;
}
1999-12-16 20:10:02 +00:00
2002-05-10 22:36:27 +00:00
/* Let the archiver know how noisy to be */
g_fout - > verbose = g_verbose ;
2001-06-27 21:21:37 +00:00
2002-05-10 22:36:27 +00:00
/*
* Open the database using the Archiver , so it knows about it . Errors
* mean death .
*/
g_fout - > minRemoteVersion = 70000 ; /* we can handle back to 7.0 */
g_fout - > maxRemoteVersion = parse_version ( PG_VERSION ) ;
g_conn = ConnectDatabase ( g_fout , dbname , pghost , pgport , username , force_password , ignore_version ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
/*
* Start serializable transaction to dump consistent data
*/
{
PGresult * res ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
res = PQexec ( g_conn , " begin " ) ;
if ( ! res | | PQresultStatus ( res ) ! = PGRES_COMMAND_OK )
exit_horribly ( g_fout , NULL , " BEGIN command failed: %s " ,
PQerrorMessage ( g_conn ) ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
PQclear ( res ) ;
res = PQexec ( g_conn , " set transaction isolation level serializable " ) ;
if ( ! res | | PQresultStatus ( res ) ! = PGRES_COMMAND_OK )
exit_horribly ( g_fout , NULL , " could not set transaction isolation level to serializable: %s " ,
PQerrorMessage ( g_conn ) ) ;
2000-01-18 00:03:37 +00:00
2002-05-10 22:36:27 +00:00
PQclear ( res ) ;
2000-07-21 11:40:08 +00:00
}
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
if ( g_fout - > remoteVersion < 70300 )
2001-01-06 20:57:26 +00:00
{
2002-05-10 22:36:27 +00:00
if ( g_fout - > remoteVersion > = 70100 )
2002-08-10 16:57:32 +00:00
g_last_builtin_oid = findLastBuiltinOid_V71 ( PQdb ( ( ( ArchiveHandle * ) g_conn ) - > connection ) ) ;
2002-05-10 22:36:27 +00:00
else
g_last_builtin_oid = findLastBuiltinOid_V70 ( ) ;
if ( g_verbose )
write_msg ( NULL , " last built-in oid is %u \n " , g_last_builtin_oid ) ;
2001-01-06 20:57:26 +00:00
}
2002-05-10 22:36:27 +00:00
/* Dump the database definition */
if ( ! dataOnly )
dumpDatabase ( g_fout ) ;
2001-03-22 04:01:46 +00:00
2002-05-10 22:36:27 +00:00
if ( oids = = true )
setMaxOid ( g_fout ) ;
2000-08-01 15:51:45 +00:00
2002-05-10 22:36:27 +00:00
tblinfo = dumpSchema ( g_fout , & numTables , aclsSkip , schemaOnly , dataOnly ) ;
2000-08-01 15:51:45 +00:00
2002-05-10 22:36:27 +00:00
if ( ! schemaOnly )
dumpClasses ( tblinfo , numTables , g_fout , oids ) ;
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
if ( outputBlobs )
ArchiveEntry ( g_fout , " 0 " , " BLOBS " , NULL , " " ,
" BLOBS " , NULL , " " , " " , NULL , dumpBlobs , NULL ) ;
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
if ( ! dataOnly ) /* dump indexes and triggers at the end
* for performance */
{
2002-08-16 23:01:21 +00:00
dumpConstraints ( g_fout , tblinfo , numTables ) ;
2002-05-10 22:36:27 +00:00
dumpTriggers ( g_fout , tblinfo , numTables ) ;
dumpRules ( g_fout , tblinfo , numTables ) ;
}
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
/* Now sort the output nicely */
SortTocByOID ( g_fout ) ;
MoveToStart ( g_fout , " SCHEMA " ) ;
MoveToStart ( g_fout , " DATABASE " ) ;
MoveToEnd ( g_fout , " TABLE DATA " ) ;
MoveToEnd ( g_fout , " BLOBS " ) ;
MoveToEnd ( g_fout , " INDEX " ) ;
MoveToEnd ( g_fout , " CONSTRAINT " ) ;
MoveToEnd ( g_fout , " TRIGGER " ) ;
MoveToEnd ( g_fout , " RULE " ) ;
MoveToEnd ( g_fout , " SEQUENCE SET " ) ;
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
/*
* Moving all comments to end is annoying , but must do it for comments
* on stuff we just moved , and we don ' t seem to have quite enough
* dependency structure to get it really right . . .
*/
MoveToEnd ( g_fout , " COMMENT " ) ;
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
if ( plainText )
{
ropt = NewRestoreOptions ( ) ;
ropt - > filename = ( char * ) filename ;
ropt - > dropSchema = outputClean ;
ropt - > aclsSkip = aclsSkip ;
ropt - > superuser = outputSuperuser ;
ropt - > create = outputCreate ;
ropt - > noOwner = outputNoOwner ;
ropt - > noReconnect = outputNoReconnect ;
ropt - > use_setsessauth = use_setsessauth ;
ropt - > disable_triggers = disable_triggers ;
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
if ( compressLevel = = - 1 )
ropt - > compression = 0 ;
else
ropt - > compression = compressLevel ;
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
ropt - > suppressDumpWarnings = true ; /* We've already shown
* them */
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
RestoreArchive ( g_fout , ropt ) ;
}
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
CloseArchive ( g_fout ) ;
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
PQfinish ( g_conn ) ;
exit ( 0 ) ;
}
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
static void
help ( const char * progname )
{
printf ( gettext ( " %s dumps a database as a text file or to other formats. \n \n " ) , progname ) ;
puts ( gettext ( " Usage: " ) ) ;
printf ( gettext ( " %s [options] dbname \n \n " ) , progname ) ;
puts ( gettext ( " Options: " ) ) ;
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
# ifdef HAVE_GETOPT_LONG
puts ( gettext (
" -a, --data-only dump only the data, not the schema \n "
" -b, --blobs include large objects in dump \n "
" -c, --clean clean (drop) schema prior to create \n "
" -C, --create include commands to create database in dump \n "
" -d, --inserts dump data as INSERT, rather than COPY, commands \n "
" -D, --column-inserts dump data as INSERT commands with column names \n "
" -f, --file=FILENAME output file name \n "
" -F, --format {c|t|p} output file format (custom, tar, plain text) \n "
" -h, --host=HOSTNAME database server host name \n "
" -i, --ignore-version proceed even when server version mismatches \n "
" pg_dump version \n "
" -n, --no-quotes suppress most quotes around identifiers \n "
" -N, --quotes enable most quotes around identifiers \n "
" -o, --oids include oids in dump \n "
" -O, --no-owner do not output \\ connect commands in plain \n "
" text format \n "
" -p, --port=PORT database server port number \n "
" -R, --no-reconnect disable ALL reconnections to the database in \n "
" plain text format \n "
" -s, --schema-only dump only the schema, no data \n "
" -S, --superuser=NAME specify the superuser user name to use in \n "
" plain text format \n "
" -t, --table=TABLE dump this table only (* for all) \n "
" -U, --username=NAME connect as specified database user \n "
" -v, --verbose verbose mode \n "
" -W, --password force password prompt (should happen automatically) \n "
" -x, --no-privileges do not dump privileges (grant/revoke) \n "
" -X use-set-session-authorization, --use-set-session-authorization \n "
" output SET SESSION AUTHORIZATION commands rather \n "
" than \\ connect commands \n "
" -X disable-triggers, --disable-triggers \n "
" disable triggers during data-only restore \n "
" -Z, --compress {0-9} compression level for compressed formats \n "
) ) ;
# else
puts ( gettext (
" -a dump only the data, not the schema \n "
" -b include large objects in dump \n "
" -c clean (drop) schema prior to create \n "
" -C include commands to create database in dump \n "
" -d dump data as INSERT, rather than COPY, commands \n "
" -D dump data as INSERT commands with column names \n "
" -f FILENAME output file name \n "
" -F {c|t|p} output file format (custom, tar, plain text) \n "
" -h HOSTNAME database server host name \n "
" -i proceed even when server version mismatches \n "
" pg_dump version \n "
" -n suppress most quotes around identifiers \n "
" -N enable most quotes around identifiers \n "
" -o include oids in dump \n "
" -O do not output \\ connect commands in plain \n "
" text format \n "
" -p PORT database server port number \n "
" -R disable ALL reconnections to the database in \n "
" plain text format \n "
" -s dump only the schema, no data \n "
" -S NAME specify the superuser user name to use in \n "
" plain text format \n "
" -t TABLE dump this table only (* for all) \n "
" -U NAME connect as specified database user \n "
" -v verbose mode \n "
" -W force password prompt (should happen automatically) \n "
" -x do not dump privileges (grant/revoke) \n "
" -X use-set-session-authorization \n "
" output SET SESSION AUTHORIZATION commands rather \n "
" than \\ connect commands \n "
" -X disable-triggers disable triggers during data-only restore \n "
" -Z {0-9} compression level for compressed formats \n "
) ) ;
# endif
puts ( gettext ( " If no database name is not supplied, then the PGDATABASE environment \n "
" variable value is used. \n \n "
" Report bugs to <pgsql-bugs@postgresql.org>. " ) ) ;
}
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
static int
parse_version ( const char * versionString )
{
int cnt ;
int vmaj ,
vmin ,
vrev ;
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
cnt = sscanf ( versionString , " %d.%d.%d " , & vmaj , & vmin , & vrev ) ;
1998-02-18 15:33:37 +00:00
2002-05-10 22:36:27 +00:00
if ( cnt < 2 )
{
write_msg ( NULL , " unable to parse version string \" %s \" \n " , versionString ) ;
exit ( 1 ) ;
}
1999-05-25 16:15:34 +00:00
2002-05-10 22:36:27 +00:00
if ( cnt = = 2 )
vrev = 0 ;
2001-01-12 04:32:07 +00:00
2002-05-10 22:36:27 +00:00
return ( 100 * vmaj + vmin ) * 100 + vrev ;
}
2001-01-12 04:32:07 +00:00
2002-05-10 22:36:27 +00:00
void
exit_nicely ( void )
{
PQfinish ( g_conn ) ;
if ( g_verbose )
write_msg ( NULL , " *** aborted because of error \n " ) ;
exit ( 1 ) ;
}
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
/*
* selectDumpableNamespace : policy - setting subroutine
* Mark a namespace as to be dumped or not
*/
static void
selectDumpableNamespace ( NamespaceInfo * nsinfo )
{
/*
* If a specific table is being dumped , do not dump any complete
* namespaces . Otherwise , dump all non - system namespaces .
*/
if ( selectTablename ! = NULL )
nsinfo - > dump = false ;
else if ( strncmp ( nsinfo - > nspname , " pg_ " , 3 ) = = 0 )
nsinfo - > dump = false ;
else
nsinfo - > dump = true ;
}
2001-05-17 21:12:49 +00:00
2002-05-10 22:36:27 +00:00
/*
* selectDumpableTable : policy - setting subroutine
* Mark a table as to be dumped or not
*/
static void
selectDumpableTable ( TableInfo * tbinfo )
{
/*
* Always dump if dumping parent namespace ; else , if a particular
* tablename has been specified , dump matching table name ; else ,
* do not dump .
*/
if ( tbinfo - > relnamespace - > dump )
tbinfo - > dump = true ;
else if ( selectTablename ! = NULL )
tbinfo - > dump = ( strcmp ( tbinfo - > relname , selectTablename ) = = 0 ) ;
else
tbinfo - > dump = false ;
}
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
/*
* Dump a table ' s contents for loading using the COPY command
* - this routine is called by the Archiver when it wants the table
* to be dumped .
*/
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
# define COPYBUFSIZ 8192
2001-05-17 21:12:49 +00:00
2002-05-10 22:36:27 +00:00
static int
dumpClasses_nodumpData ( Archive * fout , char * oid , void * dctxv )
{
const DumpContext * dctx = ( DumpContext * ) dctxv ;
TableInfo * tbinfo = & dctx - > tblinfo [ dctx - > tblidx ] ;
const char * classname = tbinfo - > relname ;
const bool hasoids = tbinfo - > hasoids ;
const bool oids = dctx - > oids ;
PQExpBuffer q = createPQExpBuffer ( ) ;
PGresult * res ;
int ret ;
bool copydone ;
char copybuf [ COPYBUFSIZ ] ;
2002-07-18 04:43:51 +00:00
const char * column_list ;
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
if ( g_verbose )
write_msg ( NULL , " dumping out the contents of table %s \n " , classname ) ;
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
/*
* Make sure we are in proper schema . We will qualify the table name
* below anyway ( in case its name conflicts with a pg_catalog table ) ;
* but this ensures reproducible results in case the table contains
* regproc , regclass , etc columns .
*/
selectSourceSchema ( tbinfo - > relnamespace - > nspname ) ;
1997-09-07 05:04:48 +00:00
2002-07-18 04:43:51 +00:00
column_list = fmtCopyColumnList ( tbinfo ) ;
2002-05-10 22:36:27 +00:00
if ( oids & & hasoids )
2001-03-22 04:01:46 +00:00
{
2002-07-18 04:43:51 +00:00
appendPQExpBuffer ( q , " COPY %s %s WITH OIDS TO stdout; " ,
2002-05-10 22:36:27 +00:00
fmtQualifiedId ( tbinfo - > relnamespace - > nspname ,
2002-08-02 18:15:10 +00:00
classname ) ,
column_list ) ;
2000-10-24 13:24:30 +00:00
}
2001-04-23 23:36:33 +00:00
else
2000-07-04 14:25:28 +00:00
{
2002-07-18 04:43:51 +00:00
appendPQExpBuffer ( q , " COPY %s %s TO stdout; " ,
2002-05-10 22:36:27 +00:00
fmtQualifiedId ( tbinfo - > relnamespace - > nspname ,
2002-08-02 18:15:10 +00:00
classname ) ,
column_list ) ;
2000-07-04 14:25:28 +00:00
}
2002-05-10 22:36:27 +00:00
res = PQexec ( g_conn , q - > data ) ;
if ( ! res | |
PQresultStatus ( res ) = = PGRES_FATAL_ERROR )
2000-10-10 13:55:28 +00:00
{
2002-05-10 22:36:27 +00:00
write_msg ( NULL , " SQL command to dump the contents of table \" %s \" failed \n " ,
classname ) ;
write_msg ( NULL , " Error message from server: %s " , PQerrorMessage ( g_conn ) ) ;
write_msg ( NULL , " The command was: %s \n " , q - > data ) ;
exit_nicely ( ) ;
2000-10-10 13:55:28 +00:00
}
2002-05-10 22:36:27 +00:00
if ( PQresultStatus ( res ) ! = PGRES_COPY_OUT )
1999-05-26 16:06:45 +00:00
{
2002-05-10 22:36:27 +00:00
write_msg ( NULL , " SQL command to dump the contents of table \" %s \" executed abnormally. \n " ,
classname ) ;
write_msg ( NULL , " The server returned status %d when %d was expected. \n " ,
PQresultStatus ( res ) , PGRES_COPY_OUT ) ;
write_msg ( NULL , " The command was: %s \n " , q - > data ) ;
exit_nicely ( ) ;
1999-05-26 16:06:45 +00:00
}
2000-01-10 17:14:46 +00:00
2002-05-10 22:36:27 +00:00
copydone = false ;
2000-10-24 13:24:30 +00:00
2002-05-10 22:36:27 +00:00
while ( ! copydone )
2001-03-22 04:01:46 +00:00
{
2002-05-10 22:36:27 +00:00
ret = PQgetline ( g_conn , copybuf , COPYBUFSIZ ) ;
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
if ( copybuf [ 0 ] = = ' \\ ' & &
copybuf [ 1 ] = = ' . ' & &
copybuf [ 2 ] = = ' \0 ' )
{
copydone = true ; /* don't print this... */
}
else
{
archputs ( copybuf , fout ) ;
switch ( ret )
{
case EOF :
copydone = true ;
/* FALLTHROUGH */
case 0 :
archputc ( ' \n ' , fout ) ;
break ;
case 1 :
break ;
}
}
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
/*
* THROTTLE :
*
* There was considerable discussion in late July , 2000
* regarding slowing down pg_dump when backing up large
* tables . Users with both slow & fast ( muti - processor )
* machines experienced performance degradation when doing
* a backup .
*
* Initial attempts based on sleeping for a number of ms for
* each ms of work were deemed too complex , then a simple
* ' sleep in each loop ' implementation was suggested . The
* latter failed because the loop was too tight . Finally ,
* the following was implemented :
*
* If throttle is non - zero , then See how long since the last
* sleep . Work out how long to sleep ( based on ratio ) . If
* sleep is more than 100 ms , then sleep reset timer EndIf
* EndIf
*
* where the throttle value was the number of ms to sleep per
* ms of work . The calculation was done in each loop .
*
* Most of the hard work is done in the backend , and this
* solution still did not work particularly well : on slow
* machines , the ratio was 50 : 1 , and on medium paced
* machines , 1 : 1 , and on fast multi - processor machines , it
* had little or no effect , for reasons that were unclear .
*
* Further discussion ensued , and the proposal was dropped .
*
* For those people who want this feature , it can be
* implemented using gettimeofday in each loop ,
* calculating the time since last sleep , multiplying that
* by the sleep ratio , then if the result is more than a
* preset ' minimum sleep time ' ( say 100 ms ) , call the
* ' select ' function to sleep for a subsecond period ie .
*
* select ( 0 , NULL , NULL , NULL , & tvi ) ;
*
* This will return after the interval specified in the
* structure tvi . Fianally , call gettimeofday again to
* save the ' last sleep time ' .
*/
2000-07-04 14:25:28 +00:00
}
2002-05-10 22:36:27 +00:00
archprintf ( fout , " \\ . \n " ) ;
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
ret = PQendcopy ( g_conn ) ;
if ( ret ! = 0 )
2000-07-04 14:25:28 +00:00
{
2002-05-10 22:36:27 +00:00
write_msg ( NULL , " SQL command to dump the contents of table \" %s \" failed: PQendcopy() failed. \n " , classname ) ;
write_msg ( NULL , " Error message from server: %s " , PQerrorMessage ( g_conn ) ) ;
write_msg ( NULL , " The command was: %s \n " , q - > data ) ;
exit_nicely ( ) ;
1997-09-07 05:04:48 +00:00
}
2002-07-02 05:49:52 +00:00
PQclear ( res ) ;
2002-05-10 22:36:27 +00:00
destroyPQExpBuffer ( q ) ;
return 1 ;
}
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
static int
dumpClasses_dumpData ( Archive * fout , char * oid , void * dctxv )
{
const DumpContext * dctx = ( DumpContext * ) dctxv ;
TableInfo * tbinfo = & dctx - > tblinfo [ dctx - > tblidx ] ;
const char * classname = tbinfo - > relname ;
PQExpBuffer q = createPQExpBuffer ( ) ;
PGresult * res ;
int tuple ;
int field ;
2000-04-04 05:22:46 +00:00
1999-05-29 10:25:33 +00:00
/*
2002-05-10 22:36:27 +00:00
* Make sure we are in proper schema . We will qualify the table name
* below anyway ( in case its name conflicts with a pg_catalog table ) ;
* but this ensures reproducible results in case the table contains
* regproc , regclass , etc columns .
1999-05-29 10:25:33 +00:00
*/
2002-05-10 22:36:27 +00:00
selectSourceSchema ( tbinfo - > relnamespace - > nspname ) ;
2000-07-21 11:40:08 +00:00
2002-05-10 22:36:27 +00:00
if ( fout - > remoteVersion > = 70100 )
{
appendPQExpBuffer ( q , " DECLARE _pg_dump_cursor CURSOR FOR "
" SELECT * FROM ONLY %s " ,
fmtQualifiedId ( tbinfo - > relnamespace - > nspname ,
classname ) ) ;
1999-05-29 10:25:33 +00:00
}
2001-04-25 07:03:20 +00:00
else
2002-05-10 22:36:27 +00:00
{
appendPQExpBuffer ( q , " DECLARE _pg_dump_cursor CURSOR FOR "
" SELECT * FROM %s " ,
fmtQualifiedId ( tbinfo - > relnamespace - > nspname ,
classname ) ) ;
}
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
res = PQexec ( g_conn , q - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_COMMAND_OK )
{
write_msg ( NULL , " dumpClasses(): SQL command failed \n " ) ;
write_msg ( NULL , " Error message from server: %s " , PQerrorMessage ( g_conn ) ) ;
write_msg ( NULL , " The command was: %s \n " , q - > data ) ;
exit_nicely ( ) ;
}
2000-08-01 15:51:45 +00:00
2002-05-10 22:36:27 +00:00
do
{
PQclear ( res ) ;
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
res = PQexec ( g_conn , " FETCH 100 FROM _pg_dump_cursor " ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " dumpClasses(): SQL command failed \n " ) ;
write_msg ( NULL , " Error message from server: %s " , PQerrorMessage ( g_conn ) ) ;
write_msg ( NULL , " The command was: FETCH 100 FROM _pg_dump_cursor \n " ) ;
exit_nicely ( ) ;
}
for ( tuple = 0 ; tuple < PQntuples ( res ) ; tuple + + )
{
archprintf ( fout , " INSERT INTO %s " , fmtId ( classname , force_quotes ) ) ;
if ( attrNames = = true )
{
resetPQExpBuffer ( q ) ;
appendPQExpBuffer ( q , " ( " ) ;
for ( field = 0 ; field < PQnfields ( res ) ; field + + )
{
if ( field > 0 )
appendPQExpBuffer ( q , " , " ) ;
appendPQExpBuffer ( q , fmtId ( PQfname ( res , field ) , force_quotes ) ) ;
}
appendPQExpBuffer ( q , " ) " ) ;
archprintf ( fout , " %s " , q - > data ) ;
}
archprintf ( fout , " VALUES ( " ) ;
for ( field = 0 ; field < PQnfields ( res ) ; field + + )
{
if ( field > 0 )
archprintf ( fout , " , " ) ;
if ( PQgetisnull ( res , tuple , field ) )
{
archprintf ( fout , " NULL " ) ;
continue ;
}
switch ( PQftype ( res , field ) )
{
case INT2OID :
case INT4OID :
case OIDOID : /* int types */
case FLOAT4OID :
case FLOAT8OID : /* float types */
/* These types are printed without quotes */
archprintf ( fout , " %s " ,
PQgetvalue ( res , tuple , field ) ) ;
break ;
case BITOID :
case VARBITOID :
archprintf ( fout , " B'%s' " ,
PQgetvalue ( res , tuple , field ) ) ;
break ;
default :
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
/*
* All other types are printed as string literals ,
* with appropriate escaping of special
* characters .
*/
resetPQExpBuffer ( q ) ;
formatStringLiteral ( q , PQgetvalue ( res , tuple , field ) , CONV_ALL ) ;
archprintf ( fout , " %s " , q - > data ) ;
break ;
}
}
archprintf ( fout , " ); \n " ) ;
}
2000-07-21 11:40:08 +00:00
2002-05-10 22:36:27 +00:00
} while ( PQntuples ( res ) > 0 ) ;
PQclear ( res ) ;
2000-02-07 16:30:58 +00:00
2002-05-10 22:36:27 +00:00
res = PQexec ( g_conn , " CLOSE _pg_dump_cursor " ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_COMMAND_OK )
1997-10-02 13:57:07 +00:00
{
2002-05-10 22:36:27 +00:00
write_msg ( NULL , " dumpClasses(): SQL command failed \n " ) ;
write_msg ( NULL , " Error message from server: %s " , PQerrorMessage ( g_conn ) ) ;
write_msg ( NULL , " The command was: CLOSE _pg_dump_cursor \n " ) ;
exit_nicely ( ) ;
1997-10-02 13:57:07 +00:00
}
2002-05-10 22:36:27 +00:00
PQclear ( res ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
destroyPQExpBuffer ( q ) ;
return 1 ;
}
2000-07-21 11:40:08 +00:00
2002-05-10 22:36:27 +00:00
/*
* Convert a string value to an SQL string literal ,
* with appropriate escaping of special characters .
* Quote mark ' goes to ' ' per SQL standard , other
* stuff goes to \ sequences .
* The literal is appended to the given PQExpBuffer .
*/
static void
formatStringLiteral ( PQExpBuffer buf , const char * str , const formatLiteralOptions opts )
{
appendPQExpBufferChar ( buf , ' \' ' ) ;
while ( * str )
2000-07-04 14:25:28 +00:00
{
2002-05-10 22:36:27 +00:00
char ch = * str + + ;
2000-08-01 15:51:45 +00:00
2002-05-10 22:36:27 +00:00
if ( ch = = ' \\ ' | | ch = = ' \' ' )
{
appendPQExpBufferChar ( buf , ch ) ; /* double these */
appendPQExpBufferChar ( buf , ch ) ;
}
else if ( ( unsigned char ) ch < ( unsigned char ) ' ' & &
( opts = = CONV_ALL
| | ( ch ! = ' \n ' & & ch ! = ' \t ' )
) )
{
/*
* generate octal escape for control chars other than
* whitespace
*/
appendPQExpBufferChar ( buf , ' \\ ' ) ;
appendPQExpBufferChar ( buf , ( ( ch > > 6 ) & 3 ) + ' 0 ' ) ;
appendPQExpBufferChar ( buf , ( ( ch > > 3 ) & 7 ) + ' 0 ' ) ;
appendPQExpBufferChar ( buf , ( ch & 7 ) + ' 0 ' ) ;
}
2000-08-01 15:51:45 +00:00
else
2002-05-10 22:36:27 +00:00
appendPQExpBufferChar ( buf , ch ) ;
}
appendPQExpBufferChar ( buf , ' \' ' ) ;
}
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
/*
* DumpClasses -
* dump the contents of all the classes .
*/
static void
dumpClasses ( const TableInfo * tblinfo , const int numTables , Archive * fout ,
const bool oids )
{
int i ;
DataDumperPtr dumpFn ;
DumpContext * dumpCtx ;
char copyBuf [ 512 ] ;
char * copyStmt ;
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
for ( i = 0 ; i < numTables ; i + + )
{
const char * classname = tblinfo [ i ] . relname ;
2001-04-25 07:03:20 +00:00
2002-05-10 22:36:27 +00:00
/* Skip VIEW relations */
if ( tblinfo [ i ] . relkind = = RELKIND_VIEW )
continue ;
2000-07-04 14:25:28 +00:00
2002-08-15 16:36:08 +00:00
/* Skip TYPE relations */
if ( tblinfo [ i ] . relkind = = RELKIND_COMPOSITE_TYPE )
continue ;
2002-05-10 22:36:27 +00:00
if ( tblinfo [ i ] . relkind = = RELKIND_SEQUENCE ) /* already dumped */
continue ;
1999-05-26 21:51:13 +00:00
2002-05-10 22:36:27 +00:00
if ( tblinfo [ i ] . dump )
{
if ( g_verbose )
write_msg ( NULL , " preparing to dump the contents of table %s \n " ,
classname ) ;
dumpCtx = ( DumpContext * ) malloc ( sizeof ( DumpContext ) ) ;
dumpCtx - > tblinfo = ( TableInfo * ) tblinfo ;
dumpCtx - > tblidx = i ;
dumpCtx - > oids = oids ;
if ( ! dumpData )
{
/* Dump/restore using COPY */
2002-08-02 18:15:10 +00:00
const char * column_list ;
2002-05-10 22:36:27 +00:00
dumpFn = dumpClasses_nodumpData ;
2002-08-02 18:15:10 +00:00
column_list = fmtCopyColumnList ( & ( tblinfo [ i ] ) ) ;
2002-07-18 04:43:51 +00:00
sprintf ( copyBuf , " COPY %s %s %sFROM stdin; \n " ,
2002-08-02 18:15:10 +00:00
fmtId ( tblinfo [ i ] . relname , force_quotes ) ,
column_list ,
2002-05-10 22:36:27 +00:00
( oids & & tblinfo [ i ] . hasoids ) ? " WITH OIDS " : " " ) ;
copyStmt = copyBuf ;
}
else
{
/* Restore using INSERT */
dumpFn = dumpClasses_dumpData ;
copyStmt = NULL ;
}
ArchiveEntry ( fout , tblinfo [ i ] . oid , tblinfo [ i ] . relname ,
tblinfo [ i ] . relnamespace - > nspname , tblinfo [ i ] . usename ,
" TABLE DATA " , NULL , " " , " " , copyStmt ,
dumpFn , dumpCtx ) ;
}
}
1996-07-09 06:22:35 +00:00
}
2002-05-10 22:36:27 +00:00
2000-08-01 15:51:45 +00:00
/*
* dumpDatabase :
* dump the database definition
*/
2001-03-22 04:01:46 +00:00
static int
2000-08-01 15:51:45 +00:00
dumpDatabase ( Archive * AH )
{
2001-03-22 04:01:46 +00:00
PQExpBuffer dbQry = createPQExpBuffer ( ) ;
PQExpBuffer delQry = createPQExpBuffer ( ) ;
PQExpBuffer creaQry = createPQExpBuffer ( ) ;
PGresult * res ;
int ntups ;
2002-02-11 00:18:20 +00:00
int i_dba ,
i_encoding ,
i_datpath ;
const char * datname ,
* dba ,
* encoding ,
* datpath ;
datname = PQdb ( g_conn ) ;
2000-08-01 15:51:45 +00:00
if ( g_verbose )
2001-07-03 20:21:50 +00:00
write_msg ( NULL , " saving database definition \n " ) ;
2000-08-01 15:51:45 +00:00
2002-05-10 22:36:27 +00:00
/* Make sure we are in proper schema */
selectSourceSchema ( " pg_catalog " ) ;
2002-02-11 00:18:20 +00:00
/* Get the database owner and parameters from pg_database */
appendPQExpBuffer ( dbQry , " select (select usename from pg_user where usesysid = datdba) as dba, "
" encoding, datpath from pg_database "
2001-03-22 04:01:46 +00:00
" where datname = " ) ;
2002-02-11 00:18:20 +00:00
formatStringLiteral ( dbQry , datname , CONV_ALL ) ;
2000-08-01 15:51:45 +00:00
res = PQexec ( g_conn , dbQry - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " SQL command failed \n " ) ;
write_msg ( NULL , " Error message from server: %s " , PQerrorMessage ( g_conn ) ) ;
write_msg ( NULL , " The command was: %s \n " , dbQry - > data ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
2000-08-01 15:51:45 +00:00
}
ntups = PQntuples ( res ) ;
2001-06-27 21:21:37 +00:00
if ( ntups < = 0 )
{
2002-02-11 00:18:20 +00:00
write_msg ( NULL , " missing pg_database entry for database \" %s \" \n " ,
datname ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
2001-06-27 21:21:37 +00:00
}
2000-08-01 15:51:45 +00:00
if ( ntups ! = 1 )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " query returned more than one (%d) pg_database entry for database \" %s \" \n " ,
2002-02-11 00:18:20 +00:00
ntups , datname ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
2000-08-01 15:51:45 +00:00
}
i_dba = PQfnumber ( res , " dba " ) ;
2002-02-11 00:18:20 +00:00
i_encoding = PQfnumber ( res , " encoding " ) ;
i_datpath = PQfnumber ( res , " datpath " ) ;
dba = PQgetvalue ( res , 0 , i_dba ) ;
encoding = PQgetvalue ( res , 0 , i_encoding ) ;
datpath = PQgetvalue ( res , 0 , i_datpath ) ;
appendPQExpBuffer ( creaQry , " CREATE DATABASE %s WITH TEMPLATE = template0 " ,
fmtId ( datname , force_quotes ) ) ;
if ( strlen ( encoding ) > 0 )
appendPQExpBuffer ( creaQry , " ENCODING = %s " , encoding ) ;
if ( strlen ( datpath ) > 0 )
appendPQExpBuffer ( creaQry , " LOCATION = '%s' " , datpath ) ;
appendPQExpBuffer ( creaQry , " ; \n " ) ;
appendPQExpBuffer ( delQry , " DROP DATABASE %s; \n " ,
fmtId ( datname , force_quotes ) ) ;
2002-05-10 22:36:27 +00:00
ArchiveEntry ( AH , " 0 " , /* OID */
datname , /* Name */
NULL , /* Namespace */
dba , /* Owner */
" DATABASE " , /* Desc */
NULL , /* Deps */
creaQry - > data , /* Create */
delQry - > data , /* Del */
NULL , /* Copy */
NULL , /* Dumper */
NULL ) ; /* Dumper Arg */
2000-08-01 15:51:45 +00:00
PQclear ( res ) ;
2001-08-03 19:43:05 +00:00
destroyPQExpBuffer ( dbQry ) ;
destroyPQExpBuffer ( delQry ) ;
destroyPQExpBuffer ( creaQry ) ;
2000-08-01 15:51:45 +00:00
return 1 ;
}
2000-07-21 11:40:08 +00:00
/*
* dumpBlobs :
* dump all blobs
*
*/
2001-03-22 04:01:46 +00:00
# define loBufSize 16384
2000-07-21 11:40:08 +00:00
# define loFetchSize 1000
2001-03-22 04:01:46 +00:00
static int
dumpBlobs ( Archive * AH , char * junkOid , void * junkVal )
2000-07-21 11:40:08 +00:00
{
2001-03-22 04:01:46 +00:00
PQExpBuffer oidQry = createPQExpBuffer ( ) ;
PQExpBuffer oidFetchQry = createPQExpBuffer ( ) ;
PGresult * res ;
int i ;
int loFd ;
char buf [ loBufSize ] ;
int cnt ;
2001-08-10 18:57:42 +00:00
Oid blobOid ;
2000-07-21 11:40:08 +00:00
if ( g_verbose )
2001-09-21 21:58:30 +00:00
write_msg ( NULL , " saving large objects \n " ) ;
2000-07-21 11:40:08 +00:00
2002-05-10 22:36:27 +00:00
/* Make sure we are in proper schema */
selectSourceSchema ( " pg_catalog " ) ;
2000-07-21 11:40:08 +00:00
/* Cursor to get all BLOB tables */
2001-04-25 07:03:20 +00:00
if ( AH - > remoteVersion > = 70100 )
appendPQExpBuffer ( oidQry , " Declare blobOid Cursor for SELECT DISTINCT loid FROM pg_largeobject " ) ;
2001-10-25 05:50:21 +00:00
else
2001-04-25 07:03:20 +00:00
appendPQExpBuffer ( oidQry , " Declare blobOid Cursor for SELECT oid from pg_class where relkind = 'l' " ) ;
2000-07-21 11:40:08 +00:00
res = PQexec ( g_conn , oidQry - > data ) ;
if ( ! res | | PQresultStatus ( res ) ! = PGRES_COMMAND_OK )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " dumpBlobs(): cursor declaration failed: %s " , PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
2000-07-21 11:40:08 +00:00
}
/* Fetch for cursor */
appendPQExpBuffer ( oidFetchQry , " Fetch %d in blobOid " , loFetchSize ) ;
2001-03-22 04:01:46 +00:00
do
{
2000-07-21 11:40:08 +00:00
/* Do a fetch */
PQclear ( res ) ;
res = PQexec ( g_conn , oidFetchQry - > data ) ;
if ( ! res | | PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " dumpBlobs(): fetch from cursor failed: %s " ,
PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
2000-07-21 11:40:08 +00:00
}
/* Process the tuples, if any */
for ( i = 0 ; i < PQntuples ( res ) ; i + + )
{
2001-08-10 18:57:42 +00:00
blobOid = atooid ( PQgetvalue ( res , i , 0 ) ) ;
2000-07-21 11:40:08 +00:00
/* Open the BLOB */
loFd = lo_open ( g_conn , blobOid , INV_READ ) ;
if ( loFd = = - 1 )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " dumpBlobs(): could not open large object: %s " ,
PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
2000-07-21 11:40:08 +00:00
}
StartBlob ( AH , blobOid ) ;
2002-05-10 22:36:27 +00:00
/* Now read it in chunks, sending data to archive */
do
{
cnt = lo_read ( g_conn , loFd , buf , loBufSize ) ;
if ( cnt < 0 )
{
write_msg ( NULL , " dumpBlobs(): error reading large object: %s " ,
PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
2000-09-18 03:24:03 +00:00
2002-05-10 22:36:27 +00:00
WriteData ( AH , buf , cnt ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
} while ( cnt > 0 ) ;
2001-08-03 19:43:05 +00:00
2002-05-10 22:36:27 +00:00
lo_close ( g_conn , loFd ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
EndBlob ( AH , blobOid ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
}
} while ( PQntuples ( res ) > 0 ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
destroyPQExpBuffer ( oidQry ) ;
destroyPQExpBuffer ( oidFetchQry ) ;
2001-08-03 19:43:05 +00:00
2002-05-10 22:36:27 +00:00
return 1 ;
1996-07-09 06:22:35 +00:00
}
/*
2002-05-10 22:36:27 +00:00
* getNamespaces :
* read all namespaces in the system catalogs and return them in the
* NamespaceInfo * structure
1996-07-09 06:22:35 +00:00
*
2002-05-10 22:36:27 +00:00
* numNamespaces is set to the number of namespaces read in
1996-07-09 06:22:35 +00:00
*/
2002-05-10 22:36:27 +00:00
NamespaceInfo *
getNamespaces ( int * numNamespaces )
1996-07-09 06:22:35 +00:00
{
2000-04-12 17:17:23 +00:00
PGresult * res ;
1997-09-08 02:41:22 +00:00
int ntups ;
int i ;
2002-05-10 22:36:27 +00:00
PQExpBuffer query ;
NamespaceInfo * nsinfo ;
1997-09-08 02:41:22 +00:00
int i_oid ;
2002-05-10 22:36:27 +00:00
int i_nspname ;
1997-09-08 02:41:22 +00:00
int i_usename ;
2002-05-10 22:36:27 +00:00
int i_nspacl ;
1997-09-07 05:04:48 +00:00
/*
2002-05-10 22:36:27 +00:00
* Before 7.3 , there are no real namespaces ; create two dummy entries ,
* one for user stuff and one for system stuff .
1997-09-07 05:04:48 +00:00
*/
2002-05-10 22:36:27 +00:00
if ( g_fout - > remoteVersion < 70300 )
{
nsinfo = ( NamespaceInfo * ) malloc ( 2 * sizeof ( NamespaceInfo ) ) ;
nsinfo [ 0 ] . oid = strdup ( " 0 " ) ;
nsinfo [ 0 ] . nspname = strdup ( " " ) ;
nsinfo [ 0 ] . usename = strdup ( " " ) ;
nsinfo [ 0 ] . nspacl = strdup ( " " ) ;
selectDumpableNamespace ( & nsinfo [ 0 ] ) ;
nsinfo [ 1 ] . oid = strdup ( " 1 " ) ;
nsinfo [ 1 ] . nspname = strdup ( " pg_catalog " ) ;
nsinfo [ 1 ] . usename = strdup ( " " ) ;
nsinfo [ 1 ] . nspacl = strdup ( " " ) ;
selectDumpableNamespace ( & nsinfo [ 1 ] ) ;
g_namespaces = nsinfo ;
g_numNamespaces = * numNamespaces = 2 ;
return nsinfo ;
}
query = createPQExpBuffer ( ) ;
/* Make sure we are in proper schema */
selectSourceSchema ( " pg_catalog " ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
/*
* we fetch all namespaces including system ones , so that every object
* we read in can be linked to a containing namespace .
*/
appendPQExpBuffer ( query , " SELECT oid, nspname, "
" (select usename from pg_user where nspowner = usesysid) as usename, "
" nspacl "
" FROM pg_namespace " ) ;
1997-09-07 05:04:48 +00:00
1999-12-27 15:42:44 +00:00
res = PQexec ( g_conn , query - > data ) ;
1997-09-07 05:04:48 +00:00
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
2002-05-10 22:36:27 +00:00
write_msg ( NULL , " query to obtain list of namespaces failed: %s " , PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1997-09-07 05:04:48 +00:00
}
ntups = PQntuples ( res ) ;
2002-05-10 22:36:27 +00:00
nsinfo = ( NamespaceInfo * ) malloc ( ntups * sizeof ( NamespaceInfo ) ) ;
1997-09-07 05:04:48 +00:00
i_oid = PQfnumber ( res , " oid " ) ;
2002-05-10 22:36:27 +00:00
i_nspname = PQfnumber ( res , " nspname " ) ;
1997-09-07 05:04:48 +00:00
i_usename = PQfnumber ( res , " usename " ) ;
2002-05-10 22:36:27 +00:00
i_nspacl = PQfnumber ( res , " nspacl " ) ;
1997-09-07 05:04:48 +00:00
for ( i = 0 ; i < ntups ; i + + )
{
2002-05-10 22:36:27 +00:00
nsinfo [ i ] . oid = strdup ( PQgetvalue ( res , i , i_oid ) ) ;
nsinfo [ i ] . nspname = strdup ( PQgetvalue ( res , i , i_nspname ) ) ;
nsinfo [ i ] . usename = strdup ( PQgetvalue ( res , i , i_usename ) ) ;
nsinfo [ i ] . nspacl = strdup ( PQgetvalue ( res , i , i_nspacl ) ) ;
2000-09-18 03:24:03 +00:00
2002-05-10 22:36:27 +00:00
/* Decide whether to dump this namespace */
selectDumpableNamespace ( & nsinfo [ i ] ) ;
2000-09-18 03:24:03 +00:00
2002-05-10 22:36:27 +00:00
if ( strlen ( nsinfo [ i ] . usename ) = = 0 )
write_msg ( NULL , " WARNING: owner of namespace %s appears to be invalid \n " ,
nsinfo [ i ] . nspname ) ;
1997-09-07 05:04:48 +00:00
}
PQclear ( res ) ;
2001-08-03 19:43:05 +00:00
destroyPQExpBuffer ( query ) ;
2002-05-10 22:36:27 +00:00
g_namespaces = nsinfo ;
g_numNamespaces = * numNamespaces = ntups ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
return nsinfo ;
1997-06-02 02:52:06 +00:00
}
2002-05-10 22:36:27 +00:00
/*
* findNamespace :
* given a namespace OID and an object OID , look up the info read by
* getNamespaces
*
* NB : for pre - 7.3 source database , we use object OID to guess whether it ' s
* a system object or not . In 7.3 and later there is no guessing .
*/
static NamespaceInfo *
findNamespace ( const char * nsoid , const char * objoid )
1997-06-02 02:52:06 +00:00
{
2002-05-10 22:36:27 +00:00
int i ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
if ( g_fout - > remoteVersion > = 70300 )
1997-09-07 05:04:48 +00:00
{
2002-05-10 22:36:27 +00:00
for ( i = 0 ; i < g_numNamespaces ; i + + )
1997-09-07 05:04:48 +00:00
{
2002-05-10 22:36:27 +00:00
NamespaceInfo * nsinfo = & g_namespaces [ i ] ;
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
if ( strcmp ( nsoid , nsinfo - > oid ) = = 0 )
return nsinfo ;
2000-07-04 14:25:28 +00:00
}
2002-05-10 22:36:27 +00:00
write_msg ( NULL , " Failed to find namespace with OID %s. \n " , nsoid ) ;
exit_nicely ( ) ;
1997-09-07 05:04:48 +00:00
}
2002-05-10 22:36:27 +00:00
else
{
/* This code depends on the layout set up by getNamespaces. */
if ( atooid ( objoid ) > g_last_builtin_oid )
i = 0 ; /* user object */
else
i = 1 ; /* system object */
return & g_namespaces [ i ] ;
1997-09-07 05:04:48 +00:00
}
2002-05-10 22:36:27 +00:00
return NULL ; /* keep compiler quiet */
1997-06-02 02:52:06 +00:00
}
1996-07-09 06:22:35 +00:00
/*
2002-05-10 22:36:27 +00:00
* getTypes :
* read all types in the system catalogs and return them in the
* TypeInfo * structure
1996-07-09 06:22:35 +00:00
*
2002-05-10 22:36:27 +00:00
* numTypes is set to the number of types read in
1996-07-09 06:22:35 +00:00
*/
2002-05-10 22:36:27 +00:00
TypeInfo *
getTypes ( int * numTypes )
1996-07-09 06:22:35 +00:00
{
1999-05-25 16:15:34 +00:00
PGresult * res ;
1997-09-08 02:41:22 +00:00
int ntups ;
int i ;
2000-04-12 17:17:23 +00:00
PQExpBuffer query = createPQExpBuffer ( ) ;
2002-05-10 22:36:27 +00:00
TypeInfo * tinfo ;
1997-09-08 02:41:22 +00:00
int i_oid ;
2002-05-10 22:36:27 +00:00
int i_typname ;
int i_typnamespace ;
1997-09-08 02:41:22 +00:00
int i_usename ;
2002-05-10 22:36:27 +00:00
int i_typelem ;
int i_typrelid ;
2002-08-15 16:36:08 +00:00
int i_typrelkind ;
2002-05-10 22:36:27 +00:00
int i_typtype ;
int i_typisdefined ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
/*
* we include even the built - in types because those may be used as
* array elements by user - defined types
*
* we filter out the built - in types when we dump out the types
2002-06-13 20:02:31 +00:00
*
* same approach for undefined ( shell ) types
2002-05-10 22:36:27 +00:00
*/
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
/* Make sure we are in proper schema */
selectSourceSchema ( " pg_catalog " ) ;
if ( g_fout - > remoteVersion > = 70300 )
2001-10-25 05:50:21 +00:00
{
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( query , " SELECT pg_type.oid, typname, "
" typnamespace, "
" (select usename from pg_user where typowner = usesysid) as usename, "
2002-08-15 16:36:08 +00:00
" typelem, typrelid, "
" (select relkind from pg_class where oid = typrelid) as typrelkind, "
" typtype, typisdefined "
2002-05-10 22:36:27 +00:00
" FROM pg_type " ) ;
2001-04-25 07:03:20 +00:00
}
2002-04-11 20:00:18 +00:00
else
{
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( query , " SELECT pg_type.oid, typname, "
" 0::oid as typnamespace, "
" (select usename from pg_user where typowner = usesysid) as usename, "
2002-08-15 16:36:08 +00:00
" typelem, typrelid, "
" ''::char as typrelkind, "
" typtype, typisdefined "
2002-05-10 22:36:27 +00:00
" FROM pg_type " ) ;
2002-04-11 20:00:18 +00:00
}
1997-09-07 05:04:48 +00:00
1999-12-27 15:42:44 +00:00
res = PQexec ( g_conn , query - > data ) ;
1997-09-07 05:04:48 +00:00
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
2002-05-10 22:36:27 +00:00
write_msg ( NULL , " query to obtain list of data types failed: %s " , PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1997-09-07 05:04:48 +00:00
}
ntups = PQntuples ( res ) ;
2002-05-10 22:36:27 +00:00
tinfo = ( TypeInfo * ) malloc ( ntups * sizeof ( TypeInfo ) ) ;
1997-09-07 05:04:48 +00:00
i_oid = PQfnumber ( res , " oid " ) ;
2002-05-10 22:36:27 +00:00
i_typname = PQfnumber ( res , " typname " ) ;
i_typnamespace = PQfnumber ( res , " typnamespace " ) ;
1997-09-07 05:04:48 +00:00
i_usename = PQfnumber ( res , " usename " ) ;
2002-05-10 22:36:27 +00:00
i_typelem = PQfnumber ( res , " typelem " ) ;
i_typrelid = PQfnumber ( res , " typrelid " ) ;
2002-08-15 16:36:08 +00:00
i_typrelkind = PQfnumber ( res , " typrelkind " ) ;
2002-05-10 22:36:27 +00:00
i_typtype = PQfnumber ( res , " typtype " ) ;
i_typisdefined = PQfnumber ( res , " typisdefined " ) ;
1997-09-07 05:04:48 +00:00
for ( i = 0 ; i < ntups ; i + + )
{
2002-05-10 22:36:27 +00:00
tinfo [ i ] . oid = strdup ( PQgetvalue ( res , i , i_oid ) ) ;
tinfo [ i ] . typname = strdup ( PQgetvalue ( res , i , i_typname ) ) ;
tinfo [ i ] . typnamespace = findNamespace ( PQgetvalue ( res , i , i_typnamespace ) ,
tinfo [ i ] . oid ) ;
tinfo [ i ] . usename = strdup ( PQgetvalue ( res , i , i_usename ) ) ;
tinfo [ i ] . typelem = strdup ( PQgetvalue ( res , i , i_typelem ) ) ;
tinfo [ i ] . typrelid = strdup ( PQgetvalue ( res , i , i_typrelid ) ) ;
2002-08-15 16:36:08 +00:00
tinfo [ i ] . typrelkind = * PQgetvalue ( res , i , i_typrelkind ) ;
2002-05-10 22:36:27 +00:00
tinfo [ i ] . typtype = * PQgetvalue ( res , i , i_typtype ) ;
/*
* check for user - defined array types , omit system generated ones
*/
if ( ( strcmp ( tinfo [ i ] . typelem , " 0 " ) ! = 0 ) & &
tinfo [ i ] . typname [ 0 ] ! = ' _ ' )
tinfo [ i ] . isArray = true ;
else
tinfo [ i ] . isArray = false ;
2001-04-25 07:03:20 +00:00
2002-05-10 22:36:27 +00:00
if ( strcmp ( PQgetvalue ( res , i , i_typisdefined ) , " t " ) = = 0 )
tinfo [ i ] . isDefined = true ;
else
tinfo [ i ] . isDefined = false ;
2002-06-13 20:02:31 +00:00
if ( strlen ( tinfo [ i ] . usename ) = = 0 & & tinfo [ i ] . isDefined )
write_msg ( NULL , " WARNING: owner of data type %s appears to be invalid \n " ,
tinfo [ i ] . typname ) ;
1997-09-07 05:04:48 +00:00
}
2002-05-10 22:36:27 +00:00
* numTypes = ntups ;
1997-09-07 05:04:48 +00:00
PQclear ( res ) ;
2001-08-03 19:43:05 +00:00
destroyPQExpBuffer ( query ) ;
2002-05-10 22:36:27 +00:00
return tinfo ;
1996-07-09 06:22:35 +00:00
}
/*
2002-05-10 22:36:27 +00:00
* getOperators :
* read all operators in the system catalogs and return them in the
* OprInfo * structure
1996-07-09 06:22:35 +00:00
*
2002-05-10 22:36:27 +00:00
* numOprs is set to the number of operators read in
1996-07-09 06:22:35 +00:00
*/
2002-05-10 22:36:27 +00:00
OprInfo *
getOperators ( int * numOprs )
1996-07-09 06:22:35 +00:00
{
2000-04-12 17:17:23 +00:00
PGresult * res ;
1997-09-08 02:41:22 +00:00
int ntups ;
int i ;
2000-04-12 17:17:23 +00:00
PQExpBuffer query = createPQExpBuffer ( ) ;
2002-05-10 22:36:27 +00:00
OprInfo * oprinfo ;
1997-09-08 02:41:22 +00:00
int i_oid ;
2002-05-10 22:36:27 +00:00
int i_oprname ;
int i_oprnamespace ;
1997-09-08 02:41:22 +00:00
int i_usename ;
2002-05-10 22:36:27 +00:00
int i_oprcode ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
/*
* find all operators , including builtin operators ;
* we filter out system - defined operators at dump - out time .
*/
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
/* Make sure we are in proper schema */
selectSourceSchema ( " pg_catalog " ) ;
if ( g_fout - > remoteVersion > = 70300 )
2002-04-05 00:31:36 +00:00
{
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( query , " SELECT pg_operator.oid, oprname, "
" oprnamespace, "
" (select usename from pg_user where oprowner = usesysid) as usename, "
" oprcode::oid "
" from pg_operator " ) ;
2001-10-25 05:50:21 +00:00
}
else
{
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( query , " SELECT pg_operator.oid, oprname, "
" 0::oid as oprnamespace, "
" (select usename from pg_user where oprowner = usesysid) as usename, "
" oprcode::oid "
" from pg_operator " ) ;
2001-04-25 07:03:20 +00:00
}
1997-09-07 05:04:48 +00:00
1999-12-27 15:42:44 +00:00
res = PQexec ( g_conn , query - > data ) ;
1997-09-07 05:04:48 +00:00
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
2002-05-10 22:36:27 +00:00
write_msg ( NULL , " query to obtain list of operators failed: %s " , PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1997-09-07 05:04:48 +00:00
}
ntups = PQntuples ( res ) ;
2002-05-10 22:36:27 +00:00
* numOprs = ntups ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
oprinfo = ( OprInfo * ) malloc ( ntups * sizeof ( OprInfo ) ) ;
2000-01-16 03:54:58 +00:00
1997-09-07 05:04:48 +00:00
i_oid = PQfnumber ( res , " oid " ) ;
2002-05-10 22:36:27 +00:00
i_oprname = PQfnumber ( res , " oprname " ) ;
i_oprnamespace = PQfnumber ( res , " oprnamespace " ) ;
1997-09-07 05:04:48 +00:00
i_usename = PQfnumber ( res , " usename " ) ;
2002-05-10 22:36:27 +00:00
i_oprcode = PQfnumber ( res , " oprcode " ) ;
1997-09-07 05:04:48 +00:00
for ( i = 0 ; i < ntups ; i + + )
{
2002-05-10 22:36:27 +00:00
oprinfo [ i ] . oid = strdup ( PQgetvalue ( res , i , i_oid ) ) ;
oprinfo [ i ] . oprname = strdup ( PQgetvalue ( res , i , i_oprname ) ) ;
oprinfo [ i ] . oprnamespace = findNamespace ( PQgetvalue ( res , i , i_oprnamespace ) ,
oprinfo [ i ] . oid ) ;
oprinfo [ i ] . usename = strdup ( PQgetvalue ( res , i , i_usename ) ) ;
oprinfo [ i ] . oprcode = strdup ( PQgetvalue ( res , i , i_oprcode ) ) ;
2000-09-18 03:24:03 +00:00
2002-05-10 22:36:27 +00:00
if ( strlen ( oprinfo [ i ] . usename ) = = 0 )
write_msg ( NULL , " WARNING: owner of operator \" %s \" appears to be invalid \n " ,
oprinfo [ i ] . oprname ) ;
1997-09-07 05:04:48 +00:00
}
PQclear ( res ) ;
2001-08-03 19:43:05 +00:00
destroyPQExpBuffer ( query ) ;
1996-07-09 06:22:35 +00:00
2002-05-10 22:36:27 +00:00
return oprinfo ;
1996-07-09 06:22:35 +00:00
}
2002-07-30 21:56:04 +00:00
/*
* getOpclasses :
* read all opclasses in the system catalogs and return them in the
* OpclassInfo * structure
*
* numOpclasses is set to the number of opclasses read in
*/
OpclassInfo *
getOpclasses ( int * numOpclasses )
{
PGresult * res ;
int ntups ;
int i ;
PQExpBuffer query = createPQExpBuffer ( ) ;
OpclassInfo * opcinfo ;
int i_oid ;
int i_opcname ;
int i_opcnamespace ;
int i_usename ;
/*
* find all opclasses , including builtin opclasses ;
* we filter out system - defined opclasses at dump - out time .
*/
/* Make sure we are in proper schema */
selectSourceSchema ( " pg_catalog " ) ;
if ( g_fout - > remoteVersion > = 70300 )
{
appendPQExpBuffer ( query , " SELECT pg_opclass.oid, opcname, "
" opcnamespace, "
" (select usename from pg_user where opcowner = usesysid) as usename "
" from pg_opclass " ) ;
}
else
{
appendPQExpBuffer ( query , " SELECT pg_opclass.oid, opcname, "
" 0::oid as opcnamespace, "
" ''::name as usename "
" from pg_opclass " ) ;
}
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to obtain list of opclasses failed: %s " , PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
ntups = PQntuples ( res ) ;
* numOpclasses = ntups ;
opcinfo = ( OpclassInfo * ) malloc ( ntups * sizeof ( OpclassInfo ) ) ;
i_oid = PQfnumber ( res , " oid " ) ;
i_opcname = PQfnumber ( res , " opcname " ) ;
i_opcnamespace = PQfnumber ( res , " opcnamespace " ) ;
i_usename = PQfnumber ( res , " usename " ) ;
for ( i = 0 ; i < ntups ; i + + )
{
opcinfo [ i ] . oid = strdup ( PQgetvalue ( res , i , i_oid ) ) ;
opcinfo [ i ] . opcname = strdup ( PQgetvalue ( res , i , i_opcname ) ) ;
opcinfo [ i ] . opcnamespace = findNamespace ( PQgetvalue ( res , i , i_opcnamespace ) ,
opcinfo [ i ] . oid ) ;
opcinfo [ i ] . usename = strdup ( PQgetvalue ( res , i , i_usename ) ) ;
if ( g_fout - > remoteVersion > = 70300 )
{
if ( strlen ( opcinfo [ i ] . usename ) = = 0 )
write_msg ( NULL , " WARNING: owner of opclass \" %s \" appears to be invalid \n " ,
opcinfo [ i ] . opcname ) ;
}
}
PQclear ( res ) ;
destroyPQExpBuffer ( query ) ;
return opcinfo ;
}
1996-07-09 06:22:35 +00:00
/*
2002-05-10 22:36:27 +00:00
* getAggregates :
* read all the user - defined aggregates in the system catalogs and
* return them in the AggInfo * structure
1996-07-09 06:22:35 +00:00
*
2002-05-10 22:36:27 +00:00
* numAggs is set to the number of aggregates read in
1996-07-09 06:22:35 +00:00
*/
2002-05-10 22:36:27 +00:00
AggInfo *
getAggregates ( int * numAggs )
1996-07-09 06:22:35 +00:00
{
2000-04-12 17:17:23 +00:00
PGresult * res ;
1997-09-08 02:41:22 +00:00
int ntups ;
int i ;
2000-04-12 17:17:23 +00:00
PQExpBuffer query = createPQExpBuffer ( ) ;
2002-05-10 22:36:27 +00:00
AggInfo * agginfo ;
1997-09-08 02:41:22 +00:00
2002-05-10 22:36:27 +00:00
int i_oid ;
int i_aggname ;
int i_aggnamespace ;
2002-05-19 10:08:25 +00:00
int i_aggbasetype ;
1997-09-08 02:41:22 +00:00
int i_usename ;
2002-05-19 10:08:25 +00:00
int i_aggacl ;
2000-09-15 04:35:16 +00:00
2002-05-10 22:36:27 +00:00
/* Make sure we are in proper schema */
selectSourceSchema ( " pg_catalog " ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
/* find all user-defined aggregates */
if ( g_fout - > remoteVersion > = 70300 )
2001-08-10 18:57:42 +00:00
{
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( query , " SELECT pg_proc.oid, proname as aggname, "
" pronamespace as aggnamespace, "
2002-05-28 22:26:57 +00:00
" proargtypes[0] as aggbasetype, "
2002-05-19 10:08:25 +00:00
" (select usename from pg_user where proowner = usesysid) as usename, "
" proacl as aggacl "
2002-05-10 22:36:27 +00:00
" FROM pg_proc "
" WHERE proisagg "
" AND pronamespace != "
" (select oid from pg_namespace where nspname = 'pg_catalog') " ) ;
2001-10-25 05:50:21 +00:00
}
else
{
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( query , " SELECT pg_aggregate.oid, aggname, "
" 0::oid as aggnamespace, "
2002-05-28 22:26:57 +00:00
" aggbasetype, "
2002-05-19 10:08:25 +00:00
" (select usename from pg_user where aggowner = usesysid) as usename, "
2002-05-28 22:26:57 +00:00
" '{=X}' as aggacl "
2002-05-10 22:36:27 +00:00
" from pg_aggregate "
" where oid > '%u'::oid " ,
g_last_builtin_oid ) ;
2001-05-12 01:03:59 +00:00
}
1997-09-07 05:04:48 +00:00
1999-12-27 15:42:44 +00:00
res = PQexec ( g_conn , query - > data ) ;
1997-09-07 05:04:48 +00:00
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
2002-05-10 22:36:27 +00:00
write_msg ( NULL , " query to obtain list of aggregate functions failed: %s " ,
2001-06-27 21:21:37 +00:00
PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1997-09-07 05:04:48 +00:00
}
ntups = PQntuples ( res ) ;
2002-05-10 22:36:27 +00:00
* numAggs = ntups ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
agginfo = ( AggInfo * ) malloc ( ntups * sizeof ( AggInfo ) ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
i_oid = PQfnumber ( res , " oid " ) ;
i_aggname = PQfnumber ( res , " aggname " ) ;
i_aggnamespace = PQfnumber ( res , " aggnamespace " ) ;
2002-05-19 10:08:25 +00:00
i_aggbasetype = PQfnumber ( res , " aggbasetype " ) ;
1997-09-07 05:04:48 +00:00
i_usename = PQfnumber ( res , " usename " ) ;
2002-05-19 10:08:25 +00:00
i_aggacl = PQfnumber ( res , " aggacl " ) ;
1997-09-07 05:04:48 +00:00
for ( i = 0 ; i < ntups ; i + + )
{
2002-05-10 22:36:27 +00:00
agginfo [ i ] . oid = strdup ( PQgetvalue ( res , i , i_oid ) ) ;
agginfo [ i ] . aggname = strdup ( PQgetvalue ( res , i , i_aggname ) ) ;
agginfo [ i ] . aggnamespace = findNamespace ( PQgetvalue ( res , i , i_aggnamespace ) ,
agginfo [ i ] . oid ) ;
2002-05-19 10:08:25 +00:00
agginfo [ i ] . aggbasetype = strdup ( PQgetvalue ( res , i , i_aggbasetype ) ) ;
2002-05-10 22:36:27 +00:00
agginfo [ i ] . usename = strdup ( PQgetvalue ( res , i , i_usename ) ) ;
if ( strlen ( agginfo [ i ] . usename ) = = 0 )
write_msg ( NULL , " WARNING: owner of aggregate function \" %s \" appears to be invalid \n " ,
agginfo [ i ] . aggname ) ;
2002-05-19 10:08:25 +00:00
agginfo [ i ] . aggacl = strdup ( PQgetvalue ( res , i , i_aggacl ) ) ;
2002-05-28 22:26:57 +00:00
agginfo [ i ] . fmtbasetype = NULL ; /* computed when it's dumped */
2002-05-10 22:36:27 +00:00
}
1998-02-26 04:46:47 +00:00
2002-05-10 22:36:27 +00:00
PQclear ( res ) ;
1998-02-26 04:46:47 +00:00
2002-05-10 22:36:27 +00:00
destroyPQExpBuffer ( query ) ;
2001-04-04 06:47:30 +00:00
2002-05-10 22:36:27 +00:00
return agginfo ;
}
2001-04-04 06:47:30 +00:00
2002-05-10 22:36:27 +00:00
/*
* getFuncs :
* read all the user - defined functions in the system catalogs and
* return them in the FuncInfo * structure
*
* numFuncs is set to the number of functions read in
*/
FuncInfo *
getFuncs ( int * numFuncs )
{
PGresult * res ;
int ntups ;
int i ;
PQExpBuffer query = createPQExpBuffer ( ) ;
FuncInfo * finfo ;
1998-02-26 04:46:47 +00:00
2002-05-10 22:36:27 +00:00
int i_oid ;
int i_proname ;
int i_pronamespace ;
int i_usename ;
int i_prolang ;
int i_pronargs ;
int i_proargtypes ;
int i_prorettype ;
2002-05-19 10:08:25 +00:00
int i_proacl ;
1998-02-26 04:46:47 +00:00
2002-05-10 22:36:27 +00:00
/* Make sure we are in proper schema */
selectSourceSchema ( " pg_catalog " ) ;
1999-12-11 00:31:05 +00:00
2002-05-10 22:36:27 +00:00
/* find all user-defined funcs */
2000-01-10 17:14:46 +00:00
2002-05-10 22:36:27 +00:00
if ( g_fout - > remoteVersion > = 70300 )
{
appendPQExpBuffer ( query ,
" SELECT pg_proc.oid, proname, prolang, "
2002-05-19 10:08:25 +00:00
" pronargs, proargtypes, prorettype, proacl, "
2002-05-10 22:36:27 +00:00
" pronamespace, "
" (select usename from pg_user where proowner = usesysid) as usename "
" FROM pg_proc "
" WHERE NOT proisagg "
" AND pronamespace != "
" (select oid from pg_namespace where nspname = 'pg_catalog') " ) ;
}
else
{
appendPQExpBuffer ( query ,
" SELECT pg_proc.oid, proname, prolang, "
" pronargs, proargtypes, prorettype, "
2002-05-28 22:26:57 +00:00
" '{=X}' as proacl, "
2002-05-10 22:36:27 +00:00
" 0::oid as pronamespace, "
" (select usename from pg_user where proowner = usesysid) as usename "
" FROM pg_proc "
" where pg_proc.oid > '%u'::oid " ,
g_last_builtin_oid ) ;
}
2000-01-18 07:29:58 +00:00
2002-05-10 22:36:27 +00:00
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to obtain list of functions failed: %s " ,
PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
2001-01-12 15:41:29 +00:00
2002-05-10 22:36:27 +00:00
ntups = PQntuples ( res ) ;
1999-12-11 00:31:05 +00:00
2002-05-10 22:36:27 +00:00
* numFuncs = ntups ;
2000-11-27 20:51:40 +00:00
2002-05-10 22:36:27 +00:00
finfo = ( FuncInfo * ) malloc ( ntups * sizeof ( FuncInfo ) ) ;
2001-04-25 07:03:20 +00:00
2002-05-10 22:36:27 +00:00
memset ( ( char * ) finfo , 0 , ntups * sizeof ( FuncInfo ) ) ;
2000-11-27 20:51:40 +00:00
2002-05-10 22:36:27 +00:00
i_oid = PQfnumber ( res , " oid " ) ;
i_proname = PQfnumber ( res , " proname " ) ;
i_pronamespace = PQfnumber ( res , " pronamespace " ) ;
i_usename = PQfnumber ( res , " usename " ) ;
i_prolang = PQfnumber ( res , " prolang " ) ;
i_pronargs = PQfnumber ( res , " pronargs " ) ;
i_proargtypes = PQfnumber ( res , " proargtypes " ) ;
i_prorettype = PQfnumber ( res , " prorettype " ) ;
2002-05-19 10:08:25 +00:00
i_proacl = PQfnumber ( res , " proacl " ) ;
2000-11-27 20:51:40 +00:00
2002-05-10 22:36:27 +00:00
for ( i = 0 ; i < ntups ; i + + )
{
finfo [ i ] . oid = strdup ( PQgetvalue ( res , i , i_oid ) ) ;
finfo [ i ] . proname = strdup ( PQgetvalue ( res , i , i_proname ) ) ;
finfo [ i ] . pronamespace = findNamespace ( PQgetvalue ( res , i , i_pronamespace ) ,
finfo [ i ] . oid ) ;
finfo [ i ] . usename = strdup ( PQgetvalue ( res , i , i_usename ) ) ;
finfo [ i ] . lang = atooid ( PQgetvalue ( res , i , i_prolang ) ) ;
finfo [ i ] . prorettype = strdup ( PQgetvalue ( res , i , i_prorettype ) ) ;
2002-05-19 10:08:25 +00:00
finfo [ i ] . proacl = strdup ( PQgetvalue ( res , i , i_proacl ) ) ;
2002-05-10 22:36:27 +00:00
finfo [ i ] . nargs = atoi ( PQgetvalue ( res , i , i_pronargs ) ) ;
if ( finfo [ i ] . nargs = = 0 )
finfo [ i ] . argtypes = NULL ;
2000-11-27 20:51:40 +00:00
else
1997-10-02 13:57:07 +00:00
{
2002-05-10 22:36:27 +00:00
finfo [ i ] . argtypes = malloc ( finfo [ i ] . nargs * sizeof ( finfo [ i ] . argtypes [ 0 ] ) ) ;
parseNumericArray ( PQgetvalue ( res , i , i_proargtypes ) ,
finfo [ i ] . argtypes ,
finfo [ i ] . nargs ) ;
}
1998-02-26 04:46:47 +00:00
2002-05-10 22:36:27 +00:00
finfo [ i ] . dumped = false ;
2000-02-04 18:49:34 +00:00
2002-05-10 22:36:27 +00:00
if ( strlen ( finfo [ i ] . usename ) = = 0 )
write_msg ( NULL , " WARNING: owner of function \" %s \" appears to be invalid \n " ,
finfo [ i ] . proname ) ;
}
2000-02-04 18:49:34 +00:00
2002-05-10 22:36:27 +00:00
PQclear ( res ) ;
2000-02-04 18:49:34 +00:00
2002-05-10 22:36:27 +00:00
destroyPQExpBuffer ( query ) ;
2000-04-12 17:17:23 +00:00
2002-05-10 22:36:27 +00:00
return finfo ;
}
2000-04-12 17:17:23 +00:00
2002-05-10 22:36:27 +00:00
/*
* getTables
* read all the user - defined tables ( no indexes , no catalogs )
* in the system catalogs return them in the TableInfo * structure
*
* numTables is set to the number of tables read in
*/
TableInfo *
getTables ( int * numTables )
{
PGresult * res ;
int ntups ;
int i ;
PQExpBuffer query = createPQExpBuffer ( ) ;
PQExpBuffer delqry = createPQExpBuffer ( ) ;
PQExpBuffer lockquery = createPQExpBuffer ( ) ;
TableInfo * tblinfo ;
2001-01-12 04:32:07 +00:00
2002-05-10 22:36:27 +00:00
int i_reloid ;
int i_relname ;
int i_relnamespace ;
int i_relkind ;
int i_relacl ;
int i_usename ;
int i_relchecks ;
int i_reltriggers ;
int i_relhasindex ;
int i_relhasrules ;
int i_relhasoids ;
2001-01-12 04:32:07 +00:00
2002-05-10 22:36:27 +00:00
/* Make sure we are in proper schema */
selectSourceSchema ( " pg_catalog " ) ;
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
/*
* Find all the tables ( including views and sequences ) .
*
* We include system catalogs , so that we can work if a user table
* is defined to inherit from a system catalog ( pretty weird , but . . . )
*
* We ignore tables that are not type ' r ' ( ordinary relation ) or ' S '
* ( sequence ) or ' v ' ( view ) .
*
* Note : in this phase we should collect only a minimal amount of
* information about each table , basically just enough to decide if
* it is interesting .
*/
1999-01-21 22:53:37 +00:00
2002-05-10 22:36:27 +00:00
if ( g_fout - > remoteVersion > = 70300 )
{
appendPQExpBuffer ( query ,
" SELECT pg_class.oid, relname, relacl, relkind, "
" relnamespace, "
" (select usename from pg_user where relowner = usesysid) as usename, "
" relchecks, reltriggers, "
" relhasindex, relhasrules, relhasoids "
" from pg_class "
" where relkind in ('%c', '%c', '%c') "
" order by oid " ,
RELKIND_RELATION , RELKIND_SEQUENCE , RELKIND_VIEW ) ;
}
else if ( g_fout - > remoteVersion > = 70200 )
{
2002-08-15 16:36:08 +00:00
/* before 7.3 there were no type relations with relkind 'c' */
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( query ,
" SELECT pg_class.oid, relname, relacl, relkind, "
" 0::oid as relnamespace, "
" (select usename from pg_user where relowner = usesysid) as usename, "
" relchecks, reltriggers, "
" relhasindex, relhasrules, relhasoids "
" from pg_class "
" where relkind in ('%c', '%c', '%c') "
" order by oid " ,
RELKIND_RELATION , RELKIND_SEQUENCE , RELKIND_VIEW ) ;
}
else if ( g_fout - > remoteVersion > = 70100 )
{
/* all tables have oids in 7.1 */
appendPQExpBuffer ( query ,
" SELECT pg_class.oid, relname, relacl, relkind, "
" 0::oid as relnamespace, "
" (select usename from pg_user where relowner = usesysid) as usename, "
" relchecks, reltriggers, "
" relhasindex, relhasrules, 't'::bool as relhasoids "
" from pg_class "
" where relkind in ('%c', '%c', '%c') "
" order by oid " ,
RELKIND_RELATION , RELKIND_SEQUENCE , RELKIND_VIEW ) ;
}
else
{
/*
* Before 7.1 , view relkind was not set to ' v ' , so we must check
* if we have a view by looking for a rule in pg_rewrite .
*/
appendPQExpBuffer ( query ,
" SELECT c.oid, relname, relacl, "
" CASE WHEN relhasrules and relkind = 'r' "
" and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
" r.ev_class = c.oid AND r.ev_type = '1') "
" THEN '%c':: \" char \" "
" ELSE relkind END AS relkind, "
" 0::oid as relnamespace, "
" (select usename from pg_user where relowner = usesysid) as usename, "
" relchecks, reltriggers, "
" relhasindex, relhasrules, 't'::bool as relhasoids "
" from pg_class c "
" where relkind in ('%c', '%c') "
" order by oid " ,
RELKIND_VIEW ,
RELKIND_RELATION , RELKIND_SEQUENCE ) ;
}
2001-04-25 07:03:20 +00:00
2002-05-10 22:36:27 +00:00
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to obtain list of tables failed: %s " ,
PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
2001-04-25 07:03:20 +00:00
2002-05-10 22:36:27 +00:00
ntups = PQntuples ( res ) ;
2001-04-25 07:03:20 +00:00
2002-05-10 22:36:27 +00:00
* numTables = ntups ;
2000-04-12 17:17:23 +00:00
2002-05-10 22:36:27 +00:00
/*
* Extract data from result and lock dumpable tables . We do the
* locking before anything else , to minimize the window wherein a
* table could disappear under us .
*
* Note that we have to save info about all tables here , even when
* dumping only one , because we don ' t yet know which tables might be
* inheritance ancestors of the target table .
*/
tblinfo = ( TableInfo * ) malloc ( ntups * sizeof ( TableInfo ) ) ;
memset ( tblinfo , 0 , ntups * sizeof ( TableInfo ) ) ;
2000-02-04 18:49:34 +00:00
2002-05-10 22:36:27 +00:00
i_reloid = PQfnumber ( res , " oid " ) ;
i_relname = PQfnumber ( res , " relname " ) ;
i_relnamespace = PQfnumber ( res , " relnamespace " ) ;
i_relacl = PQfnumber ( res , " relacl " ) ;
i_relkind = PQfnumber ( res , " relkind " ) ;
i_usename = PQfnumber ( res , " usename " ) ;
i_relchecks = PQfnumber ( res , " relchecks " ) ;
i_reltriggers = PQfnumber ( res , " reltriggers " ) ;
i_relhasindex = PQfnumber ( res , " relhasindex " ) ;
i_relhasrules = PQfnumber ( res , " relhasrules " ) ;
i_relhasoids = PQfnumber ( res , " relhasoids " ) ;
1998-02-26 04:46:47 +00:00
2002-05-10 22:36:27 +00:00
for ( i = 0 ; i < ntups ; i + + )
{
tblinfo [ i ] . oid = strdup ( PQgetvalue ( res , i , i_reloid ) ) ;
tblinfo [ i ] . relname = strdup ( PQgetvalue ( res , i , i_relname ) ) ;
tblinfo [ i ] . relnamespace = findNamespace ( PQgetvalue ( res , i , i_relnamespace ) ,
tblinfo [ i ] . oid ) ;
tblinfo [ i ] . usename = strdup ( PQgetvalue ( res , i , i_usename ) ) ;
tblinfo [ i ] . relacl = strdup ( PQgetvalue ( res , i , i_relacl ) ) ;
tblinfo [ i ] . relkind = * ( PQgetvalue ( res , i , i_relkind ) ) ;
tblinfo [ i ] . hasindex = ( strcmp ( PQgetvalue ( res , i , i_relhasindex ) , " t " ) = = 0 ) ;
tblinfo [ i ] . hasrules = ( strcmp ( PQgetvalue ( res , i , i_relhasrules ) , " t " ) = = 0 ) ;
tblinfo [ i ] . hasoids = ( strcmp ( PQgetvalue ( res , i , i_relhasoids ) , " t " ) = = 0 ) ;
tblinfo [ i ] . ncheck = atoi ( PQgetvalue ( res , i , i_relchecks ) ) ;
tblinfo [ i ] . ntrig = atoi ( PQgetvalue ( res , i , i_reltriggers ) ) ;
2000-02-04 18:49:34 +00:00
2002-05-10 22:36:27 +00:00
/* other fields were zeroed above */
2000-01-18 18:09:02 +00:00
2002-05-10 22:36:27 +00:00
/*
* Decide whether we want to dump this table .
*/
selectDumpableTable ( & tblinfo [ i ] ) ;
tblinfo [ i ] . interesting = tblinfo [ i ] . dump ;
2000-04-12 17:17:23 +00:00
2002-05-10 22:36:27 +00:00
/*
* Read - lock target tables to make sure they aren ' t DROPPED or
* altered in schema before we get around to dumping them .
*
* Note that we don ' t explicitly lock parents of the target tables ;
* we assume our lock on the child is enough to prevent schema
* alterations to parent tables .
*
* NOTE : it ' d be kinda nice to lock views and sequences too , not only
* plain tables , but the backend doesn ' t presently allow that .
*/
if ( tblinfo [ i ] . dump & & tblinfo [ i ] . relkind = = RELKIND_RELATION )
{
PGresult * lres ;
2000-01-18 18:09:02 +00:00
2002-05-10 22:36:27 +00:00
resetPQExpBuffer ( lockquery ) ;
appendPQExpBuffer ( lockquery ,
" LOCK TABLE %s IN ACCESS SHARE MODE " ,
fmtQualifiedId ( tblinfo [ i ] . relnamespace - > nspname ,
tblinfo [ i ] . relname ) ) ;
lres = PQexec ( g_conn , lockquery - > data ) ;
if ( ! lres | | PQresultStatus ( lres ) ! = PGRES_COMMAND_OK )
{
write_msg ( NULL , " Attempt to lock table \" %s \" failed. %s " ,
tblinfo [ i ] . relname , PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
1997-10-02 13:57:07 +00:00
}
2002-05-10 22:36:27 +00:00
PQclear ( lres ) ;
1997-10-02 13:57:07 +00:00
}
2000-04-12 17:17:23 +00:00
2002-05-10 22:36:27 +00:00
/* Emit notice if join for owner failed */
if ( strlen ( tblinfo [ i ] . usename ) = = 0 )
write_msg ( NULL , " WARNING: owner of table \" %s \" appears to be invalid \n " ,
tblinfo [ i ] . relname ) ;
1997-09-07 05:04:48 +00:00
}
2002-05-10 22:36:27 +00:00
PQclear ( res ) ;
2001-08-03 19:43:05 +00:00
destroyPQExpBuffer ( query ) ;
destroyPQExpBuffer ( delqry ) ;
2002-01-11 23:21:55 +00:00
destroyPQExpBuffer ( lockquery ) ;
1996-07-09 06:22:35 +00:00
2001-08-03 19:43:05 +00:00
return tblinfo ;
1996-07-09 06:22:35 +00:00
}
/*
* getInherits
1997-09-07 05:04:48 +00:00
* read all the inheritance information
1996-07-09 06:22:35 +00:00
* from the system catalogs return them in the InhInfo * structure
*
2002-05-10 22:36:27 +00:00
* numInherits is set to the number of pairs read in
1996-07-09 06:22:35 +00:00
*/
2001-10-25 05:50:21 +00:00
InhInfo *
1996-07-09 06:22:35 +00:00
getInherits ( int * numInherits )
{
2000-04-12 17:17:23 +00:00
PGresult * res ;
1997-09-08 02:41:22 +00:00
int ntups ;
int i ;
2000-04-12 17:17:23 +00:00
PQExpBuffer query = createPQExpBuffer ( ) ;
InhInfo * inhinfo ;
1997-09-07 05:04:48 +00:00
1999-11-22 17:56:41 +00:00
int i_inhrelid ;
1997-09-08 02:41:22 +00:00
int i_inhparent ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
/* Make sure we are in proper schema */
selectSourceSchema ( " pg_catalog " ) ;
1997-09-07 05:04:48 +00:00
/* find all the inheritance information */
1999-12-27 15:42:44 +00:00
appendPQExpBuffer ( query , " SELECT inhrelid, inhparent from pg_inherits " ) ;
1997-09-07 05:04:48 +00:00
1999-12-27 15:42:44 +00:00
res = PQexec ( g_conn , query - > data ) ;
1997-09-07 05:04:48 +00:00
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " query to obtain inheritance relationships failed: %s " ,
PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1997-09-07 05:04:48 +00:00
}
ntups = PQntuples ( res ) ;
* numInherits = ntups ;
inhinfo = ( InhInfo * ) malloc ( ntups * sizeof ( InhInfo ) ) ;
1999-11-22 17:56:41 +00:00
i_inhrelid = PQfnumber ( res , " inhrelid " ) ;
1997-09-07 05:04:48 +00:00
i_inhparent = PQfnumber ( res , " inhparent " ) ;
for ( i = 0 ; i < ntups ; i + + )
{
1999-11-22 17:56:41 +00:00
inhinfo [ i ] . inhrelid = strdup ( PQgetvalue ( res , i , i_inhrelid ) ) ;
1997-09-07 05:04:48 +00:00
inhinfo [ i ] . inhparent = strdup ( PQgetvalue ( res , i , i_inhparent ) ) ;
}
PQclear ( res ) ;
2001-08-03 19:43:05 +00:00
destroyPQExpBuffer ( query ) ;
1997-09-07 05:04:48 +00:00
return inhinfo ;
1996-07-09 06:22:35 +00:00
}
/*
* getTableAttrs -
2002-05-10 22:36:27 +00:00
* for each interesting table , read its attributes types and names
1997-09-07 05:04:48 +00:00
*
1996-07-09 06:22:35 +00:00
* this is implemented in a very inefficient way right now , looping
1997-09-07 05:04:48 +00:00
* through the tblinfo and doing a join per table to find the attrs and their
1996-07-09 06:22:35 +00:00
* types
*
1997-09-07 05:04:48 +00:00
* modifies tblinfo
1996-07-09 06:22:35 +00:00
*/
void
1997-09-08 21:56:23 +00:00
getTableAttrs ( TableInfo * tblinfo , int numTables )
1996-07-09 06:22:35 +00:00
{
1997-09-08 02:41:22 +00:00
int i ,
j ;
2000-04-12 17:17:23 +00:00
PQExpBuffer q = createPQExpBuffer ( ) ;
1997-09-08 02:41:22 +00:00
int i_attname ;
2002-05-10 22:36:27 +00:00
int i_atttypname ;
1998-01-16 23:21:07 +00:00
int i_atttypmod ;
2002-07-31 17:19:54 +00:00
int i_attstattarget ;
1997-09-08 02:41:22 +00:00
int i_attnotnull ;
1997-10-02 13:57:07 +00:00
int i_atthasdef ;
2002-08-02 18:15:10 +00:00
int i_attisdropped ;
2000-04-12 17:17:23 +00:00
PGresult * res ;
1997-09-08 02:41:22 +00:00
int ntups ;
2002-05-10 22:36:27 +00:00
bool hasdefaults ;
1997-09-07 05:04:48 +00:00
for ( i = 0 ; i < numTables ; i + + )
{
2002-05-10 22:36:27 +00:00
/* Don't bother to collect info for sequences */
2002-04-24 02:44:19 +00:00
if ( tblinfo [ i ] . relkind = = RELKIND_SEQUENCE )
1997-09-07 05:04:48 +00:00
continue ;
2002-08-15 16:36:08 +00:00
/* Don't bother to collect info for type relations */
if ( tblinfo [ i ] . relkind = = RELKIND_COMPOSITE_TYPE )
continue ;
2002-05-10 22:36:27 +00:00
/* Don't bother with uninteresting tables, either */
if ( ! tblinfo [ i ] . interesting )
continue ;
/*
* Make sure we are in proper schema for this table ; this allows
* correct retrieval of formatted type names and default exprs
*/
selectSourceSchema ( tblinfo [ i ] . relnamespace - > nspname ) ;
1997-09-07 05:04:48 +00:00
/* find all the user attributes and their types */
/*
2002-05-10 22:36:27 +00:00
* we must read the attribute names in attribute number order !
1997-09-07 05:04:48 +00:00
* because we will use the attnum to index into the attnames array
2002-05-10 22:36:27 +00:00
* later . We actually ask to order by " attrelid, attnum " because
* ( at least up to 7.3 ) the planner is not smart enough to realize
* it needn ' t re - sort the output of an indexscan on
* pg_attribute_relid_attnum_index .
1997-09-07 05:04:48 +00:00
*/
if ( g_verbose )
2001-07-03 20:21:50 +00:00
write_msg ( NULL , " finding the columns and types for table %s \n " ,
tblinfo [ i ] . relname ) ;
1997-09-07 05:04:48 +00:00
1999-12-27 15:42:44 +00:00
resetPQExpBuffer ( q ) ;
2001-04-25 07:03:20 +00:00
2002-05-28 22:26:57 +00:00
if ( g_fout - > remoteVersion > = 70300 )
{
2002-07-31 17:19:54 +00:00
appendPQExpBuffer ( q , " SELECT attnum, attname, atttypmod, attstattarget, "
2002-08-02 18:15:10 +00:00
" attnotnull, atthasdef, attisdropped, "
2002-05-28 22:26:57 +00:00
" pg_catalog.format_type(atttypid,atttypmod) as atttypname "
" from pg_catalog.pg_attribute a "
" where attrelid = '%s'::pg_catalog.oid "
" and attnum > 0::pg_catalog.int2 "
" order by attrelid, attnum " ,
tblinfo [ i ] . oid ) ;
}
else if ( g_fout - > remoteVersion > = 70100 )
2001-04-25 07:03:20 +00:00
{
2002-07-31 17:19:54 +00:00
/*
* attstattarget doesn ' t exist in 7.1 . It does exist in 7.2 ,
* but we don ' t dump it because we can ' t tell whether it ' s been
* explicitly set or was just a default .
*/
appendPQExpBuffer ( q , " SELECT attnum, attname, atttypmod, -1 as attstattarget, "
2002-08-02 18:15:10 +00:00
" attnotnull, atthasdef, false as attisdropped, "
2002-05-10 22:36:27 +00:00
" format_type(atttypid,atttypmod) as atttypname "
" from pg_attribute a "
" where attrelid = '%s'::oid "
" and attnum > 0::int2 "
" order by attrelid, attnum " ,
tblinfo [ i ] . oid ) ;
2001-10-25 05:50:21 +00:00
}
else
{
2002-05-10 22:36:27 +00:00
/* format_type not available before 7.1 */
2002-07-31 17:19:54 +00:00
appendPQExpBuffer ( q , " SELECT attnum, attname, atttypmod, -1 as attstattarget, "
2002-08-02 18:15:10 +00:00
" attnotnull, atthasdef, false as attisdropped, "
2002-05-10 22:36:27 +00:00
" (select typname from pg_type where oid = atttypid) as atttypname "
" from pg_attribute a "
" where attrelid = '%s'::oid "
" and attnum > 0::int2 "
" order by attrelid, attnum " ,
2001-10-25 05:50:21 +00:00
tblinfo [ i ] . oid ) ;
2001-04-25 07:03:20 +00:00
}
1999-12-27 15:42:44 +00:00
res = PQexec ( g_conn , q - > data ) ;
1997-09-07 05:04:48 +00:00
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " query to get table columns failed: %s " , PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1997-09-07 05:04:48 +00:00
}
ntups = PQntuples ( res ) ;
i_attname = PQfnumber ( res , " attname " ) ;
2002-05-10 22:36:27 +00:00
i_atttypname = PQfnumber ( res , " atttypname " ) ;
1998-01-16 23:21:07 +00:00
i_atttypmod = PQfnumber ( res , " atttypmod " ) ;
2002-07-31 17:19:54 +00:00
i_attstattarget = PQfnumber ( res , " attstattarget " ) ;
1997-09-07 05:04:48 +00:00
i_attnotnull = PQfnumber ( res , " attnotnull " ) ;
1997-10-02 13:57:07 +00:00
i_atthasdef = PQfnumber ( res , " atthasdef " ) ;
2002-08-02 18:15:10 +00:00
i_attisdropped = PQfnumber ( res , " attisdropped " ) ;
1997-09-07 05:04:48 +00:00
tblinfo [ i ] . numatts = ntups ;
tblinfo [ i ] . attnames = ( char * * ) malloc ( ntups * sizeof ( char * ) ) ;
2002-05-10 22:36:27 +00:00
tblinfo [ i ] . atttypnames = ( char * * ) malloc ( ntups * sizeof ( char * ) ) ;
1998-01-16 23:21:07 +00:00
tblinfo [ i ] . atttypmod = ( int * ) malloc ( ntups * sizeof ( int ) ) ;
2002-07-31 17:19:54 +00:00
tblinfo [ i ] . attstattarget = ( int * ) malloc ( ntups * sizeof ( int ) ) ;
2002-08-02 18:15:10 +00:00
tblinfo [ i ] . attisdropped = ( bool * ) malloc ( ntups * sizeof ( bool ) ) ;
1997-09-07 05:04:48 +00:00
tblinfo [ i ] . notnull = ( bool * ) malloc ( ntups * sizeof ( bool ) ) ;
1997-10-02 13:57:07 +00:00
tblinfo [ i ] . adef_expr = ( char * * ) malloc ( ntups * sizeof ( char * ) ) ;
2002-05-10 22:36:27 +00:00
tblinfo [ i ] . inhAttrs = ( bool * ) malloc ( ntups * sizeof ( bool ) ) ;
tblinfo [ i ] . inhAttrDef = ( bool * ) malloc ( ntups * sizeof ( bool ) ) ;
tblinfo [ i ] . inhNotNull = ( bool * ) malloc ( ntups * sizeof ( bool ) ) ;
hasdefaults = false ;
1997-09-07 05:04:48 +00:00
for ( j = 0 ; j < ntups ; j + + )
{
tblinfo [ i ] . attnames [ j ] = strdup ( PQgetvalue ( res , j , i_attname ) ) ;
2002-05-10 22:36:27 +00:00
tblinfo [ i ] . atttypnames [ j ] = strdup ( PQgetvalue ( res , j , i_atttypname ) ) ;
1998-01-16 23:21:07 +00:00
tblinfo [ i ] . atttypmod [ j ] = atoi ( PQgetvalue ( res , j , i_atttypmod ) ) ;
2002-07-31 17:19:54 +00:00
tblinfo [ i ] . attstattarget [ j ] = atoi ( PQgetvalue ( res , j , i_attstattarget ) ) ;
2002-08-02 18:15:10 +00:00
tblinfo [ i ] . attisdropped [ j ] = ( PQgetvalue ( res , j , i_attisdropped ) [ 0 ] = = ' t ' ) ;
2002-05-10 22:36:27 +00:00
tblinfo [ i ] . notnull [ j ] = ( PQgetvalue ( res , j , i_attnotnull ) [ 0 ] = = ' t ' ) ;
tblinfo [ i ] . adef_expr [ j ] = NULL ; /* fix below */
1997-10-02 13:57:07 +00:00
if ( PQgetvalue ( res , j , i_atthasdef ) [ 0 ] = = ' t ' )
2002-05-10 22:36:27 +00:00
hasdefaults = true ;
/* these flags will be set in flagInhAttrs() */
tblinfo [ i ] . inhAttrs [ j ] = false ;
tblinfo [ i ] . inhAttrDef [ j ] = false ;
tblinfo [ i ] . inhNotNull [ j ] = false ;
}
1998-02-26 04:46:47 +00:00
2002-05-10 22:36:27 +00:00
PQclear ( res ) ;
1998-02-26 04:46:47 +00:00
2002-05-10 22:36:27 +00:00
if ( hasdefaults )
{
int numDefaults ;
if ( g_verbose )
write_msg ( NULL , " finding DEFAULT expressions for table %s \n " ,
tblinfo [ i ] . relname ) ;
resetPQExpBuffer ( q ) ;
2002-05-28 22:26:57 +00:00
if ( g_fout - > remoteVersion > = 70300 )
{
appendPQExpBuffer ( q , " SELECT adnum, "
" pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
" FROM pg_catalog.pg_attrdef "
" WHERE adrelid = '%s'::pg_catalog.oid " ,
tblinfo [ i ] . oid ) ;
}
else if ( g_fout - > remoteVersion > = 70200 )
2002-05-10 22:36:27 +00:00
{
appendPQExpBuffer ( q , " SELECT adnum, "
" pg_get_expr(adbin, adrelid) AS adsrc "
" FROM pg_attrdef "
" WHERE adrelid = '%s'::oid " ,
tblinfo [ i ] . oid ) ;
}
else
{
/* no pg_get_expr, so must rely on adsrc */
appendPQExpBuffer ( q , " SELECT adnum, adsrc FROM pg_attrdef "
" WHERE adrelid = '%s'::oid " ,
tblinfo [ i ] . oid ) ;
}
res = PQexec ( g_conn , q - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to get column default values failed: %s " ,
PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
2001-01-12 04:32:07 +00:00
2002-05-10 22:36:27 +00:00
numDefaults = PQntuples ( res ) ;
for ( j = 0 ; j < numDefaults ; j + + )
{
int adnum = atoi ( PQgetvalue ( res , j , 0 ) ) ;
if ( adnum < = 0 | | adnum > ntups )
2001-03-22 04:01:46 +00:00
{
2002-05-10 22:36:27 +00:00
write_msg ( NULL , " bogus adnum value %d for table %s \n " ,
adnum , tblinfo [ i ] . relname ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
2001-01-12 04:32:07 +00:00
}
2002-05-10 22:36:27 +00:00
tblinfo [ i ] . adef_expr [ adnum - 1 ] = strdup ( PQgetvalue ( res , j , 1 ) ) ;
1997-10-02 13:57:07 +00:00
}
2002-05-10 22:36:27 +00:00
PQclear ( res ) ;
1997-09-07 05:04:48 +00:00
}
}
2001-08-03 19:43:05 +00:00
destroyPQExpBuffer ( q ) ;
1996-07-09 06:22:35 +00:00
}
/*
2001-08-10 18:57:42 +00:00
* dumpComment - -
2000-01-18 18:09:02 +00:00
*
2000-04-12 17:17:23 +00:00
* This routine is used to dump any comments associated with the
2000-01-18 18:09:02 +00:00
* oid handed to this routine . The routine takes a constant character
2001-08-10 18:57:42 +00:00
* string for the target part of the comment - creation command , plus
2002-05-10 22:36:27 +00:00
* the namespace and owner of the object ( for labeling the ArchiveEntry ) ,
* plus OID , class name , and subid which are the lookup key for pg_description .
2001-08-10 18:57:42 +00:00
* If a matching pg_description entry is found , it is dumped .
* Additional dependencies can be passed for the comment , too - - - this is
* needed for VIEWs , whose comments are filed under the table OID but
* which are dumped in order by their rule OID .
2002-05-10 22:36:27 +00:00
*/
2000-01-18 18:09:02 +00:00
2000-04-14 01:34:24 +00:00
static void
2002-05-10 22:36:27 +00:00
dumpComment ( Archive * fout , const char * target ,
const char * namespace , const char * owner ,
const char * oid , const char * classname , int subid ,
2001-08-03 19:43:05 +00:00
const char * ( ( * deps ) [ ] ) )
2000-04-12 17:17:23 +00:00
{
PGresult * res ;
2000-01-18 18:09:02 +00:00
PQExpBuffer query ;
2000-04-12 17:17:23 +00:00
int i_description ;
2000-01-18 18:09:02 +00:00
2001-05-12 01:03:59 +00:00
/* Comments are SCHEMA not data */
if ( dataOnly )
return ;
2002-05-10 22:36:27 +00:00
/*
* Note we do NOT change source schema here ; preserve the caller ' s
* setting , instead .
*/
2000-01-18 18:09:02 +00:00
/*** Build query to find comment ***/
query = createPQExpBuffer ( ) ;
2001-08-10 18:57:42 +00:00
2002-05-10 22:36:27 +00:00
if ( fout - > remoteVersion > = 70300 )
{
appendPQExpBuffer ( query , " SELECT description FROM pg_catalog.pg_description "
2002-05-28 22:26:57 +00:00
" WHERE objoid = '%s'::pg_catalog.oid and classoid = "
" 'pg_catalog.%s'::pg_catalog.regclass "
2002-05-10 22:36:27 +00:00
" and objsubid = %d " ,
oid , classname , subid ) ;
}
else if ( fout - > remoteVersion > = 70200 )
2001-08-10 18:57:42 +00:00
{
appendPQExpBuffer ( query , " SELECT description FROM pg_description "
2001-09-07 01:11:50 +00:00
" WHERE objoid = '%s'::oid and classoid = "
2001-10-25 05:50:21 +00:00
" (SELECT oid FROM pg_class where relname = '%s') "
2001-08-10 18:57:42 +00:00
" and objsubid = %d " ,
oid , classname , subid ) ;
}
else
{
/* Note: this will fail to find attribute comments in pre-7.2... */
2001-09-07 01:11:50 +00:00
appendPQExpBuffer ( query , " SELECT description FROM pg_description WHERE objoid = '%s'::oid " , oid ) ;
2001-08-10 18:57:42 +00:00
}
2000-01-18 18:09:02 +00:00
/*** Execute query ***/
res = PQexec ( g_conn , query - > data ) ;
2000-04-12 17:17:23 +00:00
if ( ! res | | PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " query to get comment on oid %s failed: %s " ,
2001-10-25 05:50:21 +00:00
oid , PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
2000-01-18 18:09:02 +00:00
}
/*** If a comment exists, build COMMENT ON statement ***/
2001-08-10 18:57:42 +00:00
if ( PQntuples ( res ) = = 1 )
2000-04-12 17:17:23 +00:00
{
2000-01-18 18:09:02 +00:00
i_description = PQfnumber ( res , " description " ) ;
2000-07-04 14:25:28 +00:00
resetPQExpBuffer ( query ) ;
2001-01-04 01:23:47 +00:00
appendPQExpBuffer ( query , " COMMENT ON %s IS " , target ) ;
2001-08-10 18:57:42 +00:00
formatStringLiteral ( query , PQgetvalue ( res , 0 , i_description ) ,
PASS_LFTAB ) ;
2001-01-04 01:23:47 +00:00
appendPQExpBuffer ( query , " ; \n " ) ;
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
ArchiveEntry ( fout , oid , target , namespace , owner ,
" COMMENT " , deps ,
query - > data , " " , NULL , NULL , NULL ) ;
}
PQclear ( res ) ;
destroyPQExpBuffer ( query ) ;
}
/*
* dumpTableComment - -
*
* As above , but dump comments for both the specified table ( or view )
* and its columns . For speed , we want to do this with only one query .
*/
static void
dumpTableComment ( Archive * fout , TableInfo * tbinfo ,
const char * reltypename ,
const char * ( ( * deps ) [ ] ) )
{
PGresult * res ;
PQExpBuffer query ;
PQExpBuffer target ;
int i_description ;
int i_objsubid ;
int ntups ;
int i ;
/* Comments are SCHEMA not data */
if ( dataOnly )
return ;
/*
* Note we do NOT change source schema here ; preserve the caller ' s
* setting , instead .
*/
/*** Build query to find comments ***/
query = createPQExpBuffer ( ) ;
target = createPQExpBuffer ( ) ;
if ( fout - > remoteVersion > = 70300 )
{
appendPQExpBuffer ( query , " SELECT description, objsubid FROM pg_catalog.pg_description "
2002-05-28 22:26:57 +00:00
" WHERE objoid = '%s'::pg_catalog.oid and classoid = "
" 'pg_catalog.pg_class'::pg_catalog.regclass "
2002-05-10 22:36:27 +00:00
" ORDER BY objoid, classoid, objsubid " ,
tbinfo - > oid ) ;
}
else if ( fout - > remoteVersion > = 70200 )
{
appendPQExpBuffer ( query , " SELECT description, objsubid FROM pg_description "
" WHERE objoid = '%s'::oid and classoid = "
" (SELECT oid FROM pg_class where relname = 'pg_class') "
" ORDER BY objoid, classoid, objsubid " ,
tbinfo - > oid ) ;
}
else
{
/* Note: this will fail to find attribute comments in pre-7.2... */
appendPQExpBuffer ( query , " SELECT description, 0 as objsubid FROM pg_description WHERE objoid = '%s'::oid " , tbinfo - > oid ) ;
}
/*** Execute query ***/
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | | PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to get comments on table %s failed: %s " ,
tbinfo - > relname , PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
i_description = PQfnumber ( res , " description " ) ;
i_objsubid = PQfnumber ( res , " objsubid " ) ;
/*** If comments exist, build COMMENT ON statements ***/
ntups = PQntuples ( res ) ;
for ( i = 0 ; i < ntups ; i + + )
{
const char * descr = PQgetvalue ( res , i , i_description ) ;
int objsubid = atoi ( PQgetvalue ( res , i , i_objsubid ) ) ;
if ( objsubid = = 0 )
{
resetPQExpBuffer ( target ) ;
appendPQExpBuffer ( target , " %s %s " , reltypename ,
fmtId ( tbinfo - > relname , force_quotes ) ) ;
resetPQExpBuffer ( query ) ;
appendPQExpBuffer ( query , " COMMENT ON %s IS " , target - > data ) ;
formatStringLiteral ( query , descr , PASS_LFTAB ) ;
appendPQExpBuffer ( query , " ; \n " ) ;
ArchiveEntry ( fout , tbinfo - > oid , target - > data ,
tbinfo - > relnamespace - > nspname , tbinfo - > usename ,
" COMMENT " , deps ,
query - > data , " " , NULL , NULL , NULL ) ;
}
else if ( objsubid > 0 & & objsubid < = tbinfo - > numatts )
{
resetPQExpBuffer ( target ) ;
appendPQExpBuffer ( target , " COLUMN %s. " ,
fmtId ( tbinfo - > relname , force_quotes ) ) ;
appendPQExpBuffer ( target , " %s " ,
fmtId ( tbinfo - > attnames [ objsubid - 1 ] ,
force_quotes ) ) ;
2000-01-18 18:09:02 +00:00
2002-05-10 22:36:27 +00:00
resetPQExpBuffer ( query ) ;
appendPQExpBuffer ( query , " COMMENT ON %s IS " , target - > data ) ;
formatStringLiteral ( query , descr , PASS_LFTAB ) ;
appendPQExpBuffer ( query , " ; \n " ) ;
ArchiveEntry ( fout , tbinfo - > oid , target - > data ,
tbinfo - > relnamespace - > nspname , tbinfo - > usename ,
" COMMENT " , deps ,
query - > data , " " , NULL , NULL , NULL ) ;
}
}
2000-01-18 18:09:02 +00:00
PQclear ( res ) ;
2001-08-03 19:43:05 +00:00
destroyPQExpBuffer ( query ) ;
2002-05-10 22:36:27 +00:00
destroyPQExpBuffer ( target ) ;
2000-01-18 18:09:02 +00:00
}
2002-05-10 22:36:27 +00:00
/*
2000-04-12 17:17:23 +00:00
* dumpDBComment - -
2000-01-18 18:09:02 +00:00
*
2000-04-12 17:17:23 +00:00
* This routine is used to dump any comments associated with the
2002-05-28 22:26:57 +00:00
* database to which we are currently connected .
2002-05-10 22:36:27 +00:00
*/
2000-04-12 17:17:23 +00:00
void
2000-07-04 14:25:28 +00:00
dumpDBComment ( Archive * fout )
2000-04-12 17:17:23 +00:00
{
PGresult * res ;
2000-01-18 18:09:02 +00:00
PQExpBuffer query ;
2000-04-12 17:17:23 +00:00
int i_oid ;
2000-01-18 18:09:02 +00:00
2002-05-10 22:36:27 +00:00
/* Make sure we are in proper schema */
selectSourceSchema ( " pg_catalog " ) ;
2000-01-18 18:09:02 +00:00
/*** Build query to find comment ***/
query = createPQExpBuffer ( ) ;
2001-01-04 01:23:47 +00:00
appendPQExpBuffer ( query , " SELECT oid FROM pg_database WHERE datname = " ) ;
2001-02-13 01:31:54 +00:00
formatStringLiteral ( query , PQdb ( g_conn ) , CONV_ALL ) ;
2000-01-18 18:09:02 +00:00
/*** Execute query ***/
res = PQexec ( g_conn , query - > data ) ;
2000-04-12 17:17:23 +00:00
if ( ! res | | PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " query to get database oid failed: %s " ,
2001-10-25 05:50:21 +00:00
PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
2000-01-18 18:09:02 +00:00
}
/*** If a comment exists, build COMMENT ON statement ***/
2000-04-12 17:17:23 +00:00
if ( PQntuples ( res ) ! = 0 )
{
2000-01-18 18:09:02 +00:00
i_oid = PQfnumber ( res , " oid " ) ;
resetPQExpBuffer ( query ) ;
appendPQExpBuffer ( query , " DATABASE %s " , fmtId ( PQdb ( g_conn ) , force_quotes ) ) ;
2002-05-10 22:36:27 +00:00
dumpComment ( fout , query - > data , NULL , " " ,
PQgetvalue ( res , 0 , i_oid ) , " pg_database " , 0 , NULL ) ;
}
PQclear ( res ) ;
destroyPQExpBuffer ( query ) ;
}
/*
* dumpNamespaces
* writes out to fout the queries to recreate user - defined namespaces
*/
void
dumpNamespaces ( Archive * fout , NamespaceInfo * nsinfo , int numNamespaces )
{
PQExpBuffer q = createPQExpBuffer ( ) ;
PQExpBuffer delq = createPQExpBuffer ( ) ;
int i ;
2002-05-28 22:26:57 +00:00
char * qnspname ;
2002-05-10 22:36:27 +00:00
for ( i = 0 ; i < numNamespaces ; i + + )
{
2002-05-28 22:26:57 +00:00
NamespaceInfo * nspinfo = & nsinfo [ i ] ;
2002-05-10 22:36:27 +00:00
/* skip if not to be dumped */
2002-05-28 22:26:57 +00:00
if ( ! nspinfo - > dump )
2002-05-10 22:36:27 +00:00
continue ;
/* don't dump dummy namespace from pre-7.3 source */
2002-05-28 22:26:57 +00:00
if ( strlen ( nspinfo - > nspname ) = = 0 )
2002-05-10 22:36:27 +00:00
continue ;
2002-05-28 22:26:57 +00:00
qnspname = strdup ( fmtId ( nspinfo - > nspname , force_quotes ) ) ;
2002-05-10 22:36:27 +00:00
2002-05-28 22:26:57 +00:00
/*
* If it ' s the PUBLIC namespace , don ' t emit a CREATE SCHEMA
* record for it , since we expect PUBLIC to exist already in
* the destination database . And emit ACL info only if the ACL
* isn ' t the standard value for PUBLIC .
*/
if ( strcmp ( nspinfo - > nspname , " public " ) = = 0 )
{
if ( ! aclsSkip & & strcmp ( nspinfo - > nspacl , " {=UC} " ) ! = 0 )
2002-07-04 03:04:55 +00:00
dumpACL ( fout , " SCHEMA " , qnspname , nspinfo - > nspname , NULL ,
2002-05-28 22:26:57 +00:00
nspinfo - > usename , nspinfo - > nspacl ,
nspinfo - > oid ) ;
}
else
{
resetPQExpBuffer ( q ) ;
resetPQExpBuffer ( delq ) ;
2002-05-10 22:36:27 +00:00
2002-05-28 22:26:57 +00:00
appendPQExpBuffer ( delq , " DROP SCHEMA %s; \n " , qnspname ) ;
2002-05-10 22:36:27 +00:00
2002-05-28 22:26:57 +00:00
appendPQExpBuffer ( q , " CREATE SCHEMA %s; \n " , qnspname ) ;
2002-05-10 22:36:27 +00:00
2002-05-28 22:26:57 +00:00
ArchiveEntry ( fout , nspinfo - > oid , nspinfo - > nspname ,
NULL ,
nspinfo - > usename , " SCHEMA " , NULL ,
q - > data , delq - > data , NULL , NULL , NULL ) ;
2002-05-10 22:36:27 +00:00
2002-05-28 22:26:57 +00:00
/*** Dump Schema Comments ***/
resetPQExpBuffer ( q ) ;
appendPQExpBuffer ( q , " SCHEMA %s " , qnspname ) ;
dumpComment ( fout , q - > data ,
NULL , nspinfo - > usename ,
nspinfo - > oid , " pg_namespace " , 0 , NULL ) ;
if ( ! aclsSkip )
2002-07-04 03:04:55 +00:00
dumpACL ( fout , " SCHEMA " , qnspname , nspinfo - > nspname , NULL ,
2002-05-28 22:26:57 +00:00
nspinfo - > usename , nspinfo - > nspacl ,
nspinfo - > oid ) ;
}
free ( qnspname ) ;
2002-05-10 22:36:27 +00:00
}
destroyPQExpBuffer ( q ) ;
destroyPQExpBuffer ( delq ) ;
}
/*
* dumpOneBaseType
* writes out to fout the queries to recreate a user - defined base type
* as requested by dumpTypes
*/
static void
dumpOneBaseType ( Archive * fout , TypeInfo * tinfo ,
FuncInfo * g_finfo , int numFuncs ,
TypeInfo * g_tinfo , int numTypes )
{
PQExpBuffer q = createPQExpBuffer ( ) ;
PQExpBuffer delq = createPQExpBuffer ( ) ;
PQExpBuffer query = createPQExpBuffer ( ) ;
PGresult * res ;
int ntups ;
int funcInd ;
char * typlen ;
char * typinput ;
char * typoutput ;
char * typinputoid ;
char * typoutputoid ;
char * typdelim ;
char * typdefault ;
char * typbyval ;
char * typalign ;
char * typstorage ;
const char * ( ( * deps ) [ ] ) ;
int depIdx = 0 ;
deps = malloc ( sizeof ( char * ) * 10 ) ;
/* Set proper schema search path so regproc references list correctly */
selectSourceSchema ( tinfo - > typnamespace - > nspname ) ;
/* Fetch type-specific details */
2002-05-28 22:26:57 +00:00
if ( fout - > remoteVersion > = 70300 )
{
2002-07-24 19:11:14 +00:00
appendPQExpBuffer ( query , " SELECT typlen, "
" typinput, typoutput, "
2002-05-28 22:26:57 +00:00
" typinput::pg_catalog.oid as typinputoid, "
" typoutput::pg_catalog.oid as typoutputoid, "
" typdelim, typdefault, typbyval, typalign, "
" typstorage "
" FROM pg_catalog.pg_type "
" WHERE oid = '%s'::pg_catalog.oid " ,
tinfo - > oid ) ;
}
else if ( fout - > remoteVersion > = 70100 )
2002-05-10 22:36:27 +00:00
{
2002-07-24 19:11:14 +00:00
appendPQExpBuffer ( query , " SELECT typlen, "
" typinput, typoutput, "
2002-05-10 22:36:27 +00:00
" typinput::oid as typinputoid, "
" typoutput::oid as typoutputoid, "
" typdelim, typdefault, typbyval, typalign, "
" typstorage "
" FROM pg_type "
" WHERE oid = '%s'::oid " ,
tinfo - > oid ) ;
}
else
{
2002-07-24 19:11:14 +00:00
appendPQExpBuffer ( query , " SELECT typlen, "
" typinput, typoutput, "
2002-05-10 22:36:27 +00:00
" typinput::oid as typinputoid, "
" typoutput::oid as typoutputoid, "
" typdelim, typdefault, typbyval, typalign, "
" 'p'::char as typstorage "
" FROM pg_type "
" WHERE oid = '%s'::oid " ,
tinfo - > oid ) ;
}
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to obtain type information for %s failed: %s " ,
tinfo - > typname , PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
/* Expecting a single result only */
ntups = PQntuples ( res ) ;
if ( ntups ! = 1 )
{
write_msg ( NULL , " Got %d rows instead of one from: %s " ,
ntups , query - > data ) ;
exit_nicely ( ) ;
}
typlen = PQgetvalue ( res , 0 , PQfnumber ( res , " typlen " ) ) ;
typinput = PQgetvalue ( res , 0 , PQfnumber ( res , " typinput " ) ) ;
typoutput = PQgetvalue ( res , 0 , PQfnumber ( res , " typoutput " ) ) ;
typinputoid = PQgetvalue ( res , 0 , PQfnumber ( res , " typinputoid " ) ) ;
typoutputoid = PQgetvalue ( res , 0 , PQfnumber ( res , " typoutputoid " ) ) ;
typdelim = PQgetvalue ( res , 0 , PQfnumber ( res , " typdelim " ) ) ;
if ( PQgetisnull ( res , 0 , PQfnumber ( res , " typdefault " ) ) )
typdefault = NULL ;
else
2002-05-28 22:26:57 +00:00
typdefault = PQgetvalue ( res , 0 , PQfnumber ( res , " typdefault " ) ) ;
2002-05-10 22:36:27 +00:00
typbyval = PQgetvalue ( res , 0 , PQfnumber ( res , " typbyval " ) ) ;
typalign = PQgetvalue ( res , 0 , PQfnumber ( res , " typalign " ) ) ;
typstorage = PQgetvalue ( res , 0 , PQfnumber ( res , " typstorage " ) ) ;
/*
* Before we create a type , we need to create the input and output
* functions for it , if they haven ' t been created already . So make
* sure there are dependency entries for this . But don ' t include
* dependencies if the functions aren ' t going to be dumped .
*/
funcInd = findFuncByOid ( g_finfo , numFuncs , typinputoid ) ;
if ( funcInd > = 0 & & g_finfo [ funcInd ] . pronamespace - > dump )
( * deps ) [ depIdx + + ] = strdup ( typinputoid ) ;
funcInd = findFuncByOid ( g_finfo , numFuncs , typoutputoid ) ;
if ( funcInd > = 0 & & g_finfo [ funcInd ] . pronamespace - > dump )
( * deps ) [ depIdx + + ] = strdup ( typoutputoid ) ;
2002-05-28 22:26:57 +00:00
/* DROP must be fully qualified in case same name appears in pg_catalog */
appendPQExpBuffer ( delq , " DROP TYPE %s. " ,
fmtId ( tinfo - > typnamespace - > nspname , force_quotes ) ) ;
appendPQExpBuffer ( delq , " %s; \n " ,
2002-05-10 22:36:27 +00:00
fmtId ( tinfo - > typname , force_quotes ) ) ;
appendPQExpBuffer ( q ,
" CREATE TYPE %s "
2002-07-24 19:11:14 +00:00
" ( internallength = %s, " ,
2002-05-10 22:36:27 +00:00
fmtId ( tinfo - > typname , force_quotes ) ,
2002-07-24 19:11:14 +00:00
( strcmp ( typlen , " -1 " ) = = 0 ) ? " variable " : typlen ) ;
2002-05-10 22:36:27 +00:00
if ( fout - > remoteVersion > = 70300 )
{
/* regproc result is correctly quoted in 7.3 */
2002-07-25 20:52:59 +00:00
appendPQExpBuffer ( q , " input = %s, output = %s " ,
2002-07-24 19:11:14 +00:00
typinput , typoutput ) ;
2002-05-10 22:36:27 +00:00
}
else
{
/* regproc delivers an unquoted name before 7.3 */
/* cannot combine these because fmtId uses static result area */
appendPQExpBuffer ( q , " input = %s, " ,
fmtId ( typinput , force_quotes ) ) ;
2002-07-25 20:52:59 +00:00
appendPQExpBuffer ( q , " output = %s " ,
2002-05-10 22:36:27 +00:00
fmtId ( typoutput , force_quotes ) ) ;
2000-01-18 18:09:02 +00:00
}
2002-05-10 22:36:27 +00:00
if ( typdefault ! = NULL )
{
appendPQExpBuffer ( q , " , default = " ) ;
formatStringLiteral ( q , typdefault , CONV_ALL ) ;
}
if ( tinfo - > isArray )
{
char * elemType ;
/* reselect schema in case changed by function dump */
selectSourceSchema ( tinfo - > typnamespace - > nspname ) ;
elemType = getFormattedTypeName ( tinfo - > typelem , zeroAsOpaque ) ;
appendPQExpBuffer ( q , " , element = %s, delimiter = " , elemType ) ;
formatStringLiteral ( q , typdelim , CONV_ALL ) ;
free ( elemType ) ;
( * deps ) [ depIdx + + ] = strdup ( tinfo - > typelem ) ;
}
if ( strcmp ( typalign , " c " ) = = 0 )
appendPQExpBuffer ( q , " , alignment = char " ) ;
else if ( strcmp ( typalign , " s " ) = = 0 )
appendPQExpBuffer ( q , " , alignment = int2 " ) ;
else if ( strcmp ( typalign , " i " ) = = 0 )
appendPQExpBuffer ( q , " , alignment = int4 " ) ;
else if ( strcmp ( typalign , " d " ) = = 0 )
appendPQExpBuffer ( q , " , alignment = double " ) ;
if ( strcmp ( typstorage , " p " ) = = 0 )
appendPQExpBuffer ( q , " , storage = plain " ) ;
else if ( strcmp ( typstorage , " e " ) = = 0 )
appendPQExpBuffer ( q , " , storage = external " ) ;
else if ( strcmp ( typstorage , " x " ) = = 0 )
appendPQExpBuffer ( q , " , storage = extended " ) ;
else if ( strcmp ( typstorage , " m " ) = = 0 )
appendPQExpBuffer ( q , " , storage = main " ) ;
if ( strcmp ( typbyval , " t " ) = = 0 )
appendPQExpBuffer ( q , " , passedbyvalue); \n " ) ;
else
appendPQExpBuffer ( q , " ); \n " ) ;
( * deps ) [ depIdx + + ] = NULL ; /* End of List */
ArchiveEntry ( fout , tinfo - > oid , tinfo - > typname ,
tinfo - > typnamespace - > nspname ,
tinfo - > usename , " TYPE " , deps ,
q - > data , delq - > data , NULL , NULL , NULL ) ;
/*** Dump Type Comments ***/
resetPQExpBuffer ( q ) ;
appendPQExpBuffer ( q , " TYPE %s " , fmtId ( tinfo - > typname , force_quotes ) ) ;
dumpComment ( fout , q - > data ,
tinfo - > typnamespace - > nspname , tinfo - > usename ,
tinfo - > oid , " pg_type " , 0 , NULL ) ;
2000-01-18 18:09:02 +00:00
PQclear ( res ) ;
2002-05-10 22:36:27 +00:00
destroyPQExpBuffer ( q ) ;
destroyPQExpBuffer ( delq ) ;
2001-08-03 19:43:05 +00:00
destroyPQExpBuffer ( query ) ;
2000-01-18 18:09:02 +00:00
}
2002-04-05 11:51:13 +00:00
/*
* dumpOneDomain
2002-05-10 22:36:27 +00:00
* writes out to fout the queries to recreate a user - defined domain
2002-04-05 11:51:13 +00:00
* as requested by dumpTypes
*/
2002-04-29 17:30:18 +00:00
static void
2002-04-05 11:51:13 +00:00
dumpOneDomain ( Archive * fout , TypeInfo * tinfo )
{
PQExpBuffer q = createPQExpBuffer ( ) ;
PQExpBuffer delq = createPQExpBuffer ( ) ;
PQExpBuffer query = createPQExpBuffer ( ) ;
2002-05-10 22:36:27 +00:00
PGresult * res ;
2002-04-05 11:51:13 +00:00
int ntups ;
2002-05-10 22:36:27 +00:00
char * typnotnull ;
char * typdefn ;
char * typdefault ;
char * typbasetype ;
2002-04-05 11:51:13 +00:00
const char * ( ( * deps ) [ ] ) ;
int depIdx = 0 ;
deps = malloc ( sizeof ( char * ) * 10 ) ;
2002-05-10 22:36:27 +00:00
/* Set proper schema search path so type references list correctly */
selectSourceSchema ( tinfo - > typnamespace - > nspname ) ;
2002-04-05 11:51:13 +00:00
/* Fetch domain specific details */
2002-05-28 22:26:57 +00:00
/* We assume here that remoteVersion must be at least 70300 */
2002-04-05 11:51:13 +00:00
appendPQExpBuffer ( query , " SELECT typnotnull, "
2002-05-28 22:26:57 +00:00
" pg_catalog.format_type(typbasetype, typtypmod) as typdefn, "
2002-05-10 22:36:27 +00:00
" typdefault, typbasetype "
2002-05-28 22:26:57 +00:00
" FROM pg_catalog.pg_type "
" WHERE oid = '%s'::pg_catalog.oid " ,
2002-05-10 22:36:27 +00:00
tinfo - > oid ) ;
2002-04-05 11:51:13 +00:00
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to obtain domain information failed: %s " , PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
/* Expecting a single result only */
ntups = PQntuples ( res ) ;
if ( ntups ! = 1 )
2002-05-10 22:36:27 +00:00
{
write_msg ( NULL , " Got %d rows instead of one from: %s " ,
ntups , query - > data ) ;
exit_nicely ( ) ;
}
2002-04-05 11:51:13 +00:00
2002-05-10 22:36:27 +00:00
typnotnull = PQgetvalue ( res , 0 , PQfnumber ( res , " typnotnull " ) ) ;
typdefn = PQgetvalue ( res , 0 , PQfnumber ( res , " typdefn " ) ) ;
if ( PQgetisnull ( res , 0 , PQfnumber ( res , " typdefault " ) ) )
typdefault = NULL ;
else
2002-05-28 22:26:57 +00:00
typdefault = PQgetvalue ( res , 0 , PQfnumber ( res , " typdefault " ) ) ;
2002-05-10 22:36:27 +00:00
typbasetype = PQgetvalue ( res , 0 , PQfnumber ( res , " typbasetype " ) ) ;
2002-04-05 11:51:13 +00:00
2002-05-28 22:26:57 +00:00
/* DROP must be fully qualified in case same name appears in pg_catalog */
appendPQExpBuffer ( delq , " DROP DOMAIN %s. " ,
fmtId ( tinfo - > typnamespace - > nspname , force_quotes ) ) ;
appendPQExpBuffer ( delq , " %s RESTRICT; \n " ,
2002-05-10 22:36:27 +00:00
fmtId ( tinfo - > typname , force_quotes ) ) ;
2002-04-05 11:51:13 +00:00
appendPQExpBuffer ( q ,
" CREATE DOMAIN %s AS %s " ,
fmtId ( tinfo - > typname , force_quotes ) ,
2002-05-10 22:36:27 +00:00
typdefn ) ;
2002-04-05 11:51:13 +00:00
/* Depends on the base type */
2002-05-10 22:36:27 +00:00
( * deps ) [ depIdx + + ] = strdup ( typbasetype ) ;
2002-04-05 11:51:13 +00:00
2002-05-10 22:36:27 +00:00
if ( typnotnull [ 0 ] = = ' t ' )
2002-04-05 11:51:13 +00:00
appendPQExpBuffer ( q , " NOT NULL " ) ;
2002-05-10 22:36:27 +00:00
if ( typdefault )
2002-05-28 22:26:57 +00:00
appendPQExpBuffer ( q , " DEFAULT %s " , typdefault ) ;
2002-04-05 11:51:13 +00:00
appendPQExpBuffer ( q , " ; \n " ) ;
( * deps ) [ depIdx + + ] = NULL ; /* End of List */
2002-05-10 22:36:27 +00:00
ArchiveEntry ( fout , tinfo - > oid , tinfo - > typname ,
tinfo - > typnamespace - > nspname ,
tinfo - > usename , " DOMAIN " , deps ,
q - > data , delq - > data , NULL , NULL , NULL ) ;
2002-04-05 11:51:13 +00:00
/*** Dump Domain Comments ***/
resetPQExpBuffer ( q ) ;
appendPQExpBuffer ( q , " DOMAIN %s " , fmtId ( tinfo - > typname , force_quotes ) ) ;
2002-05-10 22:36:27 +00:00
dumpComment ( fout , q - > data ,
tinfo - > typnamespace - > nspname , tinfo - > usename ,
tinfo - > oid , " pg_type " , 0 , NULL ) ;
PQclear ( res ) ;
destroyPQExpBuffer ( q ) ;
destroyPQExpBuffer ( delq ) ;
destroyPQExpBuffer ( query ) ;
2002-04-05 11:51:13 +00:00
}
2002-08-15 16:36:08 +00:00
/*
* dumpOneCompositeType
* writes out to fout the queries to recreate a user - defined stand - alone
* composite type as requested by dumpTypes
*/
static void
dumpOneCompositeType ( Archive * fout , TypeInfo * tinfo )
{
PQExpBuffer q = createPQExpBuffer ( ) ;
PQExpBuffer delq = createPQExpBuffer ( ) ;
PQExpBuffer query = createPQExpBuffer ( ) ;
PGresult * res ;
int ntups ;
char * attname ;
char * atttypdefn ;
char * attbasetype ;
const char * ( ( * deps ) [ ] ) ;
int depIdx = 0 ;
int i ;
deps = malloc ( sizeof ( char * ) * 10 ) ;
/* Set proper schema search path so type references list correctly */
selectSourceSchema ( tinfo - > typnamespace - > nspname ) ;
/* Fetch type specific details */
/* We assume here that remoteVersion must be at least 70300 */
appendPQExpBuffer ( query , " SELECT a.attname, "
" pg_catalog.format_type(a.atttypid, a.atttypmod) as atttypdefn, "
" a.atttypid as attbasetype "
" FROM pg_catalog.pg_type t, pg_catalog.pg_attribute a "
" WHERE t.oid = '%s'::pg_catalog.oid "
" AND a.attrelid = t.typrelid " ,
tinfo - > oid ) ;
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to obtain type information failed: %s " , PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
/* Expecting at least a single result */
ntups = PQntuples ( res ) ;
if ( ntups < 1 )
{
write_msg ( NULL , " Got no rows from: %s " , query - > data ) ;
exit_nicely ( ) ;
}
/* DROP must be fully qualified in case same name appears in pg_catalog */
appendPQExpBuffer ( delq , " DROP TYPE %s. " ,
fmtId ( tinfo - > typnamespace - > nspname , force_quotes ) ) ;
appendPQExpBuffer ( delq , " %s RESTRICT; \n " ,
fmtId ( tinfo - > typname , force_quotes ) ) ;
appendPQExpBuffer ( q ,
" CREATE TYPE %s AS ( " ,
fmtId ( tinfo - > typname , force_quotes ) ) ;
for ( i = 0 ; i < ntups ; i + + )
{
attname = PQgetvalue ( res , i , PQfnumber ( res , " attname " ) ) ;
atttypdefn = PQgetvalue ( res , i , PQfnumber ( res , " atttypdefn " ) ) ;
attbasetype = PQgetvalue ( res , i , PQfnumber ( res , " attbasetype " ) ) ;
if ( i > 0 )
appendPQExpBuffer ( q , " , \n \t %s %s " , attname , atttypdefn ) ;
else
appendPQExpBuffer ( q , " %s %s " , attname , atttypdefn ) ;
/* Depends on the base type */
( * deps ) [ depIdx + + ] = strdup ( attbasetype ) ;
}
appendPQExpBuffer ( q , " ); \n " ) ;
( * deps ) [ depIdx + + ] = NULL ; /* End of List */
ArchiveEntry ( fout , tinfo - > oid , tinfo - > typname ,
tinfo - > typnamespace - > nspname ,
tinfo - > usename , " TYPE " , deps ,
q - > data , delq - > data , NULL , NULL , NULL ) ;
/*** Dump Type Comments ***/
resetPQExpBuffer ( q ) ;
appendPQExpBuffer ( q , " TYPE %s " , fmtId ( tinfo - > typname , force_quotes ) ) ;
dumpComment ( fout , q - > data ,
tinfo - > typnamespace - > nspname , tinfo - > usename ,
tinfo - > oid , " pg_type " , 0 , NULL ) ;
PQclear ( res ) ;
destroyPQExpBuffer ( q ) ;
destroyPQExpBuffer ( delq ) ;
destroyPQExpBuffer ( query ) ;
}
1996-07-09 06:22:35 +00:00
/*
* dumpTypes
1997-09-07 05:04:48 +00:00
* writes out to fout the queries to recreate all the user - defined types
1996-07-09 06:22:35 +00:00
*/
void
2000-07-04 14:25:28 +00:00
dumpTypes ( Archive * fout , FuncInfo * finfo , int numFuncs ,
1997-09-08 21:56:23 +00:00
TypeInfo * tinfo , int numTypes )
1996-07-09 06:22:35 +00:00
{
1997-09-08 02:41:22 +00:00
int i ;
1997-09-07 05:04:48 +00:00
for ( i = 0 ; i < numTypes ; i + + )
{
2002-05-10 22:36:27 +00:00
/* Dump only types in dumpable namespaces */
if ( ! tinfo [ i ] . typnamespace - > dump )
1997-09-07 05:04:48 +00:00
continue ;
2002-08-15 16:36:08 +00:00
/* skip relation types for non-stand-alone type relations*/
if ( atooid ( tinfo [ i ] . typrelid ) ! = 0 & & tinfo [ i ] . typrelkind ! = ' c ' )
1997-09-07 05:04:48 +00:00
continue ;
2001-08-03 19:43:05 +00:00
/* skip undefined placeholder types */
if ( ! tinfo [ i ] . isDefined )
continue ;
1997-09-07 05:04:48 +00:00
/* skip all array types that start w/ underscore */
if ( ( tinfo [ i ] . typname [ 0 ] = = ' _ ' ) & &
2002-05-10 22:36:27 +00:00
atooid ( tinfo [ i ] . typelem ) ! = 0 )
1997-09-07 05:04:48 +00:00
continue ;
2002-05-10 22:36:27 +00:00
/* Dump out in proper style */
if ( tinfo [ i ] . typtype = = ' b ' )
dumpOneBaseType ( fout , & tinfo [ i ] ,
finfo , numFuncs , tinfo , numTypes ) ;
else if ( tinfo [ i ] . typtype = = ' d ' )
2002-04-05 11:51:13 +00:00
dumpOneDomain ( fout , & tinfo [ i ] ) ;
2002-08-15 16:36:08 +00:00
else if ( tinfo [ i ] . typtype = = ' c ' )
dumpOneCompositeType ( fout , & tinfo [ i ] ) ;
1997-09-07 05:04:48 +00:00
}
1996-07-09 06:22:35 +00:00
}
1998-10-06 22:14:21 +00:00
/*
* dumpProcLangs
1999-05-25 16:15:34 +00:00
* writes out to fout the queries to recreate user - defined procedural languages
1998-10-06 22:14:21 +00:00
*/
void
2002-05-19 10:08:25 +00:00
dumpProcLangs ( Archive * fout , FuncInfo finfo [ ] , int numFuncs )
1998-10-06 22:14:21 +00:00
{
2000-04-12 17:17:23 +00:00
PGresult * res ;
PQExpBuffer query = createPQExpBuffer ( ) ;
2000-07-04 14:25:28 +00:00
PQExpBuffer defqry = createPQExpBuffer ( ) ;
PQExpBuffer delqry = createPQExpBuffer ( ) ;
1998-10-06 22:14:21 +00:00
int ntups ;
2000-07-04 14:25:28 +00:00
int i_oid ;
1998-10-06 22:14:21 +00:00
int i_lanname ;
int i_lanpltrusted ;
int i_lanplcallfoid ;
2002-05-22 17:21:02 +00:00
int i_lanvalidator = - 1 ;
2002-05-19 10:08:25 +00:00
int i_lanacl = - 1 ;
2002-05-10 22:36:27 +00:00
char * lanoid ;
2000-04-12 17:17:23 +00:00
char * lanname ;
2002-05-19 10:08:25 +00:00
char * lanacl ;
2000-04-12 17:17:23 +00:00
const char * lanplcallfoid ;
2002-05-22 17:21:02 +00:00
const char * lanvalidator ;
2002-05-10 22:36:27 +00:00
const char * ( ( * deps ) [ ] ) ;
int depIdx ;
1998-10-06 22:14:21 +00:00
int i ,
2002-05-22 17:21:02 +00:00
fidx ,
vidx = - 1 ;
1998-10-06 22:14:21 +00:00
2002-05-10 22:36:27 +00:00
/* Make sure we are in proper schema */
selectSourceSchema ( " pg_catalog " ) ;
2000-07-04 14:25:28 +00:00
appendPQExpBuffer ( query , " SELECT oid, * FROM pg_language "
2000-04-12 17:17:23 +00:00
" WHERE lanispl "
" ORDER BY oid " ) ;
1999-12-27 15:42:44 +00:00
res = PQexec ( g_conn , query - > data ) ;
1998-10-06 22:14:21 +00:00
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " query to obtain list of procedural languages failed: %s " ,
2001-10-25 05:50:21 +00:00
PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1998-10-06 22:14:21 +00:00
}
ntups = PQntuples ( res ) ;
1999-05-25 16:15:34 +00:00
i_lanname = PQfnumber ( res , " lanname " ) ;
i_lanpltrusted = PQfnumber ( res , " lanpltrusted " ) ;
i_lanplcallfoid = PQfnumber ( res , " lanplcallfoid " ) ;
2000-07-04 14:25:28 +00:00
i_oid = PQfnumber ( res , " oid " ) ;
2002-05-19 10:08:25 +00:00
if ( fout - > remoteVersion > = 70300 )
2002-05-22 17:21:02 +00:00
{
i_lanvalidator = PQfnumber ( res , " lanvalidator " ) ;
2002-05-19 10:08:25 +00:00
i_lanacl = PQfnumber ( res , " lanacl " ) ;
2002-05-22 17:21:02 +00:00
}
1998-10-06 22:14:21 +00:00
1999-05-25 16:15:34 +00:00
for ( i = 0 ; i < ntups ; i + + )
{
2002-05-10 22:36:27 +00:00
lanoid = PQgetvalue ( res , i , i_oid ) ;
1998-10-06 22:14:21 +00:00
lanplcallfoid = PQgetvalue ( res , i , i_lanplcallfoid ) ;
2002-05-10 22:36:27 +00:00
lanname = PQgetvalue ( res , i , i_lanname ) ;
2002-05-19 10:08:25 +00:00
if ( fout - > remoteVersion > = 70300 )
2002-05-22 17:21:02 +00:00
{
lanvalidator = PQgetvalue ( res , i , i_lanvalidator ) ;
2002-05-19 10:08:25 +00:00
lanacl = PQgetvalue ( res , i , i_lanacl ) ;
2002-05-22 17:21:02 +00:00
}
2002-05-19 10:08:25 +00:00
else
2002-05-22 17:21:02 +00:00
{
lanvalidator = " 0 " ;
lanacl = " {=U} " ;
}
2000-10-31 14:20:30 +00:00
2002-05-10 22:36:27 +00:00
fidx = findFuncByOid ( finfo , numFuncs , lanplcallfoid ) ;
if ( fidx < 0 )
1998-10-06 22:14:21 +00:00
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " handler procedure for procedural language %s not found \n " ,
2002-05-10 22:36:27 +00:00
lanname ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1998-10-06 22:14:21 +00:00
}
2002-05-22 17:21:02 +00:00
if ( strcmp ( lanvalidator , " 0 " ) ! = 0 )
{
vidx = findFuncByOid ( finfo , numFuncs , lanvalidator ) ;
if ( vidx < 0 )
{
write_msg ( NULL , " validator procedure for procedural language %s not found \n " ,
lanname ) ;
exit_nicely ( ) ;
}
}
2002-05-10 22:36:27 +00:00
/*
* Current theory is to dump PLs iff their underlying functions
* will be dumped ( are in a dumpable namespace , or have a non - system
* OID in pre - 7.3 databases ) . Actually , we treat the PL itself
* as being in the underlying function ' s namespace , though it
* isn ' t really . This avoids searchpath problems for the HANDLER
* clause .
*/
if ( ! finfo [ fidx ] . pronamespace - > dump )
continue ;
resetPQExpBuffer ( defqry ) ;
resetPQExpBuffer ( delqry ) ;
1998-10-06 22:14:21 +00:00
2002-05-10 22:36:27 +00:00
/* Make a dependency to ensure function is dumped first */
2002-05-22 17:21:02 +00:00
deps = malloc ( sizeof ( char * ) * ( 2 + ( strcmp ( lanvalidator , " 0 " ) ! = 0 ) ? 1 : 0 ) ) ;
2002-05-10 22:36:27 +00:00
depIdx = 0 ;
( * deps ) [ depIdx + + ] = strdup ( lanplcallfoid ) ;
1998-10-06 22:14:21 +00:00
2002-05-28 22:26:57 +00:00
appendPQExpBuffer ( delqry , " DROP PROCEDURAL LANGUAGE %s; \n " ,
fmtId ( lanname , force_quotes ) ) ;
1999-01-21 22:53:37 +00:00
2002-05-17 18:32:52 +00:00
appendPQExpBuffer ( defqry , " CREATE %sPROCEDURAL LANGUAGE %s " ,
2001-01-04 01:23:47 +00:00
( PQgetvalue ( res , i , i_lanpltrusted ) [ 0 ] = = ' t ' ) ?
2002-05-17 18:32:52 +00:00
" TRUSTED " : " " ,
fmtId ( lanname , force_quotes ) ) ;
2002-05-22 17:21:02 +00:00
appendPQExpBuffer ( defqry , " HANDLER %s " ,
2001-01-04 01:23:47 +00:00
fmtId ( finfo [ fidx ] . proname , force_quotes ) ) ;
2002-05-22 17:21:02 +00:00
if ( strcmp ( lanvalidator , " 0 " ) ! = 0 )
{
2002-05-28 22:26:57 +00:00
appendPQExpBuffer ( defqry , " VALIDATOR " ) ;
/* Cope with possibility that validator is in different schema */
if ( finfo [ vidx ] . pronamespace ! = finfo [ fidx ] . pronamespace )
appendPQExpBuffer ( defqry , " %s. " ,
fmtId ( finfo [ vidx ] . pronamespace - > nspname ,
force_quotes ) ) ;
appendPQExpBuffer ( defqry , " %s " ,
2002-05-22 17:21:02 +00:00
fmtId ( finfo [ vidx ] . proname , force_quotes ) ) ;
( * deps ) [ depIdx + + ] = strdup ( lanvalidator ) ;
}
appendPQExpBuffer ( defqry , " ; \n " ) ;
1998-10-06 22:14:21 +00:00
2002-05-10 22:36:27 +00:00
( * deps ) [ depIdx + + ] = NULL ; /* End of List */
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
ArchiveEntry ( fout , lanoid , lanname ,
finfo [ fidx ] . pronamespace - > nspname , " " ,
" PROCEDURAL LANGUAGE " , deps ,
defqry - > data , delqry - > data , NULL , NULL , NULL ) ;
2002-05-19 10:08:25 +00:00
if ( ! aclsSkip )
{
2002-07-04 03:04:55 +00:00
char * tmp = strdup ( fmtId ( lanname , force_quotes ) ) ;
dumpACL ( fout , " LANGUAGE " , tmp , lanname ,
finfo [ fidx ] . pronamespace - > nspname ,
2002-05-19 10:08:25 +00:00
NULL , lanacl , lanoid ) ;
free ( tmp ) ;
}
1998-10-06 22:14:21 +00:00
}
PQclear ( res ) ;
2001-08-03 19:43:05 +00:00
destroyPQExpBuffer ( query ) ;
destroyPQExpBuffer ( defqry ) ;
destroyPQExpBuffer ( delqry ) ;
1998-10-06 22:14:21 +00:00
}
1996-07-09 06:22:35 +00:00
/*
* dumpFuncs
1997-09-07 05:04:48 +00:00
* writes out to fout the queries to recreate all the user - defined functions
1996-07-09 06:22:35 +00:00
*/
void
2002-05-19 10:08:25 +00:00
dumpFuncs ( Archive * fout , FuncInfo finfo [ ] , int numFuncs )
1996-07-09 06:22:35 +00:00
{
1997-09-08 02:41:22 +00:00
int i ;
1997-09-07 05:04:48 +00:00
for ( i = 0 ; i < numFuncs ; i + + )
2002-05-10 22:36:27 +00:00
{
/* Dump only funcs in dumpable namespaces */
if ( ! finfo [ i ] . pronamespace - > dump )
continue ;
dumpOneFunc ( fout , & finfo [ i ] ) ;
2002-05-19 10:08:25 +00:00
if ( ! aclsSkip )
dumpFuncACL ( fout , & finfo [ i ] ) ;
2002-05-10 22:36:27 +00:00
}
1996-07-09 06:22:35 +00:00
}
2002-05-28 22:26:57 +00:00
/*
* format_function_signature : generate function name and argument list
*
* The argument type names are qualified if needed . The function name
* is never qualified .
*/
2002-05-19 10:08:25 +00:00
static char *
2002-07-04 03:04:55 +00:00
format_function_signature ( FuncInfo * finfo , bool honor_quotes )
2002-05-19 10:08:25 +00:00
{
PQExpBufferData fn ;
int j ;
initPQExpBuffer ( & fn ) ;
2002-07-04 03:04:55 +00:00
if ( honor_quotes )
appendPQExpBuffer ( & fn , " %s( " , fmtId ( finfo - > proname , force_quotes ) ) ;
else
appendPQExpBuffer ( & fn , " %s( " , finfo - > proname ) ;
2002-05-19 10:08:25 +00:00
for ( j = 0 ; j < finfo - > nargs ; j + + )
{
char * typname ;
typname = getFormattedTypeName ( finfo - > argtypes [ j ] , zeroAsOpaque ) ;
appendPQExpBuffer ( & fn , " %s%s " ,
( j > 0 ) ? " , " : " " ,
typname ) ;
free ( typname ) ;
}
appendPQExpBuffer ( & fn , " ) " ) ;
return fn . data ;
}
static void
dumpFuncACL ( Archive * fout , FuncInfo * finfo )
{
2002-07-04 15:35:07 +00:00
char * funcsig , * funcsig_tag ;
2002-05-19 10:08:25 +00:00
2002-07-04 03:04:55 +00:00
funcsig = format_function_signature ( finfo , true ) ;
2002-07-04 15:35:07 +00:00
funcsig_tag = format_function_signature ( finfo , false ) ;
dumpACL ( fout , " FUNCTION " , funcsig , funcsig_tag ,
2002-07-04 03:04:55 +00:00
finfo - > pronamespace - > nspname ,
2002-05-19 10:08:25 +00:00
finfo - > usename , finfo - > proacl , finfo - > oid ) ;
free ( funcsig ) ;
2002-07-04 15:35:07 +00:00
free ( funcsig_tag ) ;
2002-05-19 10:08:25 +00:00
}
1996-07-09 06:22:35 +00:00
/*
* dumpOneFunc :
2002-05-10 22:36:27 +00:00
* dump out only one function
1996-07-09 06:22:35 +00:00
*/
1997-08-19 21:40:56 +00:00
static void
2002-05-10 22:36:27 +00:00
dumpOneFunc ( Archive * fout , FuncInfo * finfo )
1996-07-09 06:22:35 +00:00
{
2002-05-10 22:36:27 +00:00
PQExpBuffer query = createPQExpBuffer ( ) ;
2000-04-12 17:17:23 +00:00
PQExpBuffer q = createPQExpBuffer ( ) ;
2000-07-04 14:25:28 +00:00
PQExpBuffer delqry = createPQExpBuffer ( ) ;
2000-07-21 11:40:08 +00:00
PQExpBuffer asPart = createPQExpBuffer ( ) ;
2002-05-10 22:36:27 +00:00
PGresult * res = NULL ;
2002-05-19 10:08:25 +00:00
char * funcsig = NULL ;
2002-07-04 15:35:07 +00:00
char * funcsig_tag = NULL ;
2002-05-10 22:36:27 +00:00
int ntups ;
char * proretset ;
char * prosrc ;
char * probin ;
char * provolatile ;
char * proisstrict ;
2002-05-18 13:48:01 +00:00
char * prosecdef ;
2002-05-10 22:36:27 +00:00
char * lanname ;
2001-03-22 04:01:46 +00:00
char * rettypename ;
2000-10-10 13:55:28 +00:00
2002-05-10 22:36:27 +00:00
if ( finfo - > dumped )
2001-08-03 19:43:05 +00:00
goto done ;
2002-05-10 22:36:27 +00:00
finfo - > dumped = true ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
/* Set proper schema search path so type references list correctly */
selectSourceSchema ( finfo - > pronamespace - > nspname ) ;
/* Fetch function-specific details */
if ( g_fout - > remoteVersion > = 70300 )
{
appendPQExpBuffer ( query ,
" SELECT proretset, prosrc, probin, "
2002-07-18 23:11:32 +00:00
" provolatile, proisstrict, prosecdef, "
2002-05-28 22:26:57 +00:00
" (SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
" FROM pg_catalog.pg_proc "
" WHERE oid = '%s'::pg_catalog.oid " ,
2002-05-10 22:36:27 +00:00
finfo - > oid ) ;
}
else if ( g_fout - > remoteVersion > = 70100 )
{
appendPQExpBuffer ( query ,
" SELECT proretset, prosrc, probin, "
" case when proiscachable then 'i' else 'v' end as provolatile, "
" proisstrict, "
2002-05-18 13:48:01 +00:00
" 'f'::boolean as prosecdef, "
2002-05-10 22:36:27 +00:00
" (SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
" FROM pg_proc "
" WHERE oid = '%s'::oid " ,
finfo - > oid ) ;
}
else
{
appendPQExpBuffer ( query ,
" SELECT proretset, prosrc, probin, "
" case when proiscachable then 'i' else 'v' end as provolatile, "
" 'f'::boolean as proisstrict, "
2002-05-18 13:48:01 +00:00
" 'f'::boolean as prosecdef, "
2002-05-10 22:36:27 +00:00
" (SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
" FROM pg_proc "
" WHERE oid = '%s'::oid " ,
finfo - > oid ) ;
}
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
res = PQexec ( g_conn , query - > data ) ;
2000-05-28 20:34:52 +00:00
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
2001-03-22 04:01:46 +00:00
{
2002-05-10 22:36:27 +00:00
write_msg ( NULL , " query to obtain function information for %s failed: %s " ,
finfo - > proname , PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
2001-03-22 04:01:46 +00:00
}
2000-05-28 20:34:52 +00:00
2002-05-10 22:36:27 +00:00
/* Expecting a single result only */
ntups = PQntuples ( res ) ;
if ( ntups ! = 1 )
2001-03-22 04:01:46 +00:00
{
2002-05-10 22:36:27 +00:00
write_msg ( NULL , " Got %d rows instead of one from: %s " ,
ntups , query - > data ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
2001-03-22 04:01:46 +00:00
}
2002-05-10 22:36:27 +00:00
proretset = PQgetvalue ( res , 0 , PQfnumber ( res , " proretset " ) ) ;
prosrc = PQgetvalue ( res , 0 , PQfnumber ( res , " prosrc " ) ) ;
probin = PQgetvalue ( res , 0 , PQfnumber ( res , " probin " ) ) ;
provolatile = PQgetvalue ( res , 0 , PQfnumber ( res , " provolatile " ) ) ;
proisstrict = PQgetvalue ( res , 0 , PQfnumber ( res , " proisstrict " ) ) ;
2002-05-18 13:48:01 +00:00
prosecdef = PQgetvalue ( res , 0 , PQfnumber ( res , " prosecdef " ) ) ;
2002-05-10 22:36:27 +00:00
lanname = PQgetvalue ( res , 0 , PQfnumber ( res , " lanname " ) ) ;
2000-07-11 13:07:17 +00:00
2000-07-21 11:40:08 +00:00
/*
2001-03-22 04:01:46 +00:00
* See backend / commands / define . c for details of how the ' AS ' clause is
* used .
2000-07-11 13:07:17 +00:00
*/
2002-05-10 22:36:27 +00:00
if ( strcmp ( probin , " - " ) ! = 0 )
2000-07-11 13:07:17 +00:00
{
2001-01-04 01:23:47 +00:00
appendPQExpBuffer ( asPart , " AS " ) ;
2002-05-10 22:36:27 +00:00
formatStringLiteral ( asPart , probin , CONV_ALL ) ;
if ( strcmp ( prosrc , " - " ) ! = 0 )
2001-01-04 01:23:47 +00:00
{
appendPQExpBuffer ( asPart , " , " ) ;
2002-05-10 22:36:27 +00:00
formatStringLiteral ( asPart , prosrc , PASS_LFTAB ) ;
2001-01-04 01:23:47 +00:00
}
2000-07-11 13:07:17 +00:00
}
else
{
2002-05-10 22:36:27 +00:00
if ( strcmp ( prosrc , " - " ) ! = 0 )
2001-01-04 01:23:47 +00:00
{
appendPQExpBuffer ( asPart , " AS " ) ;
2002-05-10 22:36:27 +00:00
formatStringLiteral ( asPart , prosrc , PASS_LFTAB ) ;
2001-01-04 01:23:47 +00:00
}
2000-07-11 13:07:17 +00:00
}
2002-07-04 03:04:55 +00:00
funcsig = format_function_signature ( finfo , true ) ;
2002-07-04 15:35:07 +00:00
funcsig_tag = format_function_signature ( finfo , false ) ;
2000-07-04 14:25:28 +00:00
2002-05-28 22:26:57 +00:00
/* DROP must be fully qualified in case same name appears in pg_catalog */
appendPQExpBuffer ( delqry , " DROP FUNCTION %s.%s; \n " ,
fmtId ( finfo - > pronamespace - > nspname , force_quotes ) ,
funcsig ) ;
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
rettypename = getFormattedTypeName ( finfo - > prorettype , zeroAsOpaque ) ;
2001-01-28 02:57:06 +00:00
2002-05-19 10:08:25 +00:00
appendPQExpBuffer ( q , " CREATE FUNCTION %s " , funcsig ) ;
2002-05-17 18:32:52 +00:00
appendPQExpBuffer ( q , " RETURNS %s%s %s LANGUAGE %s " ,
2002-05-10 22:36:27 +00:00
( proretset [ 0 ] = = ' t ' ) ? " SETOF " : " " ,
2001-01-28 02:57:06 +00:00
rettypename ,
2002-05-17 18:32:52 +00:00
asPart - > data ,
fmtId ( lanname , force_quotes ) ) ;
2002-05-10 22:36:27 +00:00
free ( rettypename ) ;
1997-09-07 05:04:48 +00:00
2002-05-17 18:32:52 +00:00
if ( provolatile [ 0 ] ! = PROVOLATILE_VOLATILE )
2000-08-07 12:32:54 +00:00
{
2002-05-10 22:36:27 +00:00
if ( provolatile [ 0 ] = = PROVOLATILE_IMMUTABLE )
2002-05-17 18:32:52 +00:00
appendPQExpBuffer ( q , " IMMUTABLE " ) ;
2002-05-10 22:36:27 +00:00
else if ( provolatile [ 0 ] = = PROVOLATILE_STABLE )
2002-05-17 18:32:52 +00:00
appendPQExpBuffer ( q , " STABLE " ) ;
2002-05-10 22:36:27 +00:00
else if ( provolatile [ 0 ] ! = PROVOLATILE_VOLATILE )
2002-04-05 00:31:36 +00:00
{
write_msg ( NULL , " Unexpected provolatile value for function %s \n " ,
2002-05-10 22:36:27 +00:00
finfo - > proname ) ;
2002-04-05 00:31:36 +00:00
exit_nicely ( ) ;
}
2002-07-04 03:04:55 +00:00
}
2000-10-10 13:55:28 +00:00
2002-05-17 18:32:52 +00:00
if ( proisstrict [ 0 ] = = ' t ' )
appendPQExpBuffer ( q , " STRICT " ) ;
2000-08-07 12:32:54 +00:00
2002-05-18 13:48:01 +00:00
if ( prosecdef [ 0 ] = = ' t ' )
appendPQExpBuffer ( q , " SECURITY DEFINER " ) ;
2000-08-07 12:32:54 +00:00
appendPQExpBuffer ( q , " ; \n " ) ;
2002-07-04 15:35:07 +00:00
ArchiveEntry ( fout , finfo - > oid , funcsig_tag ,
2002-07-04 03:04:55 +00:00
finfo - > pronamespace - > nspname ,
2002-05-10 22:36:27 +00:00
finfo - > usename , " FUNCTION " , NULL ,
q - > data , delqry - > data ,
NULL , NULL , NULL ) ;
1996-07-09 06:22:35 +00:00
2000-01-18 18:09:02 +00:00
/*** Dump Function Comments ***/
resetPQExpBuffer ( q ) ;
2002-05-19 10:08:25 +00:00
appendPQExpBuffer ( q , " FUNCTION %s " , funcsig ) ;
2002-05-10 22:36:27 +00:00
dumpComment ( fout , q - > data ,
finfo - > pronamespace - > nspname , finfo - > usename ,
finfo - > oid , " pg_proc " , 0 , NULL ) ;
2001-08-03 19:43:05 +00:00
done :
2002-05-10 22:36:27 +00:00
PQclear ( res ) ;
destroyPQExpBuffer ( query ) ;
2001-08-03 19:43:05 +00:00
destroyPQExpBuffer ( q ) ;
destroyPQExpBuffer ( delqry ) ;
destroyPQExpBuffer ( asPart ) ;
2002-05-19 10:08:25 +00:00
free ( funcsig ) ;
2002-07-04 15:35:07 +00:00
free ( funcsig_tag ) ;
1996-07-09 06:22:35 +00:00
}
2002-07-18 23:11:32 +00:00
/*
* Dump all casts
*/
void
dumpCasts ( Archive * fout ,
FuncInfo * finfo , int numFuncs ,
TypeInfo * tinfo , int numTypes )
{
PGresult * res ;
PQExpBuffer query = createPQExpBuffer ( ) ;
PQExpBuffer defqry = createPQExpBuffer ( ) ;
PQExpBuffer delqry = createPQExpBuffer ( ) ;
int ntups ;
int i ;
/* Make sure we are in proper schema */
selectSourceSchema ( " pg_catalog " ) ;
if ( fout - > remoteVersion > = 70300 )
appendPQExpBuffer ( query , " SELECT oid, castsource, casttarget, castfunc, castimplicit FROM pg_cast ORDER BY 1,2,3; " ) ;
else
appendPQExpBuffer ( query , " SELECT p.oid, t1.oid, t2.oid, p.oid, true FROM pg_type t1, pg_type t2, pg_proc p WHERE p.pronargs = 1 AND p.proargtypes[0] = t1.oid AND p.prorettype = t2.oid AND p.proname = t2.typname ORDER BY 1,2,3; " ) ;
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | | PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to obtain list of casts failed: %s " ,
PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
ntups = PQntuples ( res ) ;
for ( i = 0 ; i < ntups ; i + + )
{
char * castoid = PQgetvalue ( res , i , 0 ) ;
char * castsource = PQgetvalue ( res , i , 1 ) ;
char * casttarget = PQgetvalue ( res , i , 2 ) ;
char * castfunc = PQgetvalue ( res , i , 3 ) ;
char * castimplicit = PQgetvalue ( res , i , 4 ) ;
int fidx = - 1 ;
const char * ( ( * deps ) [ ] ) ;
if ( strcmp ( castfunc , " 0 " ) ! = 0 )
fidx = findFuncByOid ( finfo , numFuncs , castfunc ) ;
/*
* We treat the cast as being in the namespace of the
* underlying function . This doesn ' t handle binary compatible
* casts . Where should those go ?
*/
if ( fidx < 0 | | ! finfo [ fidx ] . pronamespace - > dump )
continue ;
/* Make a dependency to ensure function is dumped first */
if ( fidx > = 0 )
{
deps = malloc ( sizeof ( char * ) * 2 ) ;
( * deps ) [ 0 ] = strdup ( castfunc ) ;
( * deps ) [ 1 ] = NULL ; /* End of List */
}
else
deps = NULL ;
resetPQExpBuffer ( defqry ) ;
resetPQExpBuffer ( delqry ) ;
appendPQExpBuffer ( delqry , " DROP CAST (%s AS %s); \n " ,
getFormattedTypeName ( castsource , zeroAsNone ) ,
getFormattedTypeName ( casttarget , zeroAsNone ) ) ;
appendPQExpBuffer ( defqry , " CREATE CAST (%s AS %s) " ,
getFormattedTypeName ( castsource , zeroAsNone ) ,
getFormattedTypeName ( casttarget , zeroAsNone ) ) ;
if ( strcmp ( castfunc , " 0 " ) = = 0 )
appendPQExpBuffer ( defqry , " WITHOUT FUNCTION " ) ;
else
appendPQExpBuffer ( defqry , " WITH FUNCTION %s " ,
format_function_signature ( & finfo [ fidx ] , true ) ) ;
if ( strcmp ( castimplicit , " t " ) = = 0 )
appendPQExpBuffer ( defqry , " AS ASSIGNMENT " ) ;
appendPQExpBuffer ( defqry , " ; \n " ) ;
ArchiveEntry ( fout , castoid ,
format_function_signature ( & finfo [ fidx ] , false ) ,
finfo [ fidx ] . pronamespace - > nspname , " " ,
" CAST " , deps ,
defqry - > data , delqry - > data ,
NULL , NULL , NULL ) ;
}
PQclear ( res ) ;
destroyPQExpBuffer ( query ) ;
destroyPQExpBuffer ( defqry ) ;
destroyPQExpBuffer ( delqry ) ;
}
1996-07-09 06:22:35 +00:00
/*
* dumpOprs
1997-09-07 05:04:48 +00:00
* writes out to fout the queries to recreate all the user - defined operators
1996-07-09 06:22:35 +00:00
*/
1997-09-07 05:04:48 +00:00
void
2002-05-10 22:36:27 +00:00
dumpOprs ( Archive * fout , OprInfo * oprinfo , int numOperators )
1996-07-09 06:22:35 +00:00
{
1999-05-25 16:15:34 +00:00
int i ;
1997-09-07 05:04:48 +00:00
for ( i = 0 ; i < numOperators ; i + + )
{
2002-05-10 22:36:27 +00:00
/* Dump only operators in dumpable namespaces */
if ( ! oprinfo [ i ] . oprnamespace - > dump )
1997-09-07 05:04:48 +00:00
continue ;
/*
2002-05-10 22:36:27 +00:00
* some operators are invalid because they were the result of user
1997-09-07 05:04:48 +00:00
* defining operators before commutators exist
*/
2002-05-10 22:36:27 +00:00
if ( strcmp ( oprinfo [ i ] . oprcode , " 0 " ) = = 0 )
1997-09-07 05:04:48 +00:00
continue ;
2002-05-10 22:36:27 +00:00
/* OK, dump it */
dumpOneOpr ( fout , & oprinfo [ i ] ,
oprinfo , numOperators ) ;
}
}
2001-01-28 02:57:06 +00:00
2002-05-10 22:36:27 +00:00
/*
* dumpOneOpr
* write out a single operator definition
*/
static void
dumpOneOpr ( Archive * fout , OprInfo * oprinfo ,
OprInfo * g_oprinfo , int numOperators )
{
PQExpBuffer query = createPQExpBuffer ( ) ;
PQExpBuffer q = createPQExpBuffer ( ) ;
PQExpBuffer delq = createPQExpBuffer ( ) ;
PQExpBuffer oprid = createPQExpBuffer ( ) ;
PQExpBuffer details = createPQExpBuffer ( ) ;
const char * name ;
PGresult * res ;
int ntups ;
int i_oprkind ;
int i_oprcode ;
int i_oprleft ;
int i_oprright ;
int i_oprcom ;
int i_oprnegate ;
int i_oprrest ;
int i_oprjoin ;
int i_oprcanhash ;
int i_oprlsortop ;
int i_oprrsortop ;
int i_oprltcmpop ;
int i_oprgtcmpop ;
char * oprkind ;
char * oprcode ;
char * oprleft ;
char * oprright ;
char * oprcom ;
char * oprnegate ;
char * oprrest ;
char * oprjoin ;
char * oprcanhash ;
char * oprlsortop ;
char * oprrsortop ;
char * oprltcmpop ;
char * oprgtcmpop ;
/* Make sure we are in proper schema so regoperator works correctly */
selectSourceSchema ( oprinfo - > oprnamespace - > nspname ) ;
if ( g_fout - > remoteVersion > = 70300 )
{
2002-05-28 22:26:57 +00:00
appendPQExpBuffer ( query , " SELECT oprkind, "
" oprcode::pg_catalog.regprocedure, "
" oprleft::pg_catalog.regtype, "
" oprright::pg_catalog.regtype, "
" oprcom::pg_catalog.regoperator, "
" oprnegate::pg_catalog.regoperator, "
" oprrest::pg_catalog.regprocedure, "
" oprjoin::pg_catalog.regprocedure, "
2002-05-10 22:36:27 +00:00
" oprcanhash, "
2002-05-28 22:26:57 +00:00
" oprlsortop::pg_catalog.regoperator, "
" oprrsortop::pg_catalog.regoperator, "
" oprltcmpop::pg_catalog.regoperator, "
" oprgtcmpop::pg_catalog.regoperator "
" from pg_catalog.pg_operator "
" where oid = '%s'::pg_catalog.oid " ,
2002-05-10 22:36:27 +00:00
oprinfo - > oid ) ;
}
else if ( g_fout - > remoteVersion > = 70100 )
{
appendPQExpBuffer ( query , " SELECT oprkind, oprcode, "
" CASE WHEN oprleft = 0 THEN '-' "
" ELSE format_type(oprleft, NULL) END as oprleft, "
" CASE WHEN oprright = 0 THEN '-' "
" ELSE format_type(oprright, NULL) END as oprright, "
" oprcom, oprnegate, oprrest, oprjoin, "
" oprcanhash, oprlsortop, oprrsortop, "
" 0 as oprltcmpop, 0 as oprgtcmpop "
" from pg_operator "
" where oid = '%s'::oid " ,
oprinfo - > oid ) ;
}
else
{
appendPQExpBuffer ( query , " SELECT oprkind, oprcode, "
" CASE WHEN oprleft = 0 THEN '-'::name "
" ELSE (select typname from pg_type where oid = oprleft) END as oprleft, "
" CASE WHEN oprright = 0 THEN '-'::name "
" ELSE (select typname from pg_type where oid = oprright) END as oprright, "
" oprcom, oprnegate, oprrest, oprjoin, "
" oprcanhash, oprlsortop, oprrsortop, "
" 0 as oprltcmpop, 0 as oprgtcmpop "
" from pg_operator "
" where oid = '%s'::oid " ,
oprinfo - > oid ) ;
}
2001-01-28 02:57:06 +00:00
2002-05-10 22:36:27 +00:00
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to obtain list of operators failed: %s " , PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
/* Expecting a single result only */
ntups = PQntuples ( res ) ;
if ( ntups ! = 1 )
{
write_msg ( NULL , " Got %d rows instead of one from: %s " ,
ntups , query - > data ) ;
exit_nicely ( ) ;
}
i_oprkind = PQfnumber ( res , " oprkind " ) ;
i_oprcode = PQfnumber ( res , " oprcode " ) ;
i_oprleft = PQfnumber ( res , " oprleft " ) ;
i_oprright = PQfnumber ( res , " oprright " ) ;
i_oprcom = PQfnumber ( res , " oprcom " ) ;
i_oprnegate = PQfnumber ( res , " oprnegate " ) ;
i_oprrest = PQfnumber ( res , " oprrest " ) ;
i_oprjoin = PQfnumber ( res , " oprjoin " ) ;
i_oprcanhash = PQfnumber ( res , " oprcanhash " ) ;
i_oprlsortop = PQfnumber ( res , " oprlsortop " ) ;
i_oprrsortop = PQfnumber ( res , " oprrsortop " ) ;
i_oprltcmpop = PQfnumber ( res , " oprltcmpop " ) ;
i_oprgtcmpop = PQfnumber ( res , " oprgtcmpop " ) ;
oprkind = PQgetvalue ( res , 0 , i_oprkind ) ;
oprcode = PQgetvalue ( res , 0 , i_oprcode ) ;
oprleft = PQgetvalue ( res , 0 , i_oprleft ) ;
oprright = PQgetvalue ( res , 0 , i_oprright ) ;
oprcom = PQgetvalue ( res , 0 , i_oprcom ) ;
oprnegate = PQgetvalue ( res , 0 , i_oprnegate ) ;
oprrest = PQgetvalue ( res , 0 , i_oprrest ) ;
oprjoin = PQgetvalue ( res , 0 , i_oprjoin ) ;
oprcanhash = PQgetvalue ( res , 0 , i_oprcanhash ) ;
oprlsortop = PQgetvalue ( res , 0 , i_oprlsortop ) ;
oprrsortop = PQgetvalue ( res , 0 , i_oprrsortop ) ;
oprltcmpop = PQgetvalue ( res , 0 , i_oprltcmpop ) ;
oprgtcmpop = PQgetvalue ( res , 0 , i_oprgtcmpop ) ;
appendPQExpBuffer ( details , " PROCEDURE = %s " ,
convertRegProcReference ( oprcode ) ) ;
appendPQExpBuffer ( oprid , " %s ( " ,
oprinfo - > oprname ) ;
/*
* right unary means there ' s a left arg and left unary means
* there ' s a right arg
*/
if ( strcmp ( oprkind , " r " ) = = 0 | |
strcmp ( oprkind , " b " ) = = 0 )
{
if ( g_fout - > remoteVersion > = 70100 )
name = oprleft ;
else
name = fmtId ( oprleft , force_quotes ) ;
appendPQExpBuffer ( details , " , \n \t LEFTARG = %s " , name ) ;
appendPQExpBuffer ( oprid , " %s " , name ) ;
}
else
appendPQExpBuffer ( oprid , " NONE " ) ;
if ( strcmp ( oprkind , " l " ) = = 0 | |
strcmp ( oprkind , " b " ) = = 0 )
{
if ( g_fout - > remoteVersion > = 70100 )
name = oprright ;
else
name = fmtId ( oprright , force_quotes ) ;
appendPQExpBuffer ( details , " , \n \t RIGHTARG = %s " , name ) ;
appendPQExpBuffer ( oprid , " , %s) " , name ) ;
}
else
appendPQExpBuffer ( oprid , " , NONE) " ) ;
name = convertOperatorReference ( oprcom , g_oprinfo , numOperators ) ;
if ( name )
appendPQExpBuffer ( details , " , \n \t COMMUTATOR = %s " , name ) ;
name = convertOperatorReference ( oprnegate , g_oprinfo , numOperators ) ;
if ( name )
appendPQExpBuffer ( details , " , \n \t NEGATOR = %s " , name ) ;
if ( strcmp ( oprcanhash , " t " ) = = 0 )
appendPQExpBuffer ( details , " , \n \t HASHES " ) ;
name = convertRegProcReference ( oprrest ) ;
if ( name )
appendPQExpBuffer ( details , " , \n \t RESTRICT = %s " , name ) ;
name = convertRegProcReference ( oprjoin ) ;
if ( name )
appendPQExpBuffer ( details , " , \n \t JOIN = %s " , name ) ;
name = convertOperatorReference ( oprlsortop , g_oprinfo , numOperators ) ;
if ( name )
appendPQExpBuffer ( details , " , \n \t SORT1 = %s " , name ) ;
name = convertOperatorReference ( oprrsortop , g_oprinfo , numOperators ) ;
if ( name )
appendPQExpBuffer ( details , " , \n \t SORT2 = %s " , name ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
name = convertOperatorReference ( oprltcmpop , g_oprinfo , numOperators ) ;
if ( name )
appendPQExpBuffer ( details , " , \n \t LTCMP = %s " , name ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
name = convertOperatorReference ( oprgtcmpop , g_oprinfo , numOperators ) ;
if ( name )
appendPQExpBuffer ( details , " , \n \t GTCMP = %s " , name ) ;
1997-09-07 05:04:48 +00:00
2002-05-28 22:26:57 +00:00
/* DROP must be fully qualified in case same name appears in pg_catalog */
appendPQExpBuffer ( delq , " DROP OPERATOR %s.%s; \n " ,
fmtId ( oprinfo - > oprnamespace - > nspname , force_quotes ) ,
2002-05-10 22:36:27 +00:00
oprid - > data ) ;
appendPQExpBuffer ( q , " CREATE OPERATOR %s (%s); \n " ,
oprinfo - > oprname , details - > data ) ;
ArchiveEntry ( fout , oprinfo - > oid , oprinfo - > oprname ,
oprinfo - > oprnamespace - > nspname , oprinfo - > usename ,
" OPERATOR " , NULL ,
q - > data , delq - > data ,
NULL , NULL , NULL ) ;
2002-05-13 17:45:30 +00:00
/*** Dump Operator Comments ***/
resetPQExpBuffer ( q ) ;
appendPQExpBuffer ( q , " OPERATOR %s " , oprid - > data ) ;
dumpComment ( fout , q - > data ,
oprinfo - > oprnamespace - > nspname , oprinfo - > usename ,
oprinfo - > oid , " pg_operator " , 0 , NULL ) ;
2002-05-10 22:36:27 +00:00
PQclear ( res ) ;
destroyPQExpBuffer ( query ) ;
destroyPQExpBuffer ( q ) ;
destroyPQExpBuffer ( delq ) ;
destroyPQExpBuffer ( oprid ) ;
destroyPQExpBuffer ( details ) ;
}
/*
* Convert a function reference obtained from pg_operator
*
* Returns what to print , or NULL if function references is InvalidOid
*
* In 7.3 the input is a REGPROCEDURE display ; we have to strip the
* argument - types part . In prior versions , the input is a REGPROC display .
*/
static const char *
convertRegProcReference ( const char * proc )
{
/* In all cases "-" means a null reference */
if ( strcmp ( proc , " - " ) = = 0 )
return NULL ;
if ( g_fout - > remoteVersion > = 70300 )
{
char * name ;
char * paren ;
bool inquote ;
name = strdup ( proc ) ;
/* find non-double-quoted left paren */
inquote = false ;
for ( paren = name ; * paren ; paren + + )
2001-01-28 02:57:06 +00:00
{
2002-05-10 22:36:27 +00:00
if ( * paren = = ' ( ' & & ! inquote )
2001-01-28 02:57:06 +00:00
{
2002-05-10 22:36:27 +00:00
* paren = ' \0 ' ;
break ;
2001-01-28 02:57:06 +00:00
}
2002-05-10 22:36:27 +00:00
if ( * paren = = ' " ' )
inquote = ! inquote ;
2001-01-28 02:57:06 +00:00
}
2002-05-10 22:36:27 +00:00
return name ;
}
/* REGPROC before 7.3 does not quote its result */
return fmtId ( proc , false ) ;
}
/*
* Convert an operator cross - reference obtained from pg_operator
*
* Returns what to print , or NULL to print nothing
*
* In 7.3 the input is a REGOPERATOR display ; we have to strip the
* argument - types part . In prior versions , the input is just a
* numeric OID , which we search our operator list for .
*/
static const char *
convertOperatorReference ( const char * opr ,
OprInfo * g_oprinfo , int numOperators )
{
char * name ;
/* In all cases "0" means a null reference */
if ( strcmp ( opr , " 0 " ) = = 0 )
return NULL ;
if ( g_fout - > remoteVersion > = 70300 )
{
char * paren ;
bool inquote ;
1999-04-14 23:47:19 +00:00
2002-05-10 22:36:27 +00:00
name = strdup ( opr ) ;
/* find non-double-quoted left paren */
inquote = false ;
for ( paren = name ; * paren ; paren + + )
2001-01-28 02:57:06 +00:00
{
2002-05-10 22:36:27 +00:00
if ( * paren = = ' ( ' & & ! inquote )
2001-01-28 02:57:06 +00:00
{
2002-05-10 22:36:27 +00:00
* paren = ' \0 ' ;
break ;
2001-01-28 02:57:06 +00:00
}
2002-05-10 22:36:27 +00:00
if ( * paren = = ' " ' )
inquote = ! inquote ;
2001-01-28 02:57:06 +00:00
}
2002-05-10 22:36:27 +00:00
return name ;
1997-09-07 05:04:48 +00:00
}
2001-08-03 19:43:05 +00:00
2002-05-10 22:36:27 +00:00
name = findOprByOid ( g_oprinfo , numOperators , opr ) ;
if ( name = = NULL )
write_msg ( NULL , " WARNING: cannot find operator with OID %s \n " ,
opr ) ;
return name ;
1996-07-09 06:22:35 +00:00
}
2002-07-30 21:56:04 +00:00
/*
* dumpOpclasses
* writes out to fout the queries to recreate all the user - defined
* operator classes
*/
void
dumpOpclasses ( Archive * fout , OpclassInfo * opcinfo , int numOpclasses )
{
int i ;
for ( i = 0 ; i < numOpclasses ; i + + )
{
/* Dump only opclasses in dumpable namespaces */
if ( ! opcinfo [ i ] . opcnamespace - > dump )
continue ;
/* OK, dump it */
dumpOneOpclass ( fout , & opcinfo [ i ] ) ;
}
}
/*
* dumpOneOpclass
* write out a single operator class definition
*/
static void
dumpOneOpclass ( Archive * fout , OpclassInfo * opcinfo )
{
PQExpBuffer query = createPQExpBuffer ( ) ;
PQExpBuffer q = createPQExpBuffer ( ) ;
PQExpBuffer delq = createPQExpBuffer ( ) ;
PGresult * res ;
int ntups ;
int i_opcintype ;
int i_opckeytype ;
int i_opcdefault ;
int i_amname ;
int i_amopstrategy ;
int i_amopreqcheck ;
int i_amopopr ;
int i_amprocnum ;
int i_amproc ;
char * opcintype ;
char * opckeytype ;
char * opcdefault ;
char * amname ;
char * amopstrategy ;
char * amopreqcheck ;
char * amopopr ;
char * amprocnum ;
char * amproc ;
bool needComma ;
int i ;
/*
* XXX currently we do not implement dumping of operator classes from
* pre - 7.3 databases . This could be done but it seems not worth the
* trouble .
*/
if ( g_fout - > remoteVersion < 70300 )
return ;
/* Make sure we are in proper schema so regoperator works correctly */
selectSourceSchema ( opcinfo - > opcnamespace - > nspname ) ;
/* Get additional fields from the pg_opclass row */
appendPQExpBuffer ( query , " SELECT opcintype::pg_catalog.regtype, "
" opckeytype::pg_catalog.regtype, "
" opcdefault, "
" (SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
" FROM pg_catalog.pg_opclass "
" WHERE oid = '%s'::pg_catalog.oid " ,
opcinfo - > oid ) ;
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to obtain opclass details failed: %s " , PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
/* Expecting a single result only */
ntups = PQntuples ( res ) ;
if ( ntups ! = 1 )
{
write_msg ( NULL , " Got %d rows instead of one from: %s " ,
ntups , query - > data ) ;
exit_nicely ( ) ;
}
i_opcintype = PQfnumber ( res , " opcintype " ) ;
i_opckeytype = PQfnumber ( res , " opckeytype " ) ;
i_opcdefault = PQfnumber ( res , " opcdefault " ) ;
i_amname = PQfnumber ( res , " amname " ) ;
opcintype = PQgetvalue ( res , 0 , i_opcintype ) ;
opckeytype = PQgetvalue ( res , 0 , i_opckeytype ) ;
opcdefault = PQgetvalue ( res , 0 , i_opcdefault ) ;
amname = PQgetvalue ( res , 0 , i_amname ) ;
/* DROP must be fully qualified in case same name appears in pg_catalog */
appendPQExpBuffer ( delq , " DROP OPERATOR CLASS %s " ,
fmtId ( opcinfo - > opcnamespace - > nspname , force_quotes ) ) ;
appendPQExpBuffer ( delq , " .%s " ,
fmtId ( opcinfo - > opcname , force_quotes ) ) ;
appendPQExpBuffer ( delq , " USING %s; \n " ,
fmtId ( amname , force_quotes ) ) ;
/* Build the fixed portion of the CREATE command */
appendPQExpBuffer ( q , " CREATE OPERATOR CLASS %s \n \t " ,
fmtId ( opcinfo - > opcname , force_quotes ) ) ;
if ( strcmp ( opcdefault , " t " ) = = 0 )
appendPQExpBuffer ( q , " DEFAULT " ) ;
appendPQExpBuffer ( q , " FOR TYPE %s USING %s AS \n \t " ,
opcintype ,
fmtId ( amname , force_quotes ) ) ;
needComma = false ;
if ( strcmp ( opckeytype , " - " ) ! = 0 )
{
appendPQExpBuffer ( q , " STORAGE \t %s " ,
opckeytype ) ;
needComma = true ;
}
PQclear ( res ) ;
/*
* Now fetch and print the OPERATOR entries ( pg_amop rows ) .
*/
resetPQExpBuffer ( query ) ;
appendPQExpBuffer ( query , " SELECT amopstrategy, amopreqcheck, "
" amopopr::pg_catalog.regoperator "
" FROM pg_catalog.pg_amop "
" WHERE amopclaid = '%s'::pg_catalog.oid "
" ORDER BY amopstrategy " ,
opcinfo - > oid ) ;
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to obtain opclass operators failed: %s " , PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
ntups = PQntuples ( res ) ;
i_amopstrategy = PQfnumber ( res , " amopstrategy " ) ;
i_amopreqcheck = PQfnumber ( res , " amopreqcheck " ) ;
i_amopopr = PQfnumber ( res , " amopopr " ) ;
for ( i = 0 ; i < ntups ; i + + )
{
amopstrategy = PQgetvalue ( res , i , i_amopstrategy ) ;
amopreqcheck = PQgetvalue ( res , i , i_amopreqcheck ) ;
amopopr = PQgetvalue ( res , i , i_amopopr ) ;
if ( needComma )
appendPQExpBuffer ( q , " , \n \t " ) ;
appendPQExpBuffer ( q , " OPERATOR \t %s \t %s " ,
amopstrategy , amopopr ) ;
if ( strcmp ( amopreqcheck , " t " ) = = 0 )
appendPQExpBuffer ( q , " \t RECHECK " ) ;
needComma = true ;
}
PQclear ( res ) ;
/*
* Now fetch and print the FUNCTION entries ( pg_amproc rows ) .
*/
resetPQExpBuffer ( query ) ;
appendPQExpBuffer ( query , " SELECT amprocnum, "
" amproc::pg_catalog.regprocedure "
" FROM pg_catalog.pg_amproc "
" WHERE amopclaid = '%s'::pg_catalog.oid "
" ORDER BY amprocnum " ,
opcinfo - > oid ) ;
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to obtain opclass functions failed: %s " , PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
ntups = PQntuples ( res ) ;
i_amprocnum = PQfnumber ( res , " amprocnum " ) ;
i_amproc = PQfnumber ( res , " amproc " ) ;
for ( i = 0 ; i < ntups ; i + + )
{
amprocnum = PQgetvalue ( res , i , i_amprocnum ) ;
amproc = PQgetvalue ( res , i , i_amproc ) ;
if ( needComma )
appendPQExpBuffer ( q , " , \n \t " ) ;
appendPQExpBuffer ( q , " FUNCTION \t %s \t %s " ,
amprocnum , amproc ) ;
needComma = true ;
}
PQclear ( res ) ;
appendPQExpBuffer ( q , " ; \n " ) ;
ArchiveEntry ( fout , opcinfo - > oid , opcinfo - > opcname ,
opcinfo - > opcnamespace - > nspname , opcinfo - > usename ,
" OPERATOR CLASS " , NULL ,
q - > data , delq - > data ,
NULL , NULL , NULL ) ;
destroyPQExpBuffer ( query ) ;
destroyPQExpBuffer ( q ) ;
destroyPQExpBuffer ( delq ) ;
}
1996-07-09 06:22:35 +00:00
/*
* dumpAggs
1997-09-07 05:04:48 +00:00
* writes out to fout the queries to create all the user - defined aggregates
1996-07-09 06:22:35 +00:00
*/
void
2002-05-19 10:08:25 +00:00
dumpAggs ( Archive * fout , AggInfo agginfo [ ] , int numAggs )
1996-07-09 06:22:35 +00:00
{
1999-05-25 16:15:34 +00:00
int i ;
2002-05-10 22:36:27 +00:00
for ( i = 0 ; i < numAggs ; i + + )
{
/* Dump only aggs in dumpable namespaces */
if ( ! agginfo [ i ] . aggnamespace - > dump )
continue ;
dumpOneAgg ( fout , & agginfo [ i ] ) ;
2002-05-19 10:08:25 +00:00
if ( ! aclsSkip )
dumpAggACL ( fout , & agginfo [ i ] ) ;
}
}
2002-05-28 22:26:57 +00:00
/*
* format_aggregate_signature : generate aggregate name and argument list
*
* The argument type names are qualified if needed . The aggregate name
* is never qualified .
*/
2002-05-19 10:08:25 +00:00
static char *
2002-07-04 03:04:55 +00:00
format_aggregate_signature ( AggInfo * agginfo , Archive * fout , bool honor_quotes )
2002-05-19 10:08:25 +00:00
{
PQExpBufferData buf ;
bool anybasetype ;
initPQExpBuffer ( & buf ) ;
2002-07-04 03:04:55 +00:00
if ( honor_quotes )
appendPQExpBuffer ( & buf , " %s " ,
2002-05-19 10:08:25 +00:00
fmtId ( agginfo - > aggname , force_quotes ) ) ;
2002-07-04 03:04:55 +00:00
else
appendPQExpBuffer ( & buf , " %s " , agginfo - > aggname ) ;
2002-05-19 10:08:25 +00:00
2002-05-28 22:26:57 +00:00
anybasetype = ( strcmp ( agginfo - > aggbasetype , " 0 " ) = = 0 ) ;
2002-05-19 10:08:25 +00:00
2002-05-28 22:26:57 +00:00
/* If using regtype or format_type, fmtbasetype is already quoted */
2002-05-19 10:08:25 +00:00
if ( fout - > remoteVersion > = 70100 )
{
if ( anybasetype )
appendPQExpBuffer ( & buf , " (*) " ) ;
else
2002-05-28 22:26:57 +00:00
appendPQExpBuffer ( & buf , " (%s) " , agginfo - > fmtbasetype ) ;
2002-05-10 22:36:27 +00:00
}
2002-05-19 10:08:25 +00:00
else
{
if ( anybasetype )
appendPQExpBuffer ( & buf , " (*) " ) ;
else
appendPQExpBuffer ( & buf , " (%s) " ,
2002-05-28 22:26:57 +00:00
fmtId ( agginfo - > fmtbasetype , force_quotes ) ) ;
2002-05-19 10:08:25 +00:00
}
return buf . data ;
2002-05-10 22:36:27 +00:00
}
2002-05-19 10:08:25 +00:00
static void
dumpAggACL ( Archive * fout , AggInfo * finfo )
{
2002-07-04 15:35:07 +00:00
char * aggsig , * aggsig_tag ;
2002-05-19 10:08:25 +00:00
2002-07-04 03:04:55 +00:00
aggsig = format_aggregate_signature ( finfo , fout , true ) ;
2002-07-04 15:35:07 +00:00
aggsig_tag = format_aggregate_signature ( finfo , fout , false ) ;
dumpACL ( fout , " FUNCTION " , aggsig , aggsig_tag ,
2002-07-04 03:04:55 +00:00
finfo - > aggnamespace - > nspname ,
2002-05-19 10:08:25 +00:00
finfo - > usename , finfo - > aggacl , finfo - > oid ) ;
free ( aggsig ) ;
2002-07-04 15:35:07 +00:00
free ( aggsig_tag ) ;
2002-05-19 10:08:25 +00:00
}
2002-05-10 22:36:27 +00:00
/*
* dumpOneAgg
* write out a single aggregate definition
*/
static void
dumpOneAgg ( Archive * fout , AggInfo * agginfo )
{
PQExpBuffer query = createPQExpBuffer ( ) ;
2000-04-12 17:17:23 +00:00
PQExpBuffer q = createPQExpBuffer ( ) ;
2000-07-04 14:25:28 +00:00
PQExpBuffer delq = createPQExpBuffer ( ) ;
2000-07-17 03:05:41 +00:00
PQExpBuffer details = createPQExpBuffer ( ) ;
2002-07-04 03:04:55 +00:00
char * aggsig ;
2002-07-04 15:35:07 +00:00
char * aggsig_tag ;
2002-05-10 22:36:27 +00:00
PGresult * res ;
int ntups ;
int i_aggtransfn ;
int i_aggfinalfn ;
int i_aggtranstype ;
int i_agginitval ;
2002-05-28 22:26:57 +00:00
int i_fmtbasetype ;
2002-05-10 22:36:27 +00:00
int i_convertok ;
const char * aggtransfn ;
const char * aggfinalfn ;
const char * aggtranstype ;
const char * agginitval ;
bool convertok ;
bool anybasetype ;
/* Make sure we are in proper schema */
selectSourceSchema ( agginfo - > aggnamespace - > nspname ) ;
/* Get aggregate-specific details */
if ( g_fout - > remoteVersion > = 70300 )
{
appendPQExpBuffer ( query , " SELECT aggtransfn, "
2002-05-28 22:26:57 +00:00
" aggfinalfn, aggtranstype::pg_catalog.regtype, "
2002-05-10 22:36:27 +00:00
" agginitval, "
2002-05-28 22:26:57 +00:00
" proargtypes[0]::pg_catalog.regtype as fmtbasetype, "
2002-05-10 22:36:27 +00:00
" 't'::boolean as convertok "
2002-05-28 22:26:57 +00:00
" from pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
2002-05-10 22:36:27 +00:00
" where a.aggfnoid = p.oid "
2002-05-28 22:26:57 +00:00
" and p.oid = '%s'::pg_catalog.oid " ,
2002-05-10 22:36:27 +00:00
agginfo - > oid ) ;
}
else if ( g_fout - > remoteVersion > = 70100 )
{
appendPQExpBuffer ( query , " SELECT aggtransfn, aggfinalfn, "
" format_type(aggtranstype, NULL) as aggtranstype, "
2002-05-28 22:26:57 +00:00
" agginitval, "
" CASE WHEN aggbasetype = 0 THEN '-' "
" ELSE format_type(aggbasetype, NULL) END as fmtbasetype, "
" 't'::boolean as convertok "
2002-05-10 22:36:27 +00:00
" from pg_aggregate "
" where oid = '%s'::oid " ,
agginfo - > oid ) ;
}
else
{
appendPQExpBuffer ( query , " SELECT aggtransfn1 as aggtransfn, "
" aggfinalfn, "
" (select typname from pg_type where oid = aggtranstype1) as aggtranstype, "
" agginitval1 as agginitval, "
2002-05-28 22:26:57 +00:00
" (select typname from pg_type where oid = aggbasetype) as fmtbasetype, "
2002-05-10 22:36:27 +00:00
" (aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) as convertok "
" from pg_aggregate "
" where oid = '%s'::oid " ,
agginfo - > oid ) ;
}
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
1997-09-07 05:04:48 +00:00
{
2002-05-10 22:36:27 +00:00
write_msg ( NULL , " query to obtain list of aggregate functions failed: %s " ,
PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
2001-01-28 02:57:06 +00:00
2002-05-10 22:36:27 +00:00
/* Expecting a single result only */
ntups = PQntuples ( res ) ;
if ( ntups ! = 1 )
{
write_msg ( NULL , " Got %d rows instead of one from: %s " ,
ntups , query - > data ) ;
exit_nicely ( ) ;
}
1999-12-27 15:42:44 +00:00
2002-05-10 22:36:27 +00:00
i_aggtransfn = PQfnumber ( res , " aggtransfn " ) ;
i_aggfinalfn = PQfnumber ( res , " aggfinalfn " ) ;
i_aggtranstype = PQfnumber ( res , " aggtranstype " ) ;
i_agginitval = PQfnumber ( res , " agginitval " ) ;
2002-05-28 22:26:57 +00:00
i_fmtbasetype = PQfnumber ( res , " fmtbasetype " ) ;
2002-05-10 22:36:27 +00:00
i_convertok = PQfnumber ( res , " convertok " ) ;
2001-04-25 07:03:20 +00:00
2002-05-10 22:36:27 +00:00
aggtransfn = PQgetvalue ( res , 0 , i_aggtransfn ) ;
aggfinalfn = PQgetvalue ( res , 0 , i_aggfinalfn ) ;
aggtranstype = PQgetvalue ( res , 0 , i_aggtranstype ) ;
agginitval = PQgetvalue ( res , 0 , i_agginitval ) ;
2002-05-28 22:26:57 +00:00
/* we save fmtbasetype so that dumpAggACL can use it later */
agginfo - > fmtbasetype = strdup ( PQgetvalue ( res , 0 , i_fmtbasetype ) ) ;
2002-05-10 22:36:27 +00:00
convertok = ( PQgetvalue ( res , 0 , i_convertok ) [ 0 ] = = ' t ' ) ;
2001-04-25 07:03:20 +00:00
2002-07-04 03:04:55 +00:00
aggsig = format_aggregate_signature ( agginfo , g_fout , true ) ;
2002-07-04 15:35:07 +00:00
aggsig_tag = format_aggregate_signature ( agginfo , g_fout , false ) ;
2001-07-03 20:21:50 +00:00
2002-05-10 22:36:27 +00:00
if ( ! convertok )
{
write_msg ( NULL , " WARNING: aggregate function %s could not be dumped correctly for this database version; ignored \n " ,
2002-07-04 03:04:55 +00:00
aggsig ) ;
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( q , " -- WARNING: aggregate function %s could not be dumped correctly for this database version; ignored \n " ,
2002-07-04 03:04:55 +00:00
aggsig ) ;
2002-07-04 15:35:07 +00:00
ArchiveEntry ( fout , agginfo - > oid , aggsig_tag ,
2002-05-10 22:36:27 +00:00
agginfo - > aggnamespace - > nspname , agginfo - > usename ,
" WARNING " , NULL ,
q - > data , " " /* Del */ ,
NULL , NULL , NULL ) ;
return ;
}
1997-09-07 05:04:48 +00:00
2002-05-28 22:26:57 +00:00
anybasetype = ( strcmp ( agginfo - > aggbasetype , " 0 " ) = = 0 ) ;
2002-05-19 10:08:25 +00:00
2002-05-10 22:36:27 +00:00
if ( g_fout - > remoteVersion > = 70300 )
{
/* If using 7.3's regproc or regtype, data is already quoted */
appendPQExpBuffer ( details , " BASETYPE = %s, SFUNC = %s, STYPE = %s " ,
2002-05-28 22:26:57 +00:00
anybasetype ? " 'any' " : agginfo - > fmtbasetype ,
2002-05-10 22:36:27 +00:00
aggtransfn ,
aggtranstype ) ;
}
else if ( g_fout - > remoteVersion > = 70100 )
{
/* format_type quotes, regproc does not */
appendPQExpBuffer ( details , " BASETYPE = %s, SFUNC = %s, STYPE = %s " ,
2002-05-28 22:26:57 +00:00
anybasetype ? " 'any' " : agginfo - > fmtbasetype ,
2002-05-10 22:36:27 +00:00
fmtId ( aggtransfn , force_quotes ) ,
aggtranstype ) ;
}
else
{
/* need quotes all around */
appendPQExpBuffer ( details , " BASETYPE = %s, " ,
anybasetype ? " 'any' " :
2002-05-28 22:26:57 +00:00
fmtId ( agginfo - > fmtbasetype , force_quotes ) ) ;
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( details , " SFUNC = %s, " ,
fmtId ( aggtransfn , force_quotes ) ) ;
appendPQExpBuffer ( details , " STYPE = %s " ,
fmtId ( aggtranstype , force_quotes ) ) ;
}
2001-07-03 20:21:50 +00:00
2002-05-10 22:36:27 +00:00
if ( ! PQgetisnull ( res , 0 , i_agginitval ) )
{
appendPQExpBuffer ( details , " , INITCOND = " ) ;
formatStringLiteral ( details , agginitval , CONV_ALL ) ;
}
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
if ( strcmp ( aggfinalfn , " - " ) ! = 0 )
{
appendPQExpBuffer ( details , " , FINALFUNC = %s " ,
aggfinalfn ) ;
}
1997-09-07 05:04:48 +00:00
2002-05-28 22:26:57 +00:00
/* DROP must be fully qualified in case same name appears in pg_catalog */
appendPQExpBuffer ( delq , " DROP AGGREGATE %s.%s; \n " ,
fmtId ( agginfo - > aggnamespace - > nspname , force_quotes ) ,
2002-07-04 03:04:55 +00:00
aggsig ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( q , " CREATE AGGREGATE %s ( %s ); \n " ,
fmtId ( agginfo - > aggname , force_quotes ) ,
details - > data ) ;
1999-01-21 22:53:37 +00:00
2002-07-04 15:35:07 +00:00
ArchiveEntry ( fout , agginfo - > oid , aggsig_tag ,
2002-05-10 22:36:27 +00:00
agginfo - > aggnamespace - > nspname , agginfo - > usename ,
" AGGREGATE " , NULL ,
q - > data , delq - > data ,
NULL , NULL , NULL ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
/*** Dump Aggregate Comments ***/
2000-01-18 18:09:02 +00:00
2002-05-10 22:36:27 +00:00
resetPQExpBuffer ( q ) ;
2002-07-04 03:04:55 +00:00
appendPQExpBuffer ( q , " AGGREGATE %s " , aggsig ) ;
2002-05-10 22:36:27 +00:00
if ( g_fout - > remoteVersion > = 70300 )
dumpComment ( fout , q - > data ,
agginfo - > aggnamespace - > nspname , agginfo - > usename ,
agginfo - > oid , " pg_proc " , 0 , NULL ) ;
else
dumpComment ( fout , q - > data ,
agginfo - > aggnamespace - > nspname , agginfo - > usename ,
agginfo - > oid , " pg_aggregate " , 0 , NULL ) ;
2000-01-18 18:09:02 +00:00
2002-05-10 22:36:27 +00:00
PQclear ( res ) ;
2001-08-03 19:43:05 +00:00
2002-05-10 22:36:27 +00:00
destroyPQExpBuffer ( query ) ;
2001-08-03 19:43:05 +00:00
destroyPQExpBuffer ( q ) ;
destroyPQExpBuffer ( delq ) ;
destroyPQExpBuffer ( details ) ;
2002-07-04 03:04:55 +00:00
free ( aggsig ) ;
2002-07-04 15:35:07 +00:00
free ( aggsig_tag ) ;
1996-07-09 06:22:35 +00:00
}
2002-05-10 22:36:27 +00:00
1997-12-04 01:31:28 +00:00
/*
* These are some support functions to fix the acl problem of pg_dump
*
* Matthew C . Aycock 12 / 02 / 97
*/
1998-12-05 22:09:57 +00:00
/* Append a keyword to a keyword list, inserting comma if needed.
* Caller must make aclbuf big enough for all possible keywords .
1997-12-04 01:31:28 +00:00
*/
1998-12-05 22:09:57 +00:00
static void
1999-05-25 16:15:34 +00:00
AddAcl ( char * aclbuf , const char * keyword )
1997-12-04 01:31:28 +00:00
{
1998-12-05 22:09:57 +00:00
if ( * aclbuf )
strcat ( aclbuf , " , " ) ;
strcat ( aclbuf , keyword ) ;
1997-12-04 01:31:28 +00:00
}
1998-02-26 04:46:47 +00:00
1997-12-04 01:31:28 +00:00
/*
2002-01-25 18:49:31 +00:00
* This will take a string of privilege code letters and return a malloced ,
* comma delimited string of keywords for GRANT .
*
* Note : for cross - version compatibility , it ' s important to use ALL when
* appropriate .
1997-12-04 01:31:28 +00:00
*/
1997-12-26 08:45:27 +00:00
static char *
2002-05-19 10:08:25 +00:00
GetPrivileges ( Archive * AH , const char * s , const char * type )
1997-12-04 01:31:28 +00:00
{
1998-12-05 22:09:57 +00:00
char aclbuf [ 100 ] ;
2002-01-25 18:49:31 +00:00
bool all = true ;
1997-12-04 01:31:28 +00:00
1998-12-05 22:09:57 +00:00
aclbuf [ 0 ] = ' \0 ' ;
1997-12-04 01:31:28 +00:00
2002-01-25 18:49:31 +00:00
# define CONVERT_PRIV(code,keywd) \
if ( strchr ( s , code ) ) \
AddAcl ( aclbuf , keywd ) ; \
else \
all = false
1997-12-04 01:31:28 +00:00
2002-05-19 10:08:25 +00:00
if ( strcmp ( type , " TABLE " ) = = 0 )
{
CONVERT_PRIV ( ' a ' , " INSERT " ) ;
CONVERT_PRIV ( ' r ' , " SELECT " ) ;
CONVERT_PRIV ( ' R ' , " RULE " ) ;
1997-12-04 01:31:28 +00:00
2002-05-19 10:08:25 +00:00
if ( AH - > remoteVersion > = 70200 )
{
CONVERT_PRIV ( ' w ' , " UPDATE " ) ;
CONVERT_PRIV ( ' d ' , " DELETE " ) ;
CONVERT_PRIV ( ' x ' , " REFERENCES " ) ;
CONVERT_PRIV ( ' t ' , " TRIGGER " ) ;
}
else
{
/* 7.0 and 7.1 have a simpler worldview */
CONVERT_PRIV ( ' w ' , " UPDATE,DELETE " ) ;
}
}
else if ( strcmp ( type , " FUNCTION " ) = = 0 )
2001-08-12 19:02:39 +00:00
{
2002-05-19 10:08:25 +00:00
CONVERT_PRIV ( ' X ' , " EXECUTE " ) ;
2001-08-12 19:02:39 +00:00
}
2002-05-19 10:08:25 +00:00
else if ( strcmp ( type , " LANGUAGE " ) = = 0 )
2001-08-12 19:02:39 +00:00
{
2002-05-19 10:08:25 +00:00
CONVERT_PRIV ( ' U ' , " USAGE " ) ;
2001-08-12 19:02:39 +00:00
}
2002-05-28 22:26:57 +00:00
else if ( strcmp ( type , " SCHEMA " ) = = 0 )
{
CONVERT_PRIV ( ' C ' , " CREATE " ) ;
CONVERT_PRIV ( ' U ' , " USAGE " ) ;
}
2002-05-19 10:08:25 +00:00
else
abort ( ) ;
1998-02-26 04:46:47 +00:00
2002-01-25 18:49:31 +00:00
# undef CONVERT_PRIV
if ( all )
return strdup ( " ALL " ) ;
else
return strdup ( aclbuf ) ;
1997-12-04 01:31:28 +00:00
}
1998-09-01 04:40:42 +00:00
2000-07-04 14:25:28 +00:00
1998-04-07 22:36:38 +00:00
/*
2002-05-19 10:08:25 +00:00
* Write out grant / revoke information
*
2002-05-28 22:26:57 +00:00
* ' type ' must be TABLE , FUNCTION , LANGUAGE , or SCHEMA . ' name ' is the
2002-05-19 10:08:25 +00:00
* formatted name of the object . Must be quoted etc . already .
2002-05-28 22:26:57 +00:00
* ' nspname ' is the namespace the object is in ( NULL if none ) .
* ' usename ' is the owner , NULL if there is no owner ( for languages ) .
* ' acls ' is the string read out of the fooacl system catalog field ;
* it will be parsed here .
* ' objoid ' is the OID of the object for purposes of ordering .
1998-04-07 22:36:38 +00:00
*/
1998-10-26 01:05:07 +00:00
static void
2002-05-19 10:08:25 +00:00
dumpACL ( Archive * fout , const char * type , const char * name ,
2002-07-04 15:35:07 +00:00
const char * tag , const char * nspname , const char * usename ,
2002-05-19 10:08:25 +00:00
const char * acls , const char * objoid )
1998-04-07 22:36:38 +00:00
{
2001-03-22 04:01:46 +00:00
char * aclbuf ,
1999-05-25 16:15:34 +00:00
* tok ,
* eqpos ,
* priv ;
2002-05-06 18:33:45 +00:00
PQExpBuffer sql ;
bool found_owner_privs = false ;
1998-12-05 22:09:57 +00:00
if ( strlen ( acls ) = = 0 )
2002-05-28 22:26:57 +00:00
return ; /* object has default permissions */
1998-12-05 22:09:57 +00:00
2002-05-06 18:33:45 +00:00
sql = createPQExpBuffer ( ) ;
1998-12-05 22:09:57 +00:00
/* Make a working copy of acls so we can use strtok */
aclbuf = strdup ( acls ) ;
1998-04-07 22:36:38 +00:00
1998-12-05 22:09:57 +00:00
/* Scan comma-separated ACL items */
for ( tok = strtok ( aclbuf , " , " ) ; tok ! = NULL ; tok = strtok ( NULL , " , " ) )
1998-11-06 15:54:47 +00:00
{
1999-05-25 16:15:34 +00:00
/*
* Token may start with ' { ' and / or ' " ' . Actually only the start
* of the string should have ' { ' , but we don ' t verify that .
1998-12-05 22:09:57 +00:00
*/
if ( * tok = = ' { ' )
tok + + ;
if ( * tok = = ' " ' )
tok + + ;
/* User name is string up to = in tok */
eqpos = strchr ( tok , ' = ' ) ;
1999-05-25 16:15:34 +00:00
if ( ! eqpos )
1998-04-07 22:36:38 +00:00
{
2002-05-19 10:08:25 +00:00
write_msg ( NULL , " could not parse ACL list ('%s') for %s %s \n " ,
acls , type , name ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1998-04-07 22:36:38 +00:00
}
2002-05-06 18:33:45 +00:00
* eqpos = ' \0 ' ; /* it's ok to clobber aclbuf */
1998-04-07 22:36:38 +00:00
1999-05-25 16:15:34 +00:00
/*
2002-05-28 22:26:57 +00:00
* Parse the privileges ( right - hand side ) .
1999-05-25 16:15:34 +00:00
*/
2002-05-19 10:08:25 +00:00
priv = GetPrivileges ( fout , eqpos + 1 , type ) ;
1998-12-05 22:09:57 +00:00
if ( * priv )
1998-07-19 05:24:51 +00:00
{
2002-05-19 10:08:25 +00:00
if ( usename & & strcmp ( tok , usename ) = = 0 )
1998-12-05 22:09:57 +00:00
{
2002-05-06 18:33:45 +00:00
/*
* For the owner , the default privilege level is ALL .
*/
found_owner_privs = true ;
if ( strcmp ( priv , " ALL " ) ! = 0 )
{
/* NB: only one fmtId per appendPQExpBuffer! */
2002-05-19 10:08:25 +00:00
appendPQExpBuffer ( sql , " REVOKE ALL ON %s %s FROM " ,
type , name ) ;
2002-05-06 18:33:45 +00:00
appendPQExpBuffer ( sql , " %s; \n " , fmtId ( tok , force_quotes ) ) ;
2002-05-19 10:08:25 +00:00
appendPQExpBuffer ( sql , " GRANT %s ON %s %s TO " ,
priv , type , name ) ;
2002-05-06 18:33:45 +00:00
appendPQExpBuffer ( sql , " %s; \n " , fmtId ( tok , force_quotes ) ) ;
}
1998-12-05 22:09:57 +00:00
}
1998-07-19 05:24:51 +00:00
else
1998-12-05 22:09:57 +00:00
{
2002-05-06 18:33:45 +00:00
/*
* Otherwise can assume we are starting from no privs .
*/
2002-05-19 10:08:25 +00:00
appendPQExpBuffer ( sql , " GRANT %s ON %s %s TO " ,
priv , type , name ) ;
2002-05-06 18:33:45 +00:00
if ( eqpos = = tok )
{
/* Empty left-hand side means "PUBLIC" */
appendPQExpBuffer ( sql , " PUBLIC; \n " ) ;
}
else if ( strncmp ( tok , " group " , strlen ( " group " ) ) = = 0 )
appendPQExpBuffer ( sql , " GROUP %s; \n " ,
fmtId ( tok + strlen ( " group " ) ,
force_quotes ) ) ;
1999-05-26 21:51:13 +00:00
else
2002-05-06 18:33:45 +00:00
appendPQExpBuffer ( sql , " %s; \n " , fmtId ( tok , force_quotes ) ) ;
1998-12-05 22:09:57 +00:00
}
1998-07-19 05:24:51 +00:00
}
2002-05-28 22:26:57 +00:00
else
{
/* No privileges. Issue explicit REVOKE for safety. */
appendPQExpBuffer ( sql , " REVOKE ALL ON %s %s FROM " ,
type , name ) ;
if ( eqpos = = tok )
{
/* Empty left-hand side means "PUBLIC" */
appendPQExpBuffer ( sql , " PUBLIC; \n " ) ;
}
else if ( strncmp ( tok , " group " , strlen ( " group " ) ) = = 0 )
appendPQExpBuffer ( sql , " GROUP %s; \n " ,
fmtId ( tok + strlen ( " group " ) ,
force_quotes ) ) ;
else
appendPQExpBuffer ( sql , " %s; \n " , fmtId ( tok , force_quotes ) ) ;
}
1998-12-05 22:09:57 +00:00
free ( priv ) ;
1998-04-07 22:36:38 +00:00
}
1998-12-05 22:09:57 +00:00
2002-05-06 18:33:45 +00:00
/*
* If we didn ' t find any owner privs , the owner must have revoked ' em all
*/
2002-05-19 10:08:25 +00:00
if ( ! found_owner_privs & & usename )
2002-05-06 18:33:45 +00:00
{
2002-05-19 10:08:25 +00:00
appendPQExpBuffer ( sql , " REVOKE ALL ON %s %s FROM " ,
type , name ) ;
appendPQExpBuffer ( sql , " %s; \n " , fmtId ( usename , force_quotes ) ) ;
2002-05-06 18:33:45 +00:00
}
2002-07-04 15:35:07 +00:00
ArchiveEntry ( fout , objoid , tag , nspname , usename ? usename : " " ,
2002-05-19 10:08:25 +00:00
" ACL " , NULL , sql - > data , " " , NULL , NULL , NULL ) ;
2001-07-29 22:12:23 +00:00
2002-05-28 22:26:57 +00:00
free ( aclbuf ) ;
2002-05-06 18:33:45 +00:00
destroyPQExpBuffer ( sql ) ;
1998-04-07 22:36:38 +00:00
}
2002-05-19 10:08:25 +00:00
static void
dumpTableACL ( Archive * fout , TableInfo * tbinfo )
{
2002-07-04 03:04:55 +00:00
char * tmp = strdup ( fmtId ( tbinfo - > relname , force_quotes ) ) ;
dumpACL ( fout , " TABLE " , tmp , tbinfo - > relname ,
tbinfo - > relnamespace - > nspname , tbinfo - > usename , tbinfo - > relacl ,
2002-05-19 10:08:25 +00:00
tbinfo - > viewoid ! = NULL ? tbinfo - > viewoid : tbinfo - > oid ) ;
free ( tmp ) ;
}
2002-05-10 22:36:27 +00:00
/*
* dumpTables :
* write out to fout the declarations ( not data ) of all user - defined tables
*/
void
2002-05-19 10:08:25 +00:00
dumpTables ( Archive * fout , TableInfo tblinfo [ ] , int numTables ,
2002-05-10 22:36:27 +00:00
const bool aclsSkip , const bool schemaOnly , const bool dataOnly )
2001-04-25 07:03:20 +00:00
{
2002-05-10 22:36:27 +00:00
int i ;
2001-04-25 07:03:20 +00:00
2002-05-10 22:36:27 +00:00
/* Dump sequences first, in case they are referenced in table defn's */
for ( i = 0 ; i < numTables ; i + + )
2001-04-25 07:03:20 +00:00
{
2002-05-10 22:36:27 +00:00
TableInfo * tbinfo = & tblinfo [ i ] ;
2001-04-25 07:03:20 +00:00
2002-05-10 22:36:27 +00:00
if ( tbinfo - > relkind ! = RELKIND_SEQUENCE )
continue ;
2002-08-15 16:36:08 +00:00
2002-05-10 22:36:27 +00:00
if ( tbinfo - > dump )
2001-04-25 07:03:20 +00:00
{
2002-05-10 22:36:27 +00:00
dumpOneSequence ( fout , tbinfo , schemaOnly , dataOnly ) ;
if ( ! dataOnly & & ! aclsSkip )
2002-05-19 10:08:25 +00:00
dumpTableACL ( fout , tbinfo ) ;
2001-04-25 07:03:20 +00:00
}
}
2002-05-10 22:36:27 +00:00
if ( ! dataOnly )
2001-04-25 07:03:20 +00:00
{
2002-05-10 22:36:27 +00:00
for ( i = 0 ; i < numTables ; i + + )
2001-04-25 07:03:20 +00:00
{
2002-05-10 22:36:27 +00:00
TableInfo * tbinfo = & tblinfo [ i ] ;
2001-04-25 07:03:20 +00:00
2002-05-10 22:36:27 +00:00
if ( tbinfo - > relkind = = RELKIND_SEQUENCE ) /* already dumped */
continue ;
2002-08-15 16:36:08 +00:00
if ( tbinfo - > relkind = = RELKIND_COMPOSITE_TYPE ) /* dumped as a type */
continue ;
2002-05-10 22:36:27 +00:00
if ( tbinfo - > dump )
{
dumpOneTable ( fout , tbinfo , tblinfo ) ;
if ( ! aclsSkip )
2002-05-19 10:08:25 +00:00
dumpTableACL ( fout , tbinfo ) ;
2002-05-10 22:36:27 +00:00
}
}
2001-04-25 07:03:20 +00:00
}
}
1998-02-26 04:46:47 +00:00
1996-07-09 06:22:35 +00:00
/*
2002-05-10 22:36:27 +00:00
* dumpOneTable
* write the declaration ( not data ) of one user - defined table or view
1996-07-09 06:22:35 +00:00
*/
2002-05-10 22:36:27 +00:00
static void
dumpOneTable ( Archive * fout , TableInfo * tbinfo , TableInfo * g_tblinfo )
1996-07-09 06:22:35 +00:00
{
2002-05-10 22:36:27 +00:00
PQExpBuffer query = createPQExpBuffer ( ) ;
2000-04-12 17:17:23 +00:00
PQExpBuffer q = createPQExpBuffer ( ) ;
2000-07-04 14:25:28 +00:00
PQExpBuffer delq = createPQExpBuffer ( ) ;
2002-05-10 22:36:27 +00:00
PGresult * res ;
1997-09-08 02:41:22 +00:00
int numParents ;
2002-05-10 22:36:27 +00:00
int * parentIndexes ;
1999-05-25 16:15:34 +00:00
int actual_atts ; /* number of attrs in this CREATE statment */
2000-09-15 04:35:16 +00:00
char * reltypename ;
2001-04-14 13:11:03 +00:00
char * objoid ;
2001-08-03 19:43:05 +00:00
const char * ( ( * commentDeps ) [ ] ) ;
2002-05-10 22:36:27 +00:00
int j ,
k ;
1999-05-13 02:35:44 +00:00
2002-05-10 22:36:27 +00:00
/* Make sure we are in proper schema */
selectSourceSchema ( tbinfo - > relnamespace - > nspname ) ;
1998-02-26 04:46:47 +00:00
2002-05-10 22:36:27 +00:00
/* Is it a table or a view? */
if ( tbinfo - > relkind = = RELKIND_VIEW )
1997-09-07 05:04:48 +00:00
{
2002-05-10 22:36:27 +00:00
char * viewdef ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
reltypename = " VIEW " ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
/* Fetch the view definition */
if ( g_fout - > remoteVersion > = 70300 )
{
/* Beginning in 7.3, viewname is not unique; use OID */
2002-05-28 22:26:57 +00:00
appendPQExpBuffer ( query , " SELECT pg_catalog.pg_get_viewdef(ev_class) as viewdef, "
2002-05-10 22:36:27 +00:00
" oid as view_oid "
2002-05-28 22:26:57 +00:00
" from pg_catalog.pg_rewrite where "
" ev_class = '%s'::pg_catalog.oid and "
2002-05-10 22:36:27 +00:00
" rulename = '_RETURN'; " ,
tbinfo - > oid ) ;
}
else
{
appendPQExpBuffer ( query , " SELECT definition as viewdef, "
" (select oid from pg_rewrite where "
" rulename=('_RET' || viewname)::name) as view_oid "
" from pg_views where viewname = " ) ;
formatStringLiteral ( query , tbinfo - > relname , CONV_ALL ) ;
appendPQExpBuffer ( query , " ; " ) ;
}
2002-04-24 02:38:58 +00:00
2002-05-10 22:36:27 +00:00
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | | PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to obtain definition of view \" %s \" failed: %s " ,
tbinfo - > relname , PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
2002-04-24 02:38:58 +00:00
2002-05-10 22:36:27 +00:00
if ( PQntuples ( res ) ! = 1 )
{
if ( PQntuples ( res ) < 1 )
write_msg ( NULL , " query to obtain definition of view \" %s \" returned no data \n " ,
tbinfo - > relname ) ;
2000-09-15 04:35:16 +00:00
else
2002-05-10 22:36:27 +00:00
write_msg ( NULL , " query to obtain definition of view \" %s \" returned more than one definition \n " ,
tbinfo - > relname ) ;
exit_nicely ( ) ;
}
1999-05-25 16:15:34 +00:00
2002-05-10 22:36:27 +00:00
if ( PQgetisnull ( res , 0 , 1 ) )
{
write_msg ( NULL , " query to obtain definition of view \" %s \" returned NULL oid \n " ,
tbinfo - > relname ) ;
exit_nicely ( ) ;
}
2000-09-15 04:35:16 +00:00
2002-05-10 22:36:27 +00:00
viewdef = PQgetvalue ( res , 0 , 0 ) ;
2001-04-25 07:03:20 +00:00
2002-05-10 22:36:27 +00:00
if ( strlen ( viewdef ) = = 0 )
{
write_msg ( NULL , " definition of view \" %s \" appears to be empty (length zero) \n " ,
tbinfo - > relname ) ;
exit_nicely ( ) ;
}
2000-09-15 04:35:16 +00:00
2002-05-10 22:36:27 +00:00
/* We use the OID of the view rule as the object OID */
objoid = strdup ( PQgetvalue ( res , 0 , 1 ) ) ;
/* Save it for use by dumpACL, too */
tbinfo - > viewoid = objoid ;
2000-09-15 04:35:16 +00:00
2002-05-28 22:26:57 +00:00
/* DROP must be fully qualified in case same name appears in pg_catalog */
appendPQExpBuffer ( delq , " DROP VIEW %s. " ,
fmtId ( tbinfo - > relnamespace - > nspname , force_quotes ) ) ;
appendPQExpBuffer ( delq , " %s; \n " ,
2002-05-10 22:36:27 +00:00
fmtId ( tbinfo - > relname , force_quotes ) ) ;
2002-05-28 22:26:57 +00:00
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( q , " CREATE VIEW %s AS %s \n " ,
fmtId ( tbinfo - > relname , force_quotes ) , viewdef ) ;
2000-09-15 04:35:16 +00:00
2002-05-10 22:36:27 +00:00
PQclear ( res ) ;
1998-10-06 03:09:02 +00:00
2002-05-10 22:36:27 +00:00
/*
* Views can have default values - - however , they must be
* specified in an ALTER TABLE command after the view has
* been created , not in the view definition itself .
*/
for ( j = 0 ; j < tbinfo - > numatts ; j + + )
{
if ( tbinfo - > adef_expr [ j ] ! = NULL & & ! tbinfo - > inhAttrDef [ j ] )
{
appendPQExpBuffer ( q , " ALTER TABLE %s " ,
fmtId ( tbinfo - > relname , force_quotes ) ) ;
appendPQExpBuffer ( q , " ALTER COLUMN %s SET DEFAULT %s; \n " ,
fmtId ( tbinfo - > attnames [ j ] , force_quotes ) ,
tbinfo - > adef_expr [ j ] ) ;
}
}
2001-01-12 15:41:29 +00:00
2002-05-10 22:36:27 +00:00
commentDeps = malloc ( sizeof ( char * ) * 2 ) ;
( * commentDeps ) [ 0 ] = strdup ( objoid ) ;
( * commentDeps ) [ 1 ] = NULL ; /* end of list */
}
else
{
reltypename = " TABLE " ;
objoid = tbinfo - > oid ;
commentDeps = NULL ;
numParents = tbinfo - > numParents ;
parentIndexes = tbinfo - > parentIndexes ;
2001-01-12 15:41:29 +00:00
2002-05-28 22:26:57 +00:00
/* DROP must be fully qualified in case same name appears in pg_catalog */
appendPQExpBuffer ( delq , " DROP TABLE %s. " ,
fmtId ( tbinfo - > relnamespace - > nspname , force_quotes ) ) ;
appendPQExpBuffer ( delq , " %s; \n " ,
2002-05-10 22:36:27 +00:00
fmtId ( tbinfo - > relname , force_quotes ) ) ;
2000-09-15 04:35:16 +00:00
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( q , " CREATE TABLE %s ( \n \t " ,
fmtId ( tbinfo - > relname , force_quotes ) ) ;
actual_atts = 0 ;
for ( j = 0 ; j < tbinfo - > numatts ; j + + )
{
2002-08-02 18:15:10 +00:00
/* Is this one of the table's own attrs, and not dropped ? */
if ( ! tbinfo - > inhAttrs [ j ] & & ! tbinfo - > attisdropped [ j ] )
2002-05-10 22:36:27 +00:00
{
/* Format properly if not first attr */
if ( actual_atts > 0 )
appendPQExpBuffer ( q , " , \n \t " ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
/* Attr name & type */
appendPQExpBuffer ( q , " %s " ,
fmtId ( tbinfo - > attnames [ j ] , force_quotes ) ) ;
2001-01-12 15:41:29 +00:00
2002-05-10 22:36:27 +00:00
/* If no format_type, fake it */
if ( g_fout - > remoteVersion > = 70100 )
appendPQExpBuffer ( q , " %s " , tbinfo - > atttypnames [ j ] ) ;
else
appendPQExpBuffer ( q , " %s " ,
myFormatType ( tbinfo - > atttypnames [ j ] ,
tbinfo - > atttypmod [ j ] ) ) ;
1998-10-06 22:14:21 +00:00
2002-05-10 22:36:27 +00:00
/* Default value */
if ( tbinfo - > adef_expr [ j ] ! = NULL & & ! tbinfo - > inhAttrDef [ j ] )
appendPQExpBuffer ( q , " DEFAULT %s " ,
tbinfo - > adef_expr [ j ] ) ;
1998-10-06 03:09:02 +00:00
2002-05-10 22:36:27 +00:00
/* Not Null constraint */
if ( tbinfo - > notnull [ j ] & & ! tbinfo - > inhNotNull [ j ] )
appendPQExpBuffer ( q , " NOT NULL " ) ;
2001-08-10 18:57:42 +00:00
2002-05-10 22:36:27 +00:00
actual_atts + + ;
2000-09-15 04:35:16 +00:00
}
2002-05-10 22:36:27 +00:00
}
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
/*
* Add non - inherited CHECK constraints , if any . If a
* constraint matches by name and condition with a constraint
* belonging to a parent class ( OR conditions match and both names
* start with ' $ ' ) , we assume it was inherited .
*/
if ( tbinfo - > ncheck > 0 )
{
PGresult * res2 ;
2002-07-12 18:43:19 +00:00
int i_conname ,
i_consrc ;
2002-05-10 22:36:27 +00:00
int ntups2 ;
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
if ( g_verbose )
write_msg ( NULL , " finding CHECK constraints for table %s \n " ,
tbinfo - > relname ) ;
2001-01-12 15:41:29 +00:00
2002-05-10 22:36:27 +00:00
resetPQExpBuffer ( query ) ;
2002-05-28 22:26:57 +00:00
if ( g_fout - > remoteVersion > = 70300 )
2002-07-12 18:43:19 +00:00
appendPQExpBuffer ( query , " SELECT conname, consrc "
" from pg_catalog.pg_constraint c1 "
" where conrelid = '%s'::pg_catalog.oid "
" and contype = 'c' "
2002-05-28 22:26:57 +00:00
" and not exists "
" (select 1 from "
2002-07-12 18:43:19 +00:00
" pg_catalog.pg_constraint c2, "
2002-05-28 22:26:57 +00:00
" pg_catalog.pg_inherits i "
2002-07-12 18:43:19 +00:00
" where i.inhrelid = c1.conrelid "
" and (c2.conname = c1.conname "
" or (c2.conname[0] = '$' "
" and c1.conname[0] = '$') "
2002-05-28 22:26:57 +00:00
" ) "
2002-07-12 18:43:19 +00:00
" and c2.consrc = c1.consrc "
" and c2.conrelid = i.inhparent) "
" order by conname " ,
2002-05-28 22:26:57 +00:00
tbinfo - > oid ) ;
else
2002-07-12 18:43:19 +00:00
appendPQExpBuffer ( query , " SELECT rcname as conname, rcsrc as consrc "
2002-05-28 22:26:57 +00:00
" from pg_relcheck c1 "
" where rcrelid = '%s'::oid "
" and not exists "
" (select 1 from pg_relcheck c2, "
" pg_inherits i "
" where i.inhrelid = c1.rcrelid "
" and (c2.rcname = c1.rcname "
" or (c2.rcname[0] = '$' "
" and c1.rcname[0] = '$') "
" ) "
" and c2.rcsrc = c1.rcsrc "
" and c2.rcrelid = i.inhparent) "
" order by rcname " ,
tbinfo - > oid ) ;
2002-05-10 22:36:27 +00:00
res2 = PQexec ( g_conn , query - > data ) ;
if ( ! res2 | |
PQresultStatus ( res2 ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to obtain check constraints failed: %s " , PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
2001-01-12 15:41:29 +00:00
}
2002-05-10 22:36:27 +00:00
ntups2 = PQntuples ( res2 ) ;
if ( ntups2 > tbinfo - > ncheck )
2000-04-12 17:17:23 +00:00
{
2002-05-10 22:36:27 +00:00
write_msg ( NULL , " expected %d check constraints on table \" %s \" but found %d \n " ,
tbinfo - > ncheck , tbinfo - > relname , ntups2 ) ;
write_msg ( NULL , " (The system catalogs might be corrupted.) \n " ) ;
exit_nicely ( ) ;
2000-01-18 18:09:02 +00:00
}
2000-04-12 17:17:23 +00:00
2002-07-12 18:43:19 +00:00
i_conname = PQfnumber ( res2 , " conname " ) ;
i_consrc = PQfnumber ( res2 , " consrc " ) ;
2000-04-12 17:17:23 +00:00
2002-05-10 22:36:27 +00:00
for ( j = 0 ; j < ntups2 ; j + + )
{
2002-07-12 18:43:19 +00:00
const char * name = PQgetvalue ( res2 , j , i_conname ) ;
const char * expr = PQgetvalue ( res2 , j , i_consrc ) ;
2002-05-10 22:36:27 +00:00
if ( actual_atts + j > 0 )
appendPQExpBuffer ( q , " , \n \t " ) ;
2000-04-12 17:17:23 +00:00
2002-05-10 22:36:27 +00:00
if ( name [ 0 ] ! = ' $ ' )
appendPQExpBuffer ( q , " CONSTRAINT %s " ,
fmtId ( name , force_quotes ) ) ;
appendPQExpBuffer ( q , " CHECK (%s) " , expr ) ;
}
PQclear ( res2 ) ;
1997-09-07 05:04:48 +00:00
}
2001-08-03 19:43:05 +00:00
2002-05-10 22:36:27 +00:00
/*
* Primary Key : In versions of PostgreSQL prior to 7.2 , we
* needed to include the primary key in the table definition .
* However , this is not ideal because it creates an index
* on the table , which makes COPY slower . As of release 7.2 ,
* we can add primary keys to a table after it has been created ,
* using ALTER TABLE ; see dumpIndexes ( ) for more information .
* Therefore , we ignore primary keys in this function .
*/
1996-07-09 06:22:35 +00:00
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( q , " \n ) " ) ;
2001-01-12 15:41:29 +00:00
2002-05-10 22:36:27 +00:00
if ( numParents > 0 )
{
appendPQExpBuffer ( q , " \n INHERITS ( " ) ;
for ( k = 0 ; k < numParents ; k + + )
{
TableInfo * parentRel = & g_tblinfo [ parentIndexes [ k ] ] ;
2001-01-12 15:41:29 +00:00
2002-05-10 22:36:27 +00:00
if ( k > 0 )
appendPQExpBuffer ( q , " , " ) ;
if ( parentRel - > relnamespace ! = tbinfo - > relnamespace )
appendPQExpBuffer ( q , " %s. " ,
fmtId ( parentRel - > relnamespace - > nspname ,
force_quotes ) ) ;
appendPQExpBuffer ( q , " %s " ,
fmtId ( parentRel - > relname , force_quotes ) ) ;
}
appendPQExpBuffer ( q , " ) " ) ;
}
2001-01-12 15:41:29 +00:00
2002-05-10 22:36:27 +00:00
if ( ! tbinfo - > hasoids )
appendPQExpBuffer ( q , " WITHOUT OIDS " ) ;
2001-01-12 15:41:29 +00:00
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( q , " ; \n " ) ;
2002-07-31 17:19:54 +00:00
/*
* Dump per - column statistics information . We only issue an ALTER TABLE
* statement if the attstattarget entry for this column is non - negative
* ( i . e . it ' s not the default value )
*/
for ( j = 0 ; j < tbinfo - > numatts ; j + + )
{
2002-08-02 18:15:10 +00:00
if ( tbinfo - > attstattarget [ j ] > = 0 & &
! tbinfo - > attisdropped [ j ] )
2002-07-31 17:19:54 +00:00
{
2002-08-16 21:03:42 +00:00
appendPQExpBuffer ( q , " ALTER TABLE ONLY %s " ,
2002-07-31 17:19:54 +00:00
fmtId ( tbinfo - > relname , force_quotes ) ) ;
appendPQExpBuffer ( q , " ALTER COLUMN %s " ,
fmtId ( tbinfo - > attnames [ j ] , force_quotes ) ) ;
appendPQExpBuffer ( q , " SET STATISTICS %d; \n " ,
tbinfo - > attstattarget [ j ] ) ;
}
}
2001-01-12 15:41:29 +00:00
}
2002-05-10 22:36:27 +00:00
ArchiveEntry ( fout , objoid , tbinfo - > relname ,
tbinfo - > relnamespace - > nspname , tbinfo - > usename ,
reltypename , NULL , q - > data , delq - > data ,
NULL , NULL , NULL ) ;
2001-01-12 15:41:29 +00:00
2002-05-10 22:36:27 +00:00
/* Dump Table Comments */
dumpTableComment ( fout , tbinfo , reltypename , commentDeps ) ;
2002-07-02 05:49:52 +00:00
if ( commentDeps )
{
for ( j = 0 ; ( * commentDeps ) [ j ] ! = NULL ; j + + )
{
free ( ( void * ) ( * commentDeps ) [ j ] ) ;
}
free ( commentDeps ) ;
}
2002-05-10 22:36:27 +00:00
destroyPQExpBuffer ( query ) ;
destroyPQExpBuffer ( q ) ;
destroyPQExpBuffer ( delq ) ;
2001-01-12 15:41:29 +00:00
}
2001-04-22 21:34:13 +00:00
/*
* getAttrName : extract the correct name for an attribute
*
* The array tblInfo - > attnames [ ] only provides names of user attributes ;
* if a system attribute number is supplied , we have to fake it .
* We also do a little bit of bounds checking for safety ' s sake .
*/
static const char *
getAttrName ( int attrnum , TableInfo * tblInfo )
{
if ( attrnum > 0 & & attrnum < = tblInfo - > numatts )
2001-10-25 05:50:21 +00:00
return tblInfo - > attnames [ attrnum - 1 ] ;
2001-04-22 21:34:13 +00:00
switch ( attrnum )
{
case SelfItemPointerAttributeNumber :
return " ctid " ;
case ObjectIdAttributeNumber :
return " oid " ;
case MinTransactionIdAttributeNumber :
return " xmin " ;
case MinCommandIdAttributeNumber :
return " cmin " ;
case MaxTransactionIdAttributeNumber :
return " xmax " ;
case MaxCommandIdAttributeNumber :
return " cmax " ;
case TableOidAttributeNumber :
return " tableoid " ;
}
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " getAttrName(): invalid column number %d for table %s \n " ,
2001-10-25 05:50:21 +00:00
attrnum , tblInfo - > relname ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
2001-04-22 21:34:13 +00:00
return NULL ; /* keep compiler quiet */
}
1996-07-09 06:22:35 +00:00
/*
2001-06-27 21:21:37 +00:00
* dumpIndexes :
2002-05-10 22:36:27 +00:00
* write out to fout all the user - defined indexes for dumpable tables
1996-07-09 06:22:35 +00:00
*/
1997-09-07 05:04:48 +00:00
void
2002-05-10 22:36:27 +00:00
dumpIndexes ( Archive * fout , TableInfo * tblinfo , int numTables )
1996-07-09 06:22:35 +00:00
{
2002-05-10 22:36:27 +00:00
int i ,
j ;
PQExpBuffer query = createPQExpBuffer ( ) ;
2001-08-03 19:43:05 +00:00
PQExpBuffer q = createPQExpBuffer ( ) ;
PQExpBuffer delq = createPQExpBuffer ( ) ;
2002-05-10 22:36:27 +00:00
PGresult * res ;
int ntups ;
int i_indexreloid ;
int i_indexrelname ;
int i_indexdef ;
2002-07-18 04:50:51 +00:00
int i_contype ;
2002-05-10 22:36:27 +00:00
int i_indkey ;
int i_indnkeys ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
for ( i = 0 ; i < numTables ; i + + )
1997-09-07 05:04:48 +00:00
{
2002-05-10 22:36:27 +00:00
TableInfo * tbinfo = & tblinfo [ i ] ;
2001-07-03 20:21:50 +00:00
2002-05-10 22:36:27 +00:00
/* Only plain tables have indexes */
if ( tbinfo - > relkind ! = RELKIND_RELATION | | ! tbinfo - > hasindex )
2001-01-12 15:41:29 +00:00
continue ;
2002-05-10 22:36:27 +00:00
if ( ! tbinfo - > dump )
continue ;
2000-04-12 17:17:23 +00:00
2002-05-10 22:36:27 +00:00
/* Make sure we are in proper schema so indexdef is right */
selectSourceSchema ( tbinfo - > relnamespace - > nspname ) ;
1996-07-09 06:22:35 +00:00
2002-08-16 21:03:42 +00:00
/*
* The point of the messy - looking outer join is to find a constraint
* that is related by an internal dependency link to the index .
* If we find one , we emit an ADD CONSTRAINT command instead of
* a CREATE INDEX command . We assume an index won ' t have more than
* one internal dependency .
*/
2002-05-10 22:36:27 +00:00
resetPQExpBuffer ( query ) ;
2002-05-28 22:26:57 +00:00
if ( g_fout - > remoteVersion > = 70300 )
appendPQExpBuffer ( query ,
" SELECT i.indexrelid as indexreloid, "
2002-07-18 04:50:51 +00:00
" coalesce(c.conname, t.relname) as indexrelname, "
2002-05-28 22:26:57 +00:00
" pg_catalog.pg_get_indexdef(i.indexrelid) as indexdef, "
2002-07-18 04:50:51 +00:00
" i.indkey, "
" t.relnatts as indnkeys, "
" coalesce(c.contype, '0') as contype "
" FROM pg_catalog.pg_index i "
" JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
2002-08-16 21:03:42 +00:00
" LEFT JOIN pg_catalog.pg_depend d "
" ON (d.classid = t.tableoid "
" AND d.objid = t.oid "
" AND d.deptype = 'i') "
" LEFT JOIN pg_catalog.pg_constraint c "
" ON (d.refclassid = c.tableoid "
" AND d.refobjid = c.oid) "
2002-07-18 04:50:51 +00:00
" WHERE i.indrelid = '%s'::pg_catalog.oid "
2002-05-28 22:26:57 +00:00
" ORDER BY indexrelname " ,
tbinfo - > oid ) ;
else
appendPQExpBuffer ( query ,
" SELECT i.indexrelid as indexreloid, "
" t.relname as indexrelname, "
" pg_get_indexdef(i.indexrelid) as indexdef, "
2002-07-18 04:50:51 +00:00
" i.indkey, "
" t.relnatts as indnkeys, "
2002-08-16 21:03:42 +00:00
" CASE WHEN i.indisprimary THEN 'p'::char "
2002-07-18 04:50:51 +00:00
" ELSE '0'::char END as contype "
2002-05-28 22:26:57 +00:00
" FROM pg_index i, pg_class t "
" WHERE t.oid = i.indexrelid "
" AND i.indrelid = '%s'::oid "
" ORDER BY indexrelname " ,
tbinfo - > oid ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to obtain list of indexes failed: %s " , PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
ntups = PQntuples ( res ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
i_indexreloid = PQfnumber ( res , " indexreloid " ) ;
i_indexrelname = PQfnumber ( res , " indexrelname " ) ;
i_indexdef = PQfnumber ( res , " indexdef " ) ;
2002-07-18 04:50:51 +00:00
i_contype = PQfnumber ( res , " contype " ) ;
2002-05-10 22:36:27 +00:00
i_indkey = PQfnumber ( res , " indkey " ) ;
i_indnkeys = PQfnumber ( res , " indnkeys " ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
for ( j = 0 ; j < ntups ; j + + )
1997-09-07 05:04:48 +00:00
{
2002-05-10 22:36:27 +00:00
const char * indexreloid = PQgetvalue ( res , j , i_indexreloid ) ;
const char * indexrelname = PQgetvalue ( res , j , i_indexrelname ) ;
const char * indexdef = PQgetvalue ( res , j , i_indexdef ) ;
2002-08-16 21:03:42 +00:00
char contype = * ( PQgetvalue ( res , j , i_contype ) ) ;
2002-05-10 22:36:27 +00:00
resetPQExpBuffer ( q ) ;
resetPQExpBuffer ( delq ) ;
2002-08-16 21:03:42 +00:00
if ( contype = = ' p ' | | contype = = ' u ' )
1997-09-07 05:04:48 +00:00
{
2002-07-18 04:50:51 +00:00
/*
2002-08-16 21:03:42 +00:00
* If we found a constraint matching the index , emit
* ADD CONSTRAINT not CREATE INDEX .
*
* In a pre - 7.3 database , we take this path iff the index
* was marked indisprimary .
2002-07-18 04:50:51 +00:00
*/
2002-05-10 22:36:27 +00:00
int indnkeys = atoi ( PQgetvalue ( res , j , i_indnkeys ) ) ;
char * * indkeys = ( char * * ) malloc ( indnkeys * sizeof ( char * ) ) ;
int k ;
parseNumericArray ( PQgetvalue ( res , j , i_indkey ) ,
indkeys , indnkeys ) ;
1997-09-07 05:04:48 +00:00
2002-08-16 21:03:42 +00:00
appendPQExpBuffer ( q , " ALTER TABLE ONLY %s " ,
2002-05-10 22:36:27 +00:00
fmtId ( tbinfo - > relname , force_quotes ) ) ;
2002-08-16 21:03:42 +00:00
appendPQExpBuffer ( q , " ADD CONSTRAINT %s %s ( " ,
2002-07-18 04:50:51 +00:00
fmtId ( indexrelname , force_quotes ) ,
2002-08-16 21:03:42 +00:00
contype = = ' p ' ? " PRIMARY KEY " : " UNIQUE " ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
for ( k = 0 ; k < indnkeys ; k + + )
1997-09-07 05:04:48 +00:00
{
2002-05-10 22:36:27 +00:00
int indkey = atoi ( indkeys [ k ] ) ;
const char * attname ;
if ( indkey = = InvalidAttrNumber )
break ;
attname = getAttrName ( indkey , tbinfo ) ;
appendPQExpBuffer ( q , " %s%s " ,
( k = = 0 ) ? " " : " , " ,
fmtId ( attname , force_quotes ) ) ;
1997-09-07 05:04:48 +00:00
}
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( q , " ); \n " ) ;
2002-08-16 21:03:42 +00:00
/* DROP must be fully qualified in case same name appears in pg_catalog */
appendPQExpBuffer ( delq , " ALTER TABLE ONLY %s. " ,
fmtId ( tbinfo - > relnamespace - > nspname , force_quotes ) ) ;
appendPQExpBuffer ( delq , " %s " ,
fmtId ( tbinfo - > relname , force_quotes ) ) ;
appendPQExpBuffer ( delq , " DROP CONSTRAINT %s; \n " ,
fmtId ( indexrelname , force_quotes ) ) ;
2002-05-10 22:36:27 +00:00
ArchiveEntry ( fout , indexreloid ,
indexrelname ,
tbinfo - > relnamespace - > nspname ,
tbinfo - > usename ,
" CONSTRAINT " , NULL ,
2002-08-16 21:03:42 +00:00
q - > data , delq - > data ,
2002-05-10 22:36:27 +00:00
NULL , NULL , NULL ) ;
2002-08-04 05:03:29 +00:00
for ( k = 0 ; k < indnkeys ; k + + )
free ( indkeys [ k ] ) ;
2002-05-10 22:36:27 +00:00
free ( indkeys ) ;
}
else
{
/* Plain secondary index */
appendPQExpBuffer ( q , " %s; \n " , indexdef ) ;
2002-05-28 22:26:57 +00:00
/* DROP must be fully qualified in case same name appears in pg_catalog */
appendPQExpBuffer ( delq , " DROP INDEX %s. " ,
fmtId ( tbinfo - > relnamespace - > nspname , force_quotes ) ) ;
appendPQExpBuffer ( delq , " %s; \n " ,
2002-05-10 22:36:27 +00:00
fmtId ( indexrelname , force_quotes ) ) ;
ArchiveEntry ( fout , indexreloid ,
indexrelname ,
tbinfo - > relnamespace - > nspname ,
tbinfo - > usename ,
" INDEX " , NULL ,
q - > data , delq - > data ,
NULL , NULL , NULL ) ;
1997-09-07 05:04:48 +00:00
}
2002-05-10 22:36:27 +00:00
/* Dump Index Comments */
resetPQExpBuffer ( q ) ;
appendPQExpBuffer ( q , " INDEX %s " ,
fmtId ( indexrelname , force_quotes ) ) ;
dumpComment ( fout , q - > data ,
tbinfo - > relnamespace - > nspname ,
tbinfo - > usename ,
indexreloid , " pg_class " , 0 , NULL ) ;
1997-09-07 05:04:48 +00:00
}
2002-05-10 22:36:27 +00:00
PQclear ( res ) ;
1997-09-07 05:04:48 +00:00
}
2002-05-10 22:36:27 +00:00
destroyPQExpBuffer ( query ) ;
destroyPQExpBuffer ( q ) ;
destroyPQExpBuffer ( delq ) ;
1996-07-09 06:22:35 +00:00
}
1996-08-24 20:49:41 +00:00
/*
* setMaxOid -
* find the maximum oid and generate a COPY statement to set it
*/
1996-07-09 06:22:35 +00:00
1997-08-19 21:40:56 +00:00
static void
2000-07-04 14:25:28 +00:00
setMaxOid ( Archive * fout )
1996-08-24 20:49:41 +00:00
{
2001-03-22 04:01:46 +00:00
PGresult * res ;
Oid max_oid ;
2000-07-04 14:25:28 +00:00
char sql [ 1024 ] ;
1997-09-07 05:04:48 +00:00
2002-05-28 22:26:57 +00:00
res = PQexec ( g_conn , " CREATE TEMPORARY TABLE pgdump_oid (dummy integer) " ) ;
1997-09-07 05:04:48 +00:00
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_COMMAND_OK )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " could not create pgdump_oid table: %s " , PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1997-09-07 05:04:48 +00:00
}
PQclear ( res ) ;
2000-09-15 04:35:16 +00:00
res = PQexec ( g_conn , " INSERT INTO pgdump_oid VALUES (0) " ) ;
1997-09-07 05:04:48 +00:00
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_COMMAND_OK )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " could not insert into pgdump_oid table: %s " , PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1997-09-07 05:04:48 +00:00
}
2001-08-10 22:50:10 +00:00
max_oid = PQoidValue ( res ) ;
1997-09-07 05:04:48 +00:00
if ( max_oid = = 0 )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " inserted invalid oid \n " ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1997-09-07 05:04:48 +00:00
}
PQclear ( res ) ;
2000-09-15 04:35:16 +00:00
res = PQexec ( g_conn , " DROP TABLE pgdump_oid; " ) ;
1997-09-07 05:04:48 +00:00
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_COMMAND_OK )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " could not drop pgdump_oid table: %s " , PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1997-09-07 05:04:48 +00:00
}
PQclear ( res ) ;
if ( g_verbose )
2001-07-03 20:21:50 +00:00
write_msg ( NULL , " maximum system oid is %u \n " , max_oid ) ;
2001-06-27 21:21:37 +00:00
snprintf ( sql , 1024 ,
2002-05-28 22:26:57 +00:00
" CREATE TEMPORARY TABLE pgdump_oid (dummy integer); \n "
2001-06-27 21:21:37 +00:00
" COPY pgdump_oid WITH OIDS FROM stdin; \n "
2001-08-10 18:57:42 +00:00
" %u \t 0 \n "
2001-06-27 21:21:37 +00:00
" \\ . \n "
" DROP TABLE pgdump_oid; \n " ,
max_oid ) ;
2000-07-04 14:25:28 +00:00
2002-05-10 22:36:27 +00:00
ArchiveEntry ( fout , " 0 " , " Max OID " , NULL , " " ,
" <Init> " , NULL ,
sql , " " ,
NULL , NULL , NULL ) ;
1997-09-07 05:04:48 +00:00
}
1996-07-09 06:22:35 +00:00
/*
* findLastBuiltInOid -
1997-09-07 05:04:48 +00:00
* find the last built in oid
2000-10-22 23:16:55 +00:00
* we do this by retrieving datlastsysoid from the pg_database entry for this database ,
*/
1996-07-09 06:22:35 +00:00
2000-11-14 18:37:49 +00:00
static Oid
2001-04-25 07:03:20 +00:00
findLastBuiltinOid_V71 ( const char * dbname )
1996-07-09 06:22:35 +00:00
{
1999-05-25 16:15:34 +00:00
PGresult * res ;
1997-09-08 02:41:22 +00:00
int ntups ;
2000-11-14 18:37:49 +00:00
Oid last_oid ;
2000-10-22 18:13:09 +00:00
PQExpBuffer query = createPQExpBuffer ( ) ;
resetPQExpBuffer ( query ) ;
2001-01-04 01:23:47 +00:00
appendPQExpBuffer ( query , " SELECT datlastsysoid from pg_database where datname = " ) ;
2001-02-13 01:31:54 +00:00
formatStringLiteral ( query , dbname , CONV_ALL ) ;
1997-09-07 05:04:48 +00:00
2000-10-22 18:13:09 +00:00
res = PQexec ( g_conn , query - > data ) ;
1997-09-07 05:04:48 +00:00
if ( res = = NULL | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " error in finding the last system oid: %s " , PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1997-09-07 05:04:48 +00:00
}
ntups = PQntuples ( res ) ;
1999-10-10 17:00:26 +00:00
if ( ntups < 1 )
1997-09-07 05:04:48 +00:00
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " missing pg_database entry for this database \n " ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1999-10-10 17:00:26 +00:00
}
if ( ntups > 1 )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " found more than one pg_database entry for this database \n " ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1997-09-07 05:04:48 +00:00
}
2001-04-25 07:03:20 +00:00
last_oid = atooid ( PQgetvalue ( res , 0 , PQfnumber ( res , " datlastsysoid " ) ) ) ;
1997-09-07 05:04:48 +00:00
PQclear ( res ) ;
2001-08-03 19:43:05 +00:00
destroyPQExpBuffer ( query ) ;
1997-09-07 05:04:48 +00:00
return last_oid ;
1996-07-09 06:22:35 +00:00
}
2001-04-25 07:03:20 +00:00
/*
* findLastBuiltInOid -
* find the last built in oid
* we do this by looking up the oid of ' template1 ' in pg_database ,
* this is probably not foolproof but comes close
*/
2001-05-30 14:15:27 +00:00
static Oid
2001-04-25 07:03:20 +00:00
findLastBuiltinOid_V70 ( void )
{
PGresult * res ;
int ntups ;
int last_oid ;
res = PQexec ( g_conn ,
" SELECT oid from pg_database where datname = 'template1' " ) ;
if ( res = = NULL | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " error in finding the template1 database: %s " , PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
2001-04-25 07:03:20 +00:00
}
ntups = PQntuples ( res ) ;
if ( ntups < 1 )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " could not find template1 database entry in the pg_database table \n " ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
2001-04-25 07:03:20 +00:00
}
if ( ntups > 1 )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " found more than one template1 database entry in the pg_database table \n " ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
2001-04-25 07:03:20 +00:00
}
last_oid = atooid ( PQgetvalue ( res , 0 , PQfnumber ( res , " oid " ) ) ) ;
PQclear ( res ) ;
return last_oid ;
}
1996-07-09 06:22:35 +00:00
1997-09-07 05:04:48 +00:00
static void
2002-05-10 22:36:27 +00:00
dumpOneSequence ( Archive * fout , TableInfo * tbinfo ,
const bool schemaOnly , const bool dataOnly )
1997-04-02 04:17:27 +00:00
{
2000-04-12 17:17:23 +00:00
PGresult * res ;
2001-08-16 20:38:56 +00:00
char * last ,
* incby ,
* maxv ,
* minv ,
* cache ;
bool cycled ,
1999-12-11 00:31:05 +00:00
called ;
2000-04-12 17:17:23 +00:00
PQExpBuffer query = createPQExpBuffer ( ) ;
2000-07-04 14:25:28 +00:00
PQExpBuffer delqry = createPQExpBuffer ( ) ;
1997-09-07 05:04:48 +00:00
2002-05-10 22:36:27 +00:00
/* Make sure we are in proper schema */
selectSourceSchema ( tbinfo - > relnamespace - > nspname ) ;
1999-12-27 15:42:44 +00:00
appendPQExpBuffer ( query ,
1997-09-07 05:04:48 +00:00
" SELECT sequence_name, last_value, increment_by, max_value, "
2000-04-12 17:17:23 +00:00
" min_value, cache_value, is_cycled, is_called from %s " ,
2002-05-10 22:36:27 +00:00
fmtId ( tbinfo - > relname , force_quotes ) ) ;
1997-09-07 05:04:48 +00:00
1999-12-27 15:42:44 +00:00
res = PQexec ( g_conn , query - > data ) ;
1997-09-07 05:04:48 +00:00
if ( ! res | | PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
2002-05-10 22:36:27 +00:00
write_msg ( NULL , " query to get data of sequence \" %s \" failed: %s " , tbinfo - > relname , PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1997-09-07 05:04:48 +00:00
}
if ( PQntuples ( res ) ! = 1 )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " query to get data of sequence \" %s \" returned %d rows (expected 1) \n " ,
2002-05-10 22:36:27 +00:00
tbinfo - > relname , PQntuples ( res ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1997-09-07 05:04:48 +00:00
}
2002-02-27 20:59:05 +00:00
/* Disable this check: it fails if sequence has been renamed */
# ifdef NOT_USED
2002-05-10 22:36:27 +00:00
if ( strcmp ( PQgetvalue ( res , 0 , 0 ) , tbinfo - > relname ) ! = 0 )
1997-09-07 05:04:48 +00:00
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " query to get data of sequence \" %s \" returned name \" %s \" \n " ,
2002-05-10 22:36:27 +00:00
tbinfo - > relname , PQgetvalue ( res , 0 , 0 ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1997-09-07 05:04:48 +00:00
}
2002-02-27 20:59:05 +00:00
# endif
1997-09-07 05:04:48 +00:00
2001-08-16 20:38:56 +00:00
last = PQgetvalue ( res , 0 , 1 ) ;
incby = PQgetvalue ( res , 0 , 2 ) ;
maxv = PQgetvalue ( res , 0 , 3 ) ;
minv = PQgetvalue ( res , 0 , 4 ) ;
cache = PQgetvalue ( res , 0 , 5 ) ;
cycled = ( strcmp ( PQgetvalue ( res , 0 , 6 ) , " t " ) = = 0 ) ;
called = ( strcmp ( PQgetvalue ( res , 0 , 7 ) , " t " ) = = 0 ) ;
1997-09-07 05:04:48 +00:00
2000-10-13 00:43:31 +00:00
/*
2001-03-22 04:01:46 +00:00
* The logic we use for restoring sequences is as follows : - Add a
* basic CREATE SEQUENCE statement ( use last_val for start if called
2001-08-16 20:38:56 +00:00
* is false , else use min_val for start_val ) .
2001-03-23 04:49:58 +00:00
*
2001-10-25 05:50:21 +00:00
* Add a ' SETVAL ( seq , last_val , iscalled ) ' at restore - time iff we load
* data
2000-10-13 00:43:31 +00:00
*/
1997-09-07 05:04:48 +00:00
2001-03-06 04:53:28 +00:00
if ( ! dataOnly )
{
resetPQExpBuffer ( delqry ) ;
2002-05-28 22:26:57 +00:00
/* DROP must be fully qualified in case same name appears in pg_catalog */
appendPQExpBuffer ( delqry , " DROP SEQUENCE %s. " ,
fmtId ( tbinfo - > relnamespace - > nspname , force_quotes ) ) ;
appendPQExpBuffer ( delqry , " %s; \n " ,
2002-05-10 22:36:27 +00:00
fmtId ( tbinfo - > relname , force_quotes ) ) ;
2000-10-13 00:43:31 +00:00
2001-03-06 04:53:28 +00:00
resetPQExpBuffer ( query ) ;
appendPQExpBuffer ( query ,
2001-08-16 20:38:56 +00:00
" CREATE SEQUENCE %s start %s increment %s "
" maxvalue %s minvalue %s cache %s%s; \n " ,
2002-05-10 22:36:27 +00:00
fmtId ( tbinfo - > relname , force_quotes ) ,
2001-08-16 20:38:56 +00:00
( called ? minv : last ) ,
2001-03-06 04:53:28 +00:00
incby , maxv , minv , cache ,
2001-08-16 20:38:56 +00:00
( cycled ? " cycle " : " " ) ) ;
2001-03-06 04:53:28 +00:00
2002-05-10 22:36:27 +00:00
ArchiveEntry ( fout , tbinfo - > oid , tbinfo - > relname ,
tbinfo - > relnamespace - > nspname , tbinfo - > usename ,
" SEQUENCE " , NULL ,
query - > data , delqry - > data ,
NULL , NULL , NULL ) ;
2001-03-06 04:53:28 +00:00
}
2000-10-13 00:43:31 +00:00
2001-03-06 04:53:28 +00:00
if ( ! schemaOnly )
{
resetPQExpBuffer ( query ) ;
2002-05-28 22:26:57 +00:00
appendPQExpBuffer ( query , " SELECT pg_catalog.setval ( " ) ;
2002-05-10 22:36:27 +00:00
formatStringLiteral ( query , fmtId ( tbinfo - > relname , force_quotes ) , CONV_ALL ) ;
2001-08-16 20:38:56 +00:00
appendPQExpBuffer ( query , " , %s, %s); \n " ,
last , ( called ? " true " : " false " ) ) ;
2000-10-13 00:43:31 +00:00
2002-05-10 22:36:27 +00:00
ArchiveEntry ( fout , tbinfo - > oid , tbinfo - > relname ,
tbinfo - > relnamespace - > nspname , tbinfo - > usename ,
" SEQUENCE SET " , NULL ,
query - > data , " " /* Del */ ,
NULL , NULL , NULL ) ;
2001-03-06 04:53:28 +00:00
}
2000-01-18 18:09:02 +00:00
2001-03-06 04:53:28 +00:00
if ( ! dataOnly )
{
/* Dump Sequence Comments */
2000-01-18 18:09:02 +00:00
2001-03-06 04:53:28 +00:00
resetPQExpBuffer ( query ) ;
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( query , " SEQUENCE %s " , fmtId ( tbinfo - > relname , force_quotes ) ) ;
dumpComment ( fout , query - > data ,
tbinfo - > relnamespace - > nspname , tbinfo - > usename ,
tbinfo - > oid , " pg_class " , 0 , NULL ) ;
2001-03-06 04:53:28 +00:00
}
2001-08-03 19:43:05 +00:00
2001-08-16 20:38:56 +00:00
PQclear ( res ) ;
2001-08-03 19:43:05 +00:00
destroyPQExpBuffer ( query ) ;
destroyPQExpBuffer ( delqry ) ;
1997-04-02 04:17:27 +00:00
}
1997-10-02 13:57:07 +00:00
2002-08-16 23:01:21 +00:00
/*
* dumpConstraints
*
* Dump out constraints after all table creation statements in
* an alter table format . Currently handles foreign keys only .
*
* XXX Potentially wrap in a ' SET CONSTRAINTS OFF ' block so that
* the current table data is not processed
*/
static void
dumpConstraints ( Archive * fout , TableInfo * tblinfo , int numTables )
{
int i ,
j ;
PQExpBuffer query ;
PQExpBuffer delqry ;
PGresult * res ;
int i_condef ,
i_conoid ,
i_conname ;
int ntups ;
/* pg_constraint was created in 7.3, so nothing to do if older */
if ( g_fout - > remoteVersion < 70300 )
return ;
query = createPQExpBuffer ( ) ;
delqry = createPQExpBuffer ( ) ;
for ( i = 0 ; i < numTables ; i + + )
{
TableInfo * tbinfo = & tblinfo [ i ] ;
if ( tbinfo - > ntrig = = 0 | | ! tbinfo - > dump )
continue ;
if ( g_verbose )
write_msg ( NULL , " dumping triggers for table %s \n " ,
tbinfo - > relname ) ;
/* select table schema to ensure regproc name is qualified if needed */
selectSourceSchema ( tbinfo - > relnamespace - > nspname ) ;
resetPQExpBuffer ( query ) ;
appendPQExpBuffer ( query ,
" SELECT oid, conname, "
" pg_catalog.pg_get_constraintdef(oid) as condef "
" FROM pg_catalog.pg_constraint "
" WHERE conrelid = '%s'::pg_catalog.oid "
" AND contype = 'f' " ,
tbinfo - > oid ) ;
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to obtain list of foreign key definitions failed: %s " , PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
ntups = PQntuples ( res ) ;
i_conoid = PQfnumber ( res , " oid " ) ;
i_conname = PQfnumber ( res , " conname " ) ;
i_condef = PQfnumber ( res , " condef " ) ;
for ( j = 0 ; j < ntups ; j + + )
{
const char * conOid = PQgetvalue ( res , j , i_conoid ) ;
const char * conName = PQgetvalue ( res , j , i_conname ) ;
const char * conDef = PQgetvalue ( res , j , i_condef ) ;
resetPQExpBuffer ( query ) ;
appendPQExpBuffer ( query , " ALTER TABLE ONLY %s " ,
fmtId ( tbinfo - > relname , force_quotes ) ) ;
appendPQExpBuffer ( query , " ADD CONSTRAINT %s %s; \n " ,
fmtId ( conName , force_quotes ) ,
conDef ) ;
/* DROP must be fully qualified in case same name appears in pg_catalog */
resetPQExpBuffer ( delqry ) ;
appendPQExpBuffer ( delqry , " ALTER TABLE ONLY %s. " ,
fmtId ( tbinfo - > relnamespace - > nspname , force_quotes ) ) ;
appendPQExpBuffer ( delqry , " %s " ,
fmtId ( tbinfo - > relname , force_quotes ) ) ;
appendPQExpBuffer ( delqry , " DROP CONSTRAINT %s; \n " ,
fmtId ( conName , force_quotes ) ) ;
ArchiveEntry ( fout , conOid ,
conName ,
tbinfo - > relnamespace - > nspname ,
tbinfo - > usename ,
" CONSTRAINT " , NULL ,
query - > data , delqry - > data ,
NULL , NULL , NULL ) ;
resetPQExpBuffer ( query ) ;
appendPQExpBuffer ( query , " CONSTRAINT %s " ,
fmtId ( conName , force_quotes ) ) ;
appendPQExpBuffer ( query , " ON %s " ,
fmtId ( tbinfo - > relname , force_quotes ) ) ;
dumpComment ( fout , query - > data ,
tbinfo - > relnamespace - > nspname , tbinfo - > usename ,
conOid , " pg_constraint " , 0 , NULL ) ;
}
PQclear ( res ) ;
}
destroyPQExpBuffer ( query ) ;
destroyPQExpBuffer ( delqry ) ;
}
1997-10-02 13:57:07 +00:00
1998-02-26 04:46:47 +00:00
static void
2002-05-10 22:36:27 +00:00
dumpTriggers ( Archive * fout , TableInfo * tblinfo , int numTables )
1997-10-02 13:57:07 +00:00
{
1998-02-26 04:46:47 +00:00
int i ,
j ;
2002-05-10 22:36:27 +00:00
PQExpBuffer query = createPQExpBuffer ( ) ;
PQExpBuffer delqry = createPQExpBuffer ( ) ;
PGresult * res ;
int i_tgoid ,
i_tgname ,
i_tgfname ,
i_tgtype ,
i_tgnargs ,
i_tgargs ,
i_tgisconstraint ,
i_tgconstrname ,
i_tgdeferrable ,
i_tgconstrrelid ,
i_tgconstrrelname ,
i_tginitdeferred ;
int ntups ;
1998-02-26 04:46:47 +00:00
1997-10-02 13:57:07 +00:00
for ( i = 0 ; i < numTables ; i + + )
{
2002-05-10 22:36:27 +00:00
TableInfo * tbinfo = & tblinfo [ i ] ;
if ( tbinfo - > ntrig = = 0 | | ! tbinfo - > dump )
1997-10-02 13:57:07 +00:00
continue ;
2001-01-12 04:32:07 +00:00
2002-05-10 22:36:27 +00:00
if ( g_verbose )
write_msg ( NULL , " dumping triggers for table %s \n " ,
tbinfo - > relname ) ;
/* select table schema to ensure regproc name is qualified if needed */
selectSourceSchema ( tbinfo - > relnamespace - > nspname ) ;
resetPQExpBuffer ( query ) ;
if ( g_fout - > remoteVersion > = 70300 )
{
2002-08-16 23:01:21 +00:00
/* We ignore triggers that are tied to a foreign-key constraint */
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( query ,
2002-05-28 22:26:57 +00:00
" SELECT tgname, "
" tgfoid::pg_catalog.regproc as tgfname, "
2002-05-10 22:36:27 +00:00
" tgtype, tgnargs, tgargs, "
" tgisconstraint, tgconstrname, tgdeferrable, "
" tgconstrrelid, tginitdeferred, oid, "
2002-05-28 22:26:57 +00:00
" tgconstrrelid::pg_catalog.regclass as tgconstrrelname "
2002-08-16 23:01:21 +00:00
" from pg_catalog.pg_trigger t "
" where tgrelid = '%s'::pg_catalog.oid "
" and (not tgisconstraint "
" OR NOT EXISTS "
" (SELECT 1 FROM pg_catalog.pg_depend d "
" JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
" WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f')) " ,
2002-05-10 22:36:27 +00:00
tbinfo - > oid ) ;
}
else
{
appendPQExpBuffer ( query ,
" SELECT tgname, tgfoid::regproc as tgfname, "
" tgtype, tgnargs, tgargs, "
" tgisconstraint, tgconstrname, tgdeferrable, "
" tgconstrrelid, tginitdeferred, oid, "
" (select relname from pg_class where oid = tgconstrrelid) "
" as tgconstrrelname "
" from pg_trigger "
" where tgrelid = '%s'::oid " ,
tbinfo - > oid ) ;
}
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to obtain list of triggers failed: %s " , PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
ntups = PQntuples ( res ) ;
2002-08-16 23:01:21 +00:00
/*
* We may have less triggers than recorded due to constraint triggers
* which are dumped by dumpConstraints
*/
if ( ntups > tbinfo - > ntrig )
2002-05-10 22:36:27 +00:00
{
write_msg ( NULL , " expected %d triggers on table \" %s \" but found %d \n " ,
tbinfo - > ntrig , tbinfo - > relname , ntups ) ;
exit_nicely ( ) ;
}
i_tgname = PQfnumber ( res , " tgname " ) ;
i_tgfname = PQfnumber ( res , " tgfname " ) ;
i_tgtype = PQfnumber ( res , " tgtype " ) ;
i_tgnargs = PQfnumber ( res , " tgnargs " ) ;
i_tgargs = PQfnumber ( res , " tgargs " ) ;
i_tgoid = PQfnumber ( res , " oid " ) ;
i_tgisconstraint = PQfnumber ( res , " tgisconstraint " ) ;
i_tgconstrname = PQfnumber ( res , " tgconstrname " ) ;
i_tgdeferrable = PQfnumber ( res , " tgdeferrable " ) ;
i_tgconstrrelid = PQfnumber ( res , " tgconstrrelid " ) ;
i_tgconstrrelname = PQfnumber ( res , " tgconstrrelname " ) ;
i_tginitdeferred = PQfnumber ( res , " tginitdeferred " ) ;
for ( j = 0 ; j < ntups ; j + + )
1997-10-02 13:57:07 +00:00
{
2002-05-10 22:36:27 +00:00
const char * tgoid = PQgetvalue ( res , j , i_tgoid ) ;
char * tgname = PQgetvalue ( res , j , i_tgname ) ;
const char * tgfname = PQgetvalue ( res , j , i_tgfname ) ;
int2 tgtype = atoi ( PQgetvalue ( res , j , i_tgtype ) ) ;
int tgnargs = atoi ( PQgetvalue ( res , j , i_tgnargs ) ) ;
const char * tgargs = PQgetvalue ( res , j , i_tgargs ) ;
int tgisconstraint ;
int tgdeferrable ;
int tginitdeferred ;
char * tgconstrrelid ;
const char * p ;
int findx ;
if ( strcmp ( PQgetvalue ( res , j , i_tgisconstraint ) , " f " ) = = 0 )
tgisconstraint = 0 ;
else
tgisconstraint = 1 ;
if ( strcmp ( PQgetvalue ( res , j , i_tgdeferrable ) , " f " ) = = 0 )
tgdeferrable = 0 ;
else
tgdeferrable = 1 ;
if ( strcmp ( PQgetvalue ( res , j , i_tginitdeferred ) , " f " ) = = 0 )
tginitdeferred = 0 ;
else
tginitdeferred = 1 ;
resetPQExpBuffer ( delqry ) ;
2002-05-28 22:26:57 +00:00
/* DROP must be fully qualified in case same name appears in pg_catalog */
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( delqry , " DROP TRIGGER %s " ,
fmtId ( tgname , force_quotes ) ) ;
2002-05-28 22:26:57 +00:00
appendPQExpBuffer ( delqry , " ON %s. " ,
fmtId ( tbinfo - > relnamespace - > nspname , force_quotes ) ) ;
appendPQExpBuffer ( delqry , " %s; \n " ,
2002-05-10 22:36:27 +00:00
fmtId ( tbinfo - > relname , force_quotes ) ) ;
resetPQExpBuffer ( query ) ;
if ( tgisconstraint )
{
appendPQExpBuffer ( query , " CREATE CONSTRAINT TRIGGER " ) ;
appendPQExpBuffer ( query , fmtId ( PQgetvalue ( res , j , i_tgconstrname ) , force_quotes ) ) ;
}
else
{
appendPQExpBuffer ( query , " CREATE TRIGGER " ) ;
appendPQExpBuffer ( query , fmtId ( tgname , force_quotes ) ) ;
}
appendPQExpBufferChar ( query , ' ' ) ;
/* Trigger type */
findx = 0 ;
if ( TRIGGER_FOR_BEFORE ( tgtype ) )
appendPQExpBuffer ( query , " BEFORE " ) ;
else
appendPQExpBuffer ( query , " AFTER " ) ;
if ( TRIGGER_FOR_INSERT ( tgtype ) )
{
appendPQExpBuffer ( query , " INSERT " ) ;
findx + + ;
}
if ( TRIGGER_FOR_DELETE ( tgtype ) )
{
if ( findx > 0 )
appendPQExpBuffer ( query , " OR DELETE " ) ;
else
appendPQExpBuffer ( query , " DELETE " ) ;
findx + + ;
}
if ( TRIGGER_FOR_UPDATE ( tgtype ) )
{
if ( findx > 0 )
appendPQExpBuffer ( query , " OR UPDATE " ) ;
else
appendPQExpBuffer ( query , " UPDATE " ) ;
}
appendPQExpBuffer ( query , " ON %s " ,
fmtId ( tbinfo - > relname , force_quotes ) ) ;
if ( tgisconstraint )
{
tgconstrrelid = PQgetvalue ( res , j , i_tgconstrrelid ) ;
if ( strcmp ( tgconstrrelid , " 0 " ) ! = 0 )
{
if ( PQgetisnull ( res , j , i_tgconstrrelname ) )
{
write_msg ( NULL , " query produced NULL referenced table name for foreign key trigger \" %s \" on table \" %s \" (oid of table: %s) \n " ,
tgname , tbinfo - > relname , tgconstrrelid ) ;
exit_nicely ( ) ;
}
/* If we are using regclass, name is already quoted */
if ( g_fout - > remoteVersion > = 70300 )
appendPQExpBuffer ( query , " FROM %s " ,
PQgetvalue ( res , j , i_tgconstrrelname ) ) ;
else
appendPQExpBuffer ( query , " FROM %s " ,
fmtId ( PQgetvalue ( res , j , i_tgconstrrelname ) , force_quotes ) ) ;
}
if ( ! tgdeferrable )
appendPQExpBuffer ( query , " NOT " ) ;
appendPQExpBuffer ( query , " DEFERRABLE INITIALLY " ) ;
if ( tginitdeferred )
appendPQExpBuffer ( query , " DEFERRED " ) ;
else
appendPQExpBuffer ( query , " IMMEDIATE " ) ;
}
appendPQExpBuffer ( query , " FOR EACH ROW " ) ;
/* In 7.3, result of regproc is already quoted */
if ( g_fout - > remoteVersion > = 70300 )
appendPQExpBuffer ( query , " EXECUTE PROCEDURE %s ( " ,
tgfname ) ;
else
appendPQExpBuffer ( query , " EXECUTE PROCEDURE %s ( " ,
fmtId ( tgfname , force_quotes ) ) ;
for ( findx = 0 ; findx < tgnargs ; findx + + )
{
const char * s ;
for ( p = tgargs ; ; )
{
p = strchr ( p , ' \\ ' ) ;
if ( p = = NULL )
{
write_msg ( NULL , " bad argument string (%s) for trigger \" %s \" on table \" %s \" \n " ,
PQgetvalue ( res , j , i_tgargs ) ,
tgname ,
tbinfo - > relname ) ;
exit_nicely ( ) ;
}
p + + ;
if ( * p = = ' \\ ' )
{
p + + ;
continue ;
}
if ( p [ 0 ] = = ' 0 ' & & p [ 1 ] = = ' 0 ' & & p [ 2 ] = = ' 0 ' )
break ;
}
p - - ;
appendPQExpBufferChar ( query , ' \' ' ) ;
for ( s = tgargs ; s < p ; )
{
if ( * s = = ' \' ' )
appendPQExpBufferChar ( query , ' \\ ' ) ;
appendPQExpBufferChar ( query , * s + + ) ;
}
appendPQExpBufferChar ( query , ' \' ' ) ;
appendPQExpBuffer ( query , ( findx < tgnargs - 1 ) ? " , " : " " ) ;
tgargs = p + 4 ;
}
appendPQExpBuffer ( query , " ); \n " ) ;
ArchiveEntry ( fout , tgoid ,
tgname ,
tbinfo - > relnamespace - > nspname ,
tbinfo - > usename ,
" TRIGGER " , NULL ,
query - > data , delqry - > data ,
NULL , NULL , NULL ) ;
resetPQExpBuffer ( query ) ;
appendPQExpBuffer ( query , " TRIGGER %s " ,
fmtId ( tgname , force_quotes ) ) ;
appendPQExpBuffer ( query , " ON %s " ,
fmtId ( tbinfo - > relname , force_quotes ) ) ;
dumpComment ( fout , query - > data ,
tbinfo - > relnamespace - > nspname , tbinfo - > usename ,
tgoid , " pg_trigger " , 0 , NULL ) ;
1997-10-02 13:57:07 +00:00
}
2002-05-10 22:36:27 +00:00
PQclear ( res ) ;
1997-10-02 13:57:07 +00:00
}
2002-05-10 22:36:27 +00:00
destroyPQExpBuffer ( query ) ;
destroyPQExpBuffer ( delqry ) ;
1997-10-02 13:57:07 +00:00
}
1998-07-19 05:24:51 +00:00
1998-10-06 22:14:21 +00:00
static void
2002-05-10 22:36:27 +00:00
dumpRules ( Archive * fout , TableInfo * tblinfo , int numTables )
1998-10-06 22:14:21 +00:00
{
1999-05-25 16:15:34 +00:00
PGresult * res ;
int nrules ;
int i ,
t ;
2000-04-12 17:17:23 +00:00
PQExpBuffer query = createPQExpBuffer ( ) ;
1999-05-25 16:15:34 +00:00
int i_definition ;
2000-04-12 17:17:23 +00:00
int i_oid ;
int i_rulename ;
1998-10-06 22:14:21 +00:00
if ( g_verbose )
2001-07-03 20:21:50 +00:00
write_msg ( NULL , " dumping out rules \n " ) ;
1998-10-06 22:14:21 +00:00
/*
* For each table we dump
*/
for ( t = 0 ; t < numTables ; t + + )
{
2002-05-10 22:36:27 +00:00
TableInfo * tbinfo = & tblinfo [ t ] ;
if ( ! tbinfo - > hasrules | | ! tbinfo - > dump )
1998-10-06 22:14:21 +00:00
continue ;
2002-05-10 22:36:27 +00:00
/* Make sure we are in proper schema */
selectSourceSchema ( tbinfo - > relnamespace - > nspname ) ;
1998-10-06 22:14:21 +00:00
/*
2002-04-19 23:13:54 +00:00
* Get all rules defined for this table , except view select rules
1998-10-06 22:14:21 +00:00
*/
1999-12-27 15:42:44 +00:00
resetPQExpBuffer ( query ) ;
2002-04-18 20:01:11 +00:00
2002-05-28 22:26:57 +00:00
if ( g_fout - > remoteVersion > = 70300 )
{
appendPQExpBuffer ( query ,
" SELECT pg_catalog.pg_get_ruledef(oid) AS definition, "
" oid, rulename "
" FROM pg_catalog.pg_rewrite "
" WHERE ev_class = '%s'::pg_catalog.oid "
" AND rulename != '_RETURN' "
" ORDER BY oid " ,
tbinfo - > oid ) ;
}
else
2002-04-18 20:01:11 +00:00
{
/*
* We include pg_rules in the cross since it filters out all view
* rules ( pjw 15 - Sep - 2000 ) .
*/
appendPQExpBuffer ( query , " SELECT definition, "
" pg_rewrite.oid, pg_rewrite.rulename "
" FROM pg_rewrite, pg_class, pg_rules "
" WHERE pg_class.relname = " ) ;
2002-05-10 22:36:27 +00:00
formatStringLiteral ( query , tbinfo - > relname , CONV_ALL ) ;
2002-04-18 20:01:11 +00:00
appendPQExpBuffer ( query ,
" AND pg_rewrite.ev_class = pg_class.oid "
" AND pg_rules.tablename = pg_class.relname "
" AND pg_rules.rulename = pg_rewrite.rulename "
" ORDER BY pg_rewrite.oid " ) ;
}
1999-12-27 15:42:44 +00:00
res = PQexec ( g_conn , query - > data ) ;
1998-10-06 22:14:21 +00:00
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
2001-06-27 21:21:37 +00:00
write_msg ( NULL , " query to get rules associated with table \" %s \" failed: %s " ,
2002-05-10 22:36:27 +00:00
tbinfo - > relname , PQerrorMessage ( g_conn ) ) ;
2001-07-03 20:21:50 +00:00
exit_nicely ( ) ;
1998-10-06 22:14:21 +00:00
}
nrules = PQntuples ( res ) ;
i_definition = PQfnumber ( res , " definition " ) ;
2000-01-18 18:09:02 +00:00
i_oid = PQfnumber ( res , " oid " ) ;
i_rulename = PQfnumber ( res , " rulename " ) ;
1998-10-06 22:14:21 +00:00
/*
* Dump them out
*/
2000-01-18 18:09:02 +00:00
2000-04-12 17:17:23 +00:00
for ( i = 0 ; i < nrules ; i + + )
{
2002-05-10 22:36:27 +00:00
ArchiveEntry ( fout , PQgetvalue ( res , i , i_oid ) ,
PQgetvalue ( res , i , i_rulename ) ,
tbinfo - > relnamespace - > nspname ,
tbinfo - > usename ,
" RULE " , NULL ,
PQgetvalue ( res , i , i_definition ) ,
" " , /* Del */
NULL , NULL , NULL ) ;
1998-10-06 22:14:21 +00:00
2000-01-18 18:09:02 +00:00
/* Dump rule comments */
resetPQExpBuffer ( query ) ;
appendPQExpBuffer ( query , " RULE %s " , fmtId ( PQgetvalue ( res , i , i_rulename ) , force_quotes ) ) ;
2002-05-10 22:36:27 +00:00
appendPQExpBuffer ( query , " ON %s " , fmtId ( tbinfo - > relname , force_quotes ) ) ;
dumpComment ( fout , query - > data ,
tbinfo - > relnamespace - > nspname ,
tbinfo - > usename ,
PQgetvalue ( res , i , i_oid ) , " pg_rewrite " , 0 , NULL ) ;
2000-04-12 17:17:23 +00:00
2000-01-18 18:09:02 +00:00
}
1998-10-06 22:14:21 +00:00
PQclear ( res ) ;
}
2001-08-03 19:43:05 +00:00
destroyPQExpBuffer ( query ) ;
1998-10-06 22:14:21 +00:00
}
2002-05-10 22:36:27 +00:00
/*
* selectSourceSchema - make the specified schema the active search path
* in the source database .
*
2002-05-28 22:26:57 +00:00
* NB : pg_catalog is explicitly searched after the specified schema ;
* so user names are only qualified if they are cross - schema references ,
* and system names are only qualified if they conflict with a user name
* in the current schema .
*
* Whenever the selected schema is not pg_catalog , be careful to qualify
* references to system catalogs and types in our emitted commands !
2002-05-10 22:36:27 +00:00
*/
static void
selectSourceSchema ( const char * schemaName )
{
static char * curSchemaName = NULL ;
PQExpBuffer query ;
PGresult * res ;
/* Not relevant if fetching from pre-7.3 DB */
if ( g_fout - > remoteVersion < 70300 )
return ;
/* Ignore null schema names */
if ( schemaName = = NULL | | * schemaName = = ' \0 ' )
return ;
/* Optimize away repeated selection of same schema */
if ( curSchemaName & & strcmp ( curSchemaName , schemaName ) = = 0 )
return ;
query = createPQExpBuffer ( ) ;
appendPQExpBuffer ( query , " SET search_path = %s " ,
fmtId ( schemaName , force_quotes ) ) ;
2002-05-28 22:26:57 +00:00
if ( strcmp ( schemaName , " pg_catalog " ) ! = 0 )
appendPQExpBuffer ( query , " , pg_catalog " ) ;
2002-05-10 22:36:27 +00:00
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_COMMAND_OK )
{
write_msg ( NULL , " query to set search_path failed: %s " ,
PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
PQclear ( res ) ;
destroyPQExpBuffer ( query ) ;
if ( curSchemaName )
free ( curSchemaName ) ;
curSchemaName = strdup ( schemaName ) ;
}
/*
* getFormattedTypeName - retrieve a nicely - formatted type name for the
* given type name .
*
* NB : in 7.3 and up the result may depend on the currently - selected
* schema ; this is why we don ' t try to cache the names .
*/
static char *
getFormattedTypeName ( const char * oid , OidOptions opts )
{
char * result ;
PQExpBuffer query ;
PGresult * res ;
int ntups ;
if ( atooid ( oid ) = = 0 )
{
if ( ( opts & zeroAsOpaque ) ! = 0 )
return strdup ( g_opaque_type ) ;
else if ( ( opts & zeroAsAny ) ! = 0 )
return strdup ( " 'any' " ) ;
else if ( ( opts & zeroAsStar ) ! = 0 )
return strdup ( " * " ) ;
else if ( ( opts & zeroAsNone ) ! = 0 )
return strdup ( " NONE " ) ;
}
query = createPQExpBuffer ( ) ;
2002-05-28 22:26:57 +00:00
if ( g_fout - > remoteVersion > = 70300 )
{
appendPQExpBuffer ( query , " SELECT pg_catalog.format_type('%s'::pg_catalog.oid, NULL) " ,
oid ) ;
}
else if ( g_fout - > remoteVersion > = 70100 )
2002-05-10 22:36:27 +00:00
{
appendPQExpBuffer ( query , " SELECT format_type('%s'::oid, NULL) " ,
oid ) ;
}
else
{
appendPQExpBuffer ( query , " SELECT typname "
" FROM pg_type "
" WHERE oid = '%s'::oid " ,
oid ) ;
}
res = PQexec ( g_conn , query - > data ) ;
if ( ! res | |
PQresultStatus ( res ) ! = PGRES_TUPLES_OK )
{
write_msg ( NULL , " query to obtain type name for %s failed: %s " ,
oid , PQerrorMessage ( g_conn ) ) ;
exit_nicely ( ) ;
}
/* Expecting a single result only */
ntups = PQntuples ( res ) ;
if ( ntups ! = 1 )
{
write_msg ( NULL , " Got %d rows instead of one from: %s " ,
ntups , query - > data ) ;
exit_nicely ( ) ;
}
2002-05-28 22:26:57 +00:00
if ( g_fout - > remoteVersion > = 70100 )
{
/* already quoted */
result = strdup ( PQgetvalue ( res , 0 , 0 ) ) ;
}
else
{
/* may need to quote it */
result = strdup ( fmtId ( PQgetvalue ( res , 0 , 0 ) , false ) ) ;
}
2002-05-10 22:36:27 +00:00
PQclear ( res ) ;
destroyPQExpBuffer ( query ) ;
return result ;
}
/*
* myFormatType - - - local implementation of format_type for use with 7.0 .
*/
static char *
myFormatType ( const char * typname , int32 typmod )
{
char * result ;
PQExpBuffer buf = createPQExpBuffer ( ) ;
/* Show lengths on bpchar and varchar */
if ( ! strcmp ( typname , " bpchar " ) )
{
int len = ( typmod - VARHDRSZ ) ;
appendPQExpBuffer ( buf , " character " ) ;
if ( len > 1 )
appendPQExpBuffer ( buf , " (%d) " ,
typmod - VARHDRSZ ) ;
}
else if ( ! strcmp ( typname , " varchar " ) )
{
appendPQExpBuffer ( buf , " character varying " ) ;
if ( typmod ! = - 1 )
appendPQExpBuffer ( buf , " (%d) " ,
typmod - VARHDRSZ ) ;
}
else if ( ! strcmp ( typname , " numeric " ) )
{
appendPQExpBuffer ( buf , " numeric " ) ;
if ( typmod ! = - 1 )
{
int32 tmp_typmod ;
int precision ;
int scale ;
tmp_typmod = typmod - VARHDRSZ ;
precision = ( tmp_typmod > > 16 ) & 0xffff ;
scale = tmp_typmod & 0xffff ;
appendPQExpBuffer ( buf , " (%d,%d) " ,
precision , scale ) ;
}
}
/*
* char is an internal single - byte data type ; Let ' s make sure we force
* it through with quotes . - thomas 1998 - 12 - 13
*/
else if ( ! strcmp ( typname , " char " ) )
{
2002-07-04 03:04:55 +00:00
appendPQExpBuffer ( buf , " %s " , fmtId ( typname , true ) ) ;
2002-05-10 22:36:27 +00:00
}
else
{
2002-07-04 03:04:55 +00:00
appendPQExpBuffer ( buf , " %s " , fmtId ( typname , false ) ) ;
2002-05-10 22:36:27 +00:00
}
result = strdup ( buf - > data ) ;
destroyPQExpBuffer ( buf ) ;
return result ;
}
/*
* fmtQualifiedId - convert a qualified name to the proper format for
* the source database .
*
* Like fmtId , use the result before calling again .
*/
static const char *
fmtQualifiedId ( const char * schema , const char * id )
{
static PQExpBuffer id_return = NULL ;
if ( id_return ) /* first time through? */
resetPQExpBuffer ( id_return ) ;
else
id_return = createPQExpBuffer ( ) ;
/* Suppress schema name if fetching from pre-7.3 DB */
if ( g_fout - > remoteVersion > = 70300 & & schema & & * schema )
{
appendPQExpBuffer ( id_return , " %s. " ,
fmtId ( schema , force_quotes ) ) ;
}
appendPQExpBuffer ( id_return , " %s " ,
fmtId ( id , force_quotes ) ) ;
return id_return - > data ;
}
2002-07-18 04:43:51 +00:00
/*
2002-08-02 18:15:10 +00:00
* return a column list clause for the given relation .
2002-07-18 04:43:51 +00:00
* returns an empty string if the remote server is older than
* 7.3 .
*/
static const char *
fmtCopyColumnList ( const TableInfo * ti )
{
static PQExpBuffer q = NULL ;
int numatts = ti - > numatts ;
char * * attnames = ti - > attnames ;
2002-08-02 18:15:10 +00:00
bool * attisdropped = ti - > attisdropped ;
bool needComma ;
2002-07-18 04:43:51 +00:00
int i ;
2002-08-02 18:15:10 +00:00
if ( g_fout - > remoteVersion < 70300 )
2002-07-18 04:43:51 +00:00
return " " ;
if ( q ) /* first time through? */
resetPQExpBuffer ( q ) ;
else
q = createPQExpBuffer ( ) ;
resetPQExpBuffer ( q ) ;
2002-08-02 18:15:10 +00:00
appendPQExpBuffer ( q , " ( " ) ;
needComma = false ;
2002-07-18 04:43:51 +00:00
for ( i = 0 ; i < numatts ; i + + )
{
2002-08-02 18:15:10 +00:00
if ( attisdropped [ i ] )
continue ;
if ( needComma )
appendPQExpBuffer ( q , " , " ) ;
appendPQExpBuffer ( q , " %s " , fmtId ( attnames [ i ] , force_quotes ) ) ;
needComma = true ;
2002-07-18 04:43:51 +00:00
}
appendPQExpBuffer ( q , " ) " ) ;
return q - > data ;
}