@ -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 ;
}
else
{
PQclear ( res ) ;
res = newres ;
if ( rstatus = = PGRES_COPY_IN | |
rstatus = = PGRES_COPY_OUT )
break ;
}
}
}
rstatus = PQresultStatus ( res ) ;
@ -277,126 +357,44 @@ 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 ) ;
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 ) ;
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 ) ;
}
CheckConnection ( ) ;
return NULL ;
}
}
/*
* SendQuery : send the query string to the backend
* ( and print out results )
*
* Note : This is the " front door " way to send a query . That is , use it to
* send queries actually entered by the user . These queries will be subject to
* single step mode .
* To send " back door " queries ( generated by slash commands , etc . ) in a
* controlled way , use PSQLexec ( ) .
* PrintNotifications : check for asynchronous notifications , and print them out
*
* Returns true if the query executed successfully , false otherwise .
*/
bool
SendQuery ( const char * query )
static void
PrintNotifications ( void )
{
bool success = false ;
PGresult * results ;
PGnotify * notify ;
# ifndef WIN32
struct timeval before ,
after ;
# else
struct _timeb before ,
after ;
# endif
if ( ! pset . db )
{
psql_error ( " You are currently not connected to a database. \n " ) ;
return false ;
}
if ( GetVariableBool ( pset . vars , " SINGLESTEP " ) )
{
char buf [ 3 ] ;
printf ( gettext ( " ***(Single step mode: Verify query)********************************************* \n "
" %s \n "
" ***(press return to proceed or enter x and return to cancel)******************** \n " ) ,
query ) ;
fflush ( stdout ) ;
if ( fgets ( buf , sizeof ( buf ) , stdin ) ! = NULL )
if ( buf [ 0 ] = = ' x ' )
return false ;
}
else
while ( ( notify = PQnotifies ( pset . db ) ) ! = NULL )
{
const char * var = GetVariable ( pset . vars , " ECHO " ) ;
if ( var & & strncmp ( var , " queries " , strlen ( var ) ) = = 0 )
puts ( query ) ;
fprintf ( pset . queryFout , gettext ( " Asynchronous NOTIFY '%s' from backend with pid %d received. \n " ) ,
notify - > relname , notify - > be_pid ) ;
free ( notify ) ;
fflush ( pset . queryFout ) ;
}
}
cancelConn = pset . db ;
# ifndef WIN32
if ( pset . timing )
gettimeofday ( & before , NULL ) ;
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
if ( PQresultStatus ( results ) = = PGRES_COPY_IN )
copy_in_state = true ;
/* keep cancel connection for copy out state */
if ( PQresultStatus ( results ) ! = PGRES_COPY_OUT )
cancelConn = NULL ;
if ( results = = NULL )
{
fputs ( PQerrorMessage ( pset . db ) , pset . queryFout ) ;
success = false ;
}
else
{
switch ( PQresultStatus ( results ) )
{
case PGRES_TUPLES_OK :
/*
* 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 )
{
@ -411,8 +409,7 @@ SendQuery(const char *query)
{
pset . queryFout = queryFout_copy ;
pset . queryFoutPipe = queryFoutPipe_copy ;
success = false ;
break ;
return false ;
}
printQuery ( results , & pset . popt , pset . queryFout ) ;
@ -425,14 +422,35 @@ SendQuery(const char *query)
free ( pset . gfname ) ;
pset . gfname = NULL ;
success = true ;
}
else
{
printQuery ( results , & pset . popt , pset . queryFout ) ;
success = true ;
}
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 ;
@ -471,56 +489,86 @@ SendQuery(const char *query)
fflush ( pset . queryFout ) ;
if ( PQstatus ( pset . db ) = = CONNECTION_BAD )
{
if ( ! pset . cur_cmd_interactive )
if ( ! CheckConnection ( ) ) return false ;
PrintNotifications ( ) ;
/* Possible microtiming output */
if ( pset . timing & & success )
printf ( gettext ( " Time: %.2f ms \n " ) , DIFF_MSEC ( after , before ) ) ;
return success ;
}
/*
* SendQuery : send the query string to the backend
* ( and print out results )
*
* Note : This is the " front door " way to send a query . That is , use it to
* send queries actually entered by the user . These queries will be subject to
* single step mode .
* To send " back door " queries ( generated by slash commands , etc . ) in a
* controlled way , use PSQLexec ( ) .
*
* Returns true if the query executed successfully , false otherwise .
*/
bool
SendQuery ( const char * query )
{
PGresult * results ;
TimevalStruct before , after ;
if ( ! pset . db )
{
psql_error ( " connection to server was lost \n " ) ;
exit ( EXIT_BADCONN ) ;
psql_error ( " You are currently not connected to a database. \n " ) ;
return false ;
}
fputs ( gettext ( " The connection to the server was lost. Attempting reset: " ) , stderr ) ;
PQreset ( pset . db ) ;
if ( PQstatus ( pset . db ) = = CONNECTION_BAD )
if ( GetVariableBool ( pset . vars , " SINGLESTEP " ) )
{
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 ) ;
char buf [ 3 ] ;
printf ( gettext ( " ***(Single step mode: Verify query)********************************************* \n "
" %s \n "
" ***(press return to proceed or enter x and return to cancel)******************** \n " ) ,
query ) ;
fflush ( stdout ) ;
if ( fgets ( buf , sizeof ( buf ) , stdin ) ! = NULL )
if ( buf [ 0 ] = = ' x ' )
return false ;
}
else
fputs ( gettext ( " Succeeded. \n " ) , stderr ) ;
{
const char * var = GetVariable ( pset . vars , " ECHO " ) ;
if ( var & & strncmp ( var , " queries " , strlen ( var ) ) = = 0 )
puts ( query ) ;
}
/* check for asynchronous notification returns */
while ( ( notify = PQnotifies ( pset . db ) ) ! = NULL )
cancelConn = pset . db ;
if ( pset . timing )
GETTIMEOFDAY ( & before ) ;
results = PQexec ( pset . db , query ) ;
if ( pset . timing )
GETTIMEOFDAY ( & after ) ;
if ( PQresultStatus ( results ) = = PGRES_COPY_IN )
copy_in_state = true ;
/* keep cancel connection for copy out state */
if ( PQresultStatus ( results ) ! = PGRES_COPY_OUT )
cancelConn = NULL ;
if ( results = = 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 ) ;
fputs ( PQerrorMessage ( pset . db ) , pset . queryFout ) ;
return false ;
}
if ( results )
return PrintQueryResults ( results , & before , & after ) ;
PQclear ( results ) ;
}
/* 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 ;
}