@ -3,7 +3,7 @@
*
* Copyright 2000 by PostgreSQL Global Development Group
*
* $ Header : / cvsroot / pgsql / src / bin / psql / common . c , v 1.53 2003 / 01 / 07 22 : 23 : 17 tgl Exp $
* $ Header : / cvsroot / pgsql / src / bin / psql / common . c , v 1.54 2003 / 02 / 19 03 : 54 : 39 momjian Exp $
*/
# include "postgres_fe.h"
# include "common.h"
@ -42,6 +42,26 @@
# include "print.h"
# include "mainloop.h"
/* Workarounds for Windows */
/* Probably to be moved up the source tree in the future, perhaps to be replaced by
* more specific checks like configure - style HAVE_GETTIMEOFDAY macros .
*/
# ifndef WIN32
typedef struct timeval TimevalStruct ;
# define GETTIMEOFDAY(T) gettimeofday(T, NULL)
# define DIFF_MSEC(T, U) ((((T)->tv_sec - (U)->tv_sec) * 1000000.0 + (T)->tv_usec - (U)->tv_usec) / 1000.0)
# else
typedef struct _timeb TimevalStruct ;
# define GETTIMEOFDAY(T) _ftime(&T)
# define DIFF_MSEC(T, U) ((((T)->time - (U)->time) * 1000.0 + (T)->millitm - (U)->millitm))
# endif
extern bool prompt_state ;
/*
@ -206,6 +226,63 @@ handle_sigint(SIGNAL_ARGS)
# endif /* not WIN32 */
/* ConnectionUp
*
* Returns whether our backend connection is still there .
*/
static bool
ConnectionUp ( )
{
return PQstatus ( pset . db ) ! = CONNECTION_BAD ;
}
/* CheckConnection
*
* Verify that we still have a good connection to the backend , and if not ,
* see if it can be restored .
*
* Returns true if either the connection was still there , or it could be
* restored successfully ; false otherwise . If , however , there was no
* connection and the session is non - interactive , this will exit the program
* with a code of EXIT_BADCONN .
*/
static bool
CheckConnection ( )
{
bool OK = ConnectionUp ( ) ;
if ( ! OK )
{
if ( ! pset . cur_cmd_interactive )
{
psql_error ( " connection to server was lost \n " ) ;
exit ( EXIT_BADCONN ) ;
}
fputs ( gettext ( " The connection to the server was lost. Attempting reset: " ) , stderr ) ;
PQreset ( pset . db ) ;
OK = ConnectionUp ( ) ;
if ( ! OK )
{
fputs ( gettext ( " Failed. \n " ) , stderr ) ;
PQfinish ( pset . db ) ;
pset . db = NULL ;
SetVariable ( pset . vars , " DBNAME " , NULL ) ;
SetVariable ( pset . vars , " HOST " , NULL ) ;
SetVariable ( pset . vars , " PORT " , NULL ) ;
SetVariable ( pset . vars , " USER " , NULL ) ;
SetVariable ( pset . vars , " ENCODING " , NULL ) ;
}
else
fputs ( gettext ( " Succeeded. \n " ) , stderr ) ;
}
return OK ;
}
/*
* PSQLexec
*
@ -250,19 +327,22 @@ PSQLexec(const char *query, bool ignore_command_ok)
cancelConn = pset . db ;
if ( PQsendQuery ( pset . db , query ) )
{
while ( ( newres = PQgetResult ( pset . db ) ) ! = NULL )
rstatus = PGRES_EMPTY_QUERY ;
while ( ( ( newres = PQgetResult ( pset . db ) ) ! = NULL ) & &
( rstatus = = PGRES_COPY_IN ) & &
( rstatus = = PGRES_COPY_OUT ) )
{
rstatus = PQresultStatus ( newres ) ;
if ( ignore_command_ok & & rstatus = = PGRES_COMMAND_OK )
{
PQclear ( newres ) ;
continue ;
}
PQclear ( res ) ;
res = newres ;
if ( rstatus = = PGRES_COPY_IN | |
rstatus = = PGRES_COPY_OUT )
break ;
else
{
PQclear ( res ) ;
res = newres ;
}
}
}
rstatus = PQresultStatus ( res ) ;
@ -277,37 +357,147 @@ PSQLexec(const char *query, bool ignore_command_ok)
rstatus = = PGRES_COPY_IN | |
rstatus = = PGRES_COPY_OUT ) )
return res ;
else
psql_error ( " %s " , PQerrorMessage ( pset . db ) ) ;
PQclear ( res ) ;
CheckConnection ( ) ;
return NULL ;
}
/*
* PrintNotifications : check for asynchronous notifications , and print them out
*
*/
static void
PrintNotifications ( void )
{
PGnotify * notify ;
while ( ( notify = PQnotifies ( pset . db ) ) ! = NULL )
{
psql_error ( " %s " , PQerrorMessage ( pset . db ) ) ;
PQclear ( res ) ;
fprintf ( pset . queryFout , gettext ( " Asynchronous NOTIFY '%s' from backend with pid %d received. \n " ) ,
notify - > relname , notify - > be_pid ) ;
free ( notify ) ;
fflush ( pset . queryFout ) ;
}
}
if ( PQstatus ( pset . db ) = = CONNECTION_BAD )
/*
* PrintQueryTuples : assuming query result is OK , print its tuples
*
* Returns true if successful , false otherwise .
*/
static bool
PrintQueryTuples ( const PGresult * results )
{
/* write output to \g argument, if any */
if ( pset . gfname )
{
FILE * queryFout_copy = pset . queryFout ;
bool queryFoutPipe_copy = pset . queryFoutPipe ;
pset . queryFout = stdout ; /* so it doesn't get
* closed */
/* open file/pipe */
if ( ! setQFout ( pset . gfname ) )
{
if ( ! pset . cur_cmd_interactive )
{
psql_error ( " connection to server was lost \n " ) ;
exit ( EXIT_BADCONN ) ;
}
fputs ( gettext ( " The connection to the server was lost. Attempting reset: " ) , stderr ) ;
PQreset ( pset . db ) ;
if ( PQstatus ( pset . db ) = = CONNECTION_BAD )
{
fputs ( gettext ( " Failed. \n " ) , stderr ) ;
PQfinish ( pset . db ) ;
pset . db = NULL ;
SetVariable ( pset . vars , " DBNAME " , NULL ) ;
SetVariable ( pset . vars , " HOST " , NULL ) ;
SetVariable ( pset . vars , " PORT " , NULL ) ;
SetVariable ( pset . vars , " USER " , NULL ) ;
SetVariable ( pset . vars , " ENCODING " , NULL ) ;
}
else
fputs ( gettext ( " Succeeded. \n " ) , stderr ) ;
pset . queryFout = queryFout_copy ;
pset . queryFoutPipe = queryFoutPipe_copy ;
return false ;
}
return NULL ;
printQuery ( results , & pset . popt , pset . queryFout ) ;
/* close file/pipe, restore old setting */
setQFout ( NULL ) ;
pset . queryFout = queryFout_copy ;
pset . queryFoutPipe = queryFoutPipe_copy ;
free ( pset . gfname ) ;
pset . gfname = NULL ;
}
else
{
printQuery ( results , & pset . popt , pset . queryFout ) ;
}
return true ;
}
/*
* PrintQueryResults : analyze query results and print them out
*
* Note : Utility function for use by SendQuery ( ) only .
*
* Returns true if the query executed successfully , false otherwise .
*/
static bool
PrintQueryResults ( PGresult * results ,
const TimevalStruct * before ,
const TimevalStruct * after )
{
bool success = false ;
switch ( PQresultStatus ( results ) )
{
case PGRES_TUPLES_OK :
success = PrintQueryTuples ( results ) ;
break ;
case PGRES_EMPTY_QUERY :
success = true ;
break ;
case PGRES_COMMAND_OK :
{
char buf [ 10 ] ;
success = true ;
sprintf ( buf , " %u " , ( unsigned int ) PQoidValue ( results ) ) ;
if ( ! QUIET ( ) )
fprintf ( pset . queryFout , " %s \n " , PQcmdStatus ( results ) ) ;
SetVariable ( pset . vars , " LASTOID " , buf ) ;
break ;
}
case PGRES_COPY_OUT :
success = handleCopyOut ( pset . db , pset . queryFout ) ;
break ;
case PGRES_COPY_IN :
if ( pset . cur_cmd_interactive & & ! QUIET ( ) )
puts ( gettext ( " Enter data to be copied followed by a newline. \n "
" End with a backslash and a period on a line by itself. " ) ) ;
success = handleCopyIn ( pset . db , pset . cur_cmd_source ,
pset . cur_cmd_interactive ? get_prompt ( PROMPT_COPY ) : NULL ) ;
break ;
case PGRES_NONFATAL_ERROR :
case PGRES_FATAL_ERROR :
case PGRES_BAD_RESPONSE :
success = false ;
psql_error ( " %s " , PQerrorMessage ( pset . db ) ) ;
break ;
}
fflush ( pset . queryFout ) ;
if ( ! CheckConnection ( ) ) return false ;
PrintNotifications ( ) ;
/* Possible microtiming output */
if ( pset . timing & & success )
printf ( gettext ( " Time: %.2f ms \n " ) , DIFF_MSEC ( after , before ) ) ;
return success ;
}
@ -327,16 +517,8 @@ PSQLexec(const char *query, bool ignore_command_ok)
bool
SendQuery ( const char * query )
{
bool success = false ;
PGresult * results ;
PGnotify * notify ;
# ifndef WIN32
struct timeval before ,
after ;
# else
struct _timeb before ,
after ;
# endif
TimevalStruct before , after ;
if ( ! pset . db )
{
@ -367,19 +549,11 @@ SendQuery(const char *query)
cancelConn = pset . db ;
# ifndef WIN32
if ( pset . timing )
gettimeofday ( & before , NULL ) ;
GETTIMEOFDAY ( & before ) ;
results = PQexec ( pset . db , query ) ;
if ( pset . timing )
gettimeofday ( & after , NULL ) ;
# else
if ( pset . timing )
_ftime ( & before ) ;
results = PQexec ( pset . db , query ) ;
if ( pset . timing )
_ftime ( & after ) ;
# endif
GETTIMEOFDAY ( & after ) ;
if ( PQresultStatus ( results ) = = PGRES_COPY_IN )
copy_in_state = true ;
@ -390,137 +564,11 @@ SendQuery(const char *query)
if ( results = = NULL )
{
fputs ( PQerrorMessage ( pset . db ) , pset . queryFout ) ;
success = false ;
}
else
{
switch ( PQresultStatus ( results ) )
{
case PGRES_TUPLES_OK :
/* write output to \g argument, if any */
if ( pset . gfname )
{
FILE * queryFout_copy = pset . queryFout ;
bool queryFoutPipe_copy = pset . queryFoutPipe ;
pset . queryFout = stdout ; /* so it doesn't get
* closed */
/* open file/pipe */
if ( ! setQFout ( pset . gfname ) )
{
pset . queryFout = queryFout_copy ;
pset . queryFoutPipe = queryFoutPipe_copy ;
success = false ;
break ;
}
printQuery ( results , & pset . popt , pset . queryFout ) ;
/* close file/pipe, restore old setting */
setQFout ( NULL ) ;
pset . queryFout = queryFout_copy ;
pset . queryFoutPipe = queryFoutPipe_copy ;
free ( pset . gfname ) ;
pset . gfname = NULL ;
success = true ;
}
else
{
printQuery ( results , & pset . popt , pset . queryFout ) ;
success = true ;
}
break ;
case PGRES_EMPTY_QUERY :
success = true ;
break ;
case PGRES_COMMAND_OK :
{
char buf [ 10 ] ;
success = true ;
sprintf ( buf , " %u " , ( unsigned int ) PQoidValue ( results ) ) ;
if ( ! QUIET ( ) )
fprintf ( pset . queryFout , " %s \n " , PQcmdStatus ( results ) ) ;
SetVariable ( pset . vars , " LASTOID " , buf ) ;
break ;
}
case PGRES_COPY_OUT :
success = handleCopyOut ( pset . db , pset . queryFout ) ;
break ;
case PGRES_COPY_IN :
if ( pset . cur_cmd_interactive & & ! QUIET ( ) )
puts ( gettext ( " Enter data to be copied followed by a newline. \n "
" End with a backslash and a period on a line by itself. " ) ) ;
success = handleCopyIn ( pset . db , pset . cur_cmd_source ,
pset . cur_cmd_interactive ? get_prompt ( PROMPT_COPY ) : NULL ) ;
break ;
case PGRES_NONFATAL_ERROR :
case PGRES_FATAL_ERROR :
case PGRES_BAD_RESPONSE :
success = false ;
psql_error ( " %s " , PQerrorMessage ( pset . db ) ) ;
break ;
}
fflush ( pset . queryFout ) ;
if ( PQstatus ( pset . db ) = = CONNECTION_BAD )
{
if ( ! pset . cur_cmd_interactive )
{
psql_error ( " connection to server was lost \n " ) ;
exit ( EXIT_BADCONN ) ;
}
fputs ( gettext ( " The connection to the server was lost. Attempting reset: " ) , stderr ) ;
PQreset ( pset . db ) ;
if ( PQstatus ( pset . db ) = = CONNECTION_BAD )
{
fputs ( gettext ( " Failed. \n " ) , stderr ) ;
PQfinish ( pset . db ) ;
PQclear ( results ) ;
pset . db = NULL ;
SetVariable ( pset . vars , " DBNAME " , NULL ) ;
SetVariable ( pset . vars , " HOST " , NULL ) ;
SetVariable ( pset . vars , " PORT " , NULL ) ;
SetVariable ( pset . vars , " USER " , NULL ) ;
SetVariable ( pset . vars , " ENCODING " , NULL ) ;
return false ;
}
else
fputs ( gettext ( " Succeeded. \n " ) , stderr ) ;
}
/* check for asynchronous notification returns */
while ( ( notify = PQnotifies ( pset . db ) ) ! = NULL )
{
fprintf ( pset . queryFout , gettext ( " Asynchronous NOTIFY '%s' from backend with pid %d received. \n " ) ,
notify - > relname , notify - > be_pid ) ;
free ( notify ) ;
fflush ( pset . queryFout ) ;
}
if ( results )
PQclear ( results ) ;
return false ;
}
/* Possible microtiming output */
if ( pset . timing & & success )
# ifndef WIN32
printf ( gettext ( " Time: %.2f ms \n " ) ,
( ( after . tv_sec - before . tv_sec ) * 1000000.0 + after . tv_usec - before . tv_usec ) / 1000.0 ) ;
# else
printf ( gettext ( " Time: %.2f ms \n " ) ,
( ( after . time - before . time ) * 1000.0 + after . millitm - before . millitm ) ) ;
# endif
return success ;
return PrintQueryResults ( results , & before , & after ) ;
PQclear ( results ) ;
}