@ -26,72 +26,90 @@
# include "mbprint.h"
static bool ExecQueryUsingCursor ( const char * query , double * elapsed_msec ) ;
static bool command_no_begin ( const char * query ) ;
static bool is_select_command ( const char * query ) ;
/*
* setQFout
* - - handler for - o command line option and \ o command
* openQueryOutputFile - - - attempt to open a query output file
*
* Tries to open file fname ( or pipe if fname starts with ' | ' )
* and stores the file handle in pset )
* Upon failure , sets stdout and returns false .
* fname = = NULL selects stdout , else an initial ' | ' selects a pipe ,
* else plain file .
*
* Returns output file pointer into * fout , and is - a - pipe flag into * is_pipe .
* Caller is responsible for adjusting SIGPIPE state if it ' s a pipe .
*
* On error , reports suitable error message and returns FALSE .
*/
bool
setQFout ( const char * fname )
openQueryOutputFile ( const char * fname , FILE * * fout , bool * is_pip e )
{
bool status = true ;
/* Close old file/pipe */
if ( pset . queryFout & & pset . queryFout ! = stdout & & pset . queryFout ! = stderr )
{
if ( pset . queryFoutPipe )
pclose ( pset . queryFout ) ;
else
fclose ( pset . queryFout ) ;
}
/* If no filename, set stdout */
if ( ! fname | | fname [ 0 ] = = ' \0 ' )
{
pset . queryF out = stdout ;
pset . queryFoutP ipe = false ;
* fout = stdout ;
* is_pipe = false ;
}
else if ( * fname = = ' | ' )
{
pset . queryF out = popen ( fname + 1 , " w " ) ;
pset . queryFoutP ipe = true ;
* fout = popen ( fname + 1 , " w " ) ;
* is_pipe = true ;
}
else
{
pset . queryF out = fopen ( fname , " w " ) ;
pset . queryFoutP ipe = false ;
* f out = fopen ( fname , " w " ) ;
* is_p ipe = false ;
}
if ( ! ( pset . queryFout ) )
if ( * fout = = NULL )
{
psql_error ( " %s: %s \n " , fname , strerror ( errno ) ) ;
pset . queryFout = stdout ;
pset . queryFoutPipe = false ;
status = false ;
return false ;
}
/* Direct signals */
# ifndef WIN32
pqsignal ( SIGPIPE , pset . queryFoutPipe ? SIG_IGN : SIG_DFL ) ;
# endif
return status ;
return true ;
}
/*
* setQFout
* - - handler for - o command line option and \ o command
*
* On success , updates pset with the new output file and returns true .
* On failure , returns false without changing pset state .
*/
bool
setQFout ( const char * fname )
{
FILE * fout ;
bool is_pipe ;
/* First make sure we can open the new output file/pipe */
if ( ! openQueryOutputFile ( fname , & fout , & is_pipe ) )
return false ;
/* Close old file/pipe */
if ( pset . queryFout & & pset . queryFout ! = stdout & & pset . queryFout ! = stderr )
{
if ( pset . queryFoutPipe )
pclose ( pset . queryFout ) ;
else
fclose ( pset . queryFout ) ;
}
pset . queryFout = fout ;
pset . queryFoutPipe = is_pipe ;
/* Adjust SIGPIPE handling appropriately: ignore signal if is_pipe */
set_sigpipe_trap_state ( is_pipe ) ;
restore_sigpipe_trap ( ) ;
return true ;
}
/*
* Error reporting for scripts . Errors should look like
* psql : filename : lineno : message
*
*/
void
psql_error ( const char * fmt , . . . )
@ -611,27 +629,23 @@ PrintQueryTuples(const PGresult *results)
/* write output to \g argument, if any */
if ( pset . gfname )
{
/* keep this code in sync with ExecQueryUsingCursor */
FILE * queryFout_copy = pset . queryFout ;
bool queryFoutPipe_copy = pset . queryFoutPipe ;
pset . queryFout = stdout ; /* so it doesn't get closed */
FILE * fout ;
bool is_pipe ;
/* open file/pipe */
if ( ! setQFout ( pset . gfname ) )
{
pset . queryFout = queryFout_copy ;
pset . queryFoutPipe = queryFoutPipe_copy ;
if ( ! openQueryOutputFile ( pset . gfname , & fout , & is_pipe ) )
return false ;
}
printQuery ( results , & my_popt , pset . queryFout , false , pset . logfile ) ;
if ( is_pipe )
disable_sigpipe_trap ( ) ;
/* close file/pipe, restore old setting */
setQFout ( NULL ) ;
printQuery ( results , & my_popt , fout , false , pset . logfile ) ;
pset . queryFout = queryFout_copy ;
pset . queryFoutPipe = queryFoutPipe_copy ;
if ( is_pipe )
{
pclose ( fout ) ;
restore_sigpipe_trap ( ) ;
}
else
fclose ( fout ) ;
}
else
printQuery ( results , & my_popt , pset . queryFout , false , pset . logfile ) ;
@ -1199,10 +1213,10 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
PGresult * results ;
PQExpBufferData buf ;
printQueryOpt my_popt = pset . popt ;
FILE * queryFout_copy = pset . queryFout ;
bool queryFoutPipe_copy = pset . queryFoutPipe ;
FILE * fout ;
bool is_pipe ;
bool is_pager = false ;
bool started_txn = false ;
bool did_pager = false ;
int ntuples ;
int fetch_count ;
char fetch_cmd [ 64 ] ;
@ -1268,21 +1282,22 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
/* prepare to write output to \g argument, if any */
if ( pset . gfname )
{
/* keep this code in sync with PrintQueryTuples */
pset . queryFout = stdout ; /* so it doesn't get closed */
/* open file/pipe */
if ( ! setQFout ( pset . gfname ) )
if ( ! openQueryOutputFile ( pset . gfname , & fout , & is_pipe ) )
{
pset . queryFout = queryFout_copy ;
pset . queryFoutPipe = queryFoutPipe_copy ;
OK = false ;
goto cleanup ;
}
if ( is_pipe )
disable_sigpipe_trap ( ) ;
}
else
{
fout = pset . queryFout ;
is_pipe = false ; /* doesn't matter */
}
/* clear any pre-existing error indication on the output stream */
clearerr ( pset . queryFout ) ;
clearerr ( f out) ;
for ( ; ; )
{
@ -1302,12 +1317,10 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
if ( PQresultStatus ( results ) ! = PGRES_TUPLES_OK )
{
/* shut down pager before printing error message */
if ( did _pager)
if ( is _pager)
{
ClosePager ( pset . queryFout ) ;
pset . queryFout = queryFout_copy ;
pset . queryFoutPipe = queryFoutPipe_copy ;
did_pager = false ;
ClosePager ( fout ) ;
is_pager = false ;
}
OK = AcceptResult ( results ) ;
@ -1331,17 +1344,17 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
/* this is the last result set, so allow footer decoration */
my_popt . topt . stop_table = true ;
}
else if ( pset . queryF out = = stdout & & ! did _pager)
else if ( f out = = stdout & & ! is _pager)
{
/*
* If query requires multiple result sets , hack to ensure that
* only one pager instance is used for the whole mess
*/
pset . queryF out = PageOutput ( INT_MAX , & ( my_popt . topt ) ) ;
did _pager = true ;
f out = PageOutput ( INT_MAX , & ( my_popt . topt ) ) ;
is _pager = true ;
}
printQuery ( results , & my_popt , pset . queryFout , did _pager, pset . logfile ) ;
printQuery ( results , & my_popt , fout , is _pager, pset . logfile ) ;
PQclear ( results ) ;
@ -1355,7 +1368,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
* the pager dies / exits / etc , there ' s no sense throwing more data at
* it .
*/
flush_error = fflush ( pset . queryF out) ;
flush_error = fflush ( f out) ;
/*
* Check if we are at the end , if a cancel was pressed , or if there
@ -1365,24 +1378,25 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
* stop bothering to pull down more data .
*/
if ( ntuples < fetch_count | | cancel_pressed | | flush_error | |
ferror ( pset . queryF out) )
ferror ( f out) )
break ;
}
/* close \g argument file/pipe, restore old setting */
if ( pset . gfname )
{
/* keep this code in sync with PrintQueryTuples */
setQFout ( NULL ) ;
pset . queryFout = queryFout_copy ;
pset . queryFoutPipe = queryFoutPipe_copy ;
/* close \g argument file/pipe */
if ( is_pipe )
{
pclose ( fout ) ;
restore_sigpipe_trap ( ) ;
}
else
fclose ( fout ) ;
}
else if ( did_pager )
else if ( is _pager)
{
ClosePager ( pset . queryFout ) ;
pset . queryFout = queryFout_copy ;
pset . queryFoutPipe = queryFoutPipe_copy ;
/* close transient pager */
ClosePager ( fout ) ;
}
cleanup :