@ -16,6 +16,7 @@
# include <ctype.h>
# include <ctype.h>
# include <fcntl.h>
# include <fcntl.h>
# include <limits.h>
# include "libpq-fe.h"
# include "libpq-fe.h"
# include "libpq-int.h"
# include "libpq-int.h"
@ -51,7 +52,8 @@ static bool static_std_strings = false;
static PGEvent * dupEvents ( PGEvent * events , int count ) ;
static PGEvent * dupEvents ( PGEvent * events , int count ) ;
static bool pqAddTuple ( PGresult * res , PGresAttValue * tup ) ;
static bool pqAddTuple ( PGresult * res , PGresAttValue * tup ,
const char * * errmsgp ) ;
static bool PQsendQueryStart ( PGconn * conn ) ;
static bool PQsendQueryStart ( PGconn * conn ) ;
static int PQsendQueryGuts ( PGconn * conn ,
static int PQsendQueryGuts ( PGconn * conn ,
const char * command ,
const char * command ,
@ -416,18 +418,26 @@ dupEvents(PGEvent *events, int count)
* equal to PQntuples ( res ) . If it is equal , a new tuple is created and
* equal to PQntuples ( res ) . If it is equal , a new tuple is created and
* added to the result .
* added to the result .
* Returns a non - zero value for success and zero for failure .
* Returns a non - zero value for success and zero for failure .
* ( On failure , we report the specific problem via pqInternalNotice . )
*/
*/
int
int
PQsetvalue ( PGresult * res , int tup_num , int field_num , char * value , int len )
PQsetvalue ( PGresult * res , int tup_num , int field_num , char * value , int len )
{
{
PGresAttValue * attval ;
PGresAttValue * attval ;
const char * errmsg = NULL ;
/* Note that this check also protects us against null "res" */
if ( ! check_field_number ( res , field_num ) )
if ( ! check_field_number ( res , field_num ) )
return FALSE ;
return FALSE ;
/* Invalid tup_num, must be <= ntups */
/* Invalid tup_num, must be <= ntups */
if ( tup_num < 0 | | tup_num > res - > ntups )
if ( tup_num < 0 | | tup_num > res - > ntups )
{
pqInternalNotice ( & res - > noticeHooks ,
" row number %d is out of range 0..%d " ,
tup_num , res - > ntups ) ;
return FALSE ;
return FALSE ;
}
/* need to allocate a new tuple? */
/* need to allocate a new tuple? */
if ( tup_num = = res - > ntups )
if ( tup_num = = res - > ntups )
@ -440,7 +450,7 @@ PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len)
TRUE ) ;
TRUE ) ;
if ( ! tup )
if ( ! tup )
return FALSE ;
goto fail ;
/* initialize each column to NULL */
/* initialize each column to NULL */
for ( i = 0 ; i < res - > numAttributes ; i + + )
for ( i = 0 ; i < res - > numAttributes ; i + + )
@ -450,8 +460,8 @@ PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len)
}
}
/* add it to the array */
/* add it to the array */
if ( ! pqAddTuple ( res , tup ) )
if ( ! pqAddTuple ( res , tup , & errmsg ) )
return FALSE ;
goto fail ;
}
}
attval = & res - > tuples [ tup_num ] [ field_num ] ;
attval = & res - > tuples [ tup_num ] [ field_num ] ;
@ -471,13 +481,24 @@ PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len)
{
{
attval - > value = ( char * ) pqResultAlloc ( res , len + 1 , TRUE ) ;
attval - > value = ( char * ) pqResultAlloc ( res , len + 1 , TRUE ) ;
if ( ! attval - > value )
if ( ! attval - > value )
return FALSE ;
goto fail ;
attval - > len = len ;
attval - > len = len ;
memcpy ( attval - > value , value , len ) ;
memcpy ( attval - > value , value , len ) ;
attval - > value [ len ] = ' \0 ' ;
attval - > value [ len ] = ' \0 ' ;
}
}
return TRUE ;
return TRUE ;
/*
* Report failure via pqInternalNotice . If preceding code didn ' t provide
* an error message , assume " out of memory " was meant .
*/
fail :
if ( ! errmsg )
errmsg = libpq_gettext ( " out of memory " ) ;
pqInternalNotice ( & res - > noticeHooks , " %s " , errmsg ) ;
return FALSE ;
}
}
/*
/*
@ -847,10 +868,13 @@ pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...)
/*
/*
* pqAddTuple
* pqAddTuple
* add a row pointer to the PGresult structure , growing it if necessary
* add a row pointer to the PGresult structure , growing it if necessary
* Returns TRUE if OK , FALSE if not enough memory to add the row
* Returns TRUE if OK , FALSE if an error prevented adding the row
*
* On error , * errmsgp can be set to an error string to be returned .
* If it is left NULL , the error is presumed to be " out of memory " .
*/
*/
static bool
static bool
pqAddTuple ( PGresult * res , PGresAttValue * tup )
pqAddTuple ( PGresult * res , PGresAttValue * tup , const char * * errmsgp )
{
{
if ( res - > ntups > = res - > tupArrSize )
if ( res - > ntups > = res - > tupArrSize )
{
{
@ -865,9 +889,36 @@ pqAddTuple(PGresult *res, PGresAttValue *tup)
* existing allocation . Note that the positions beyond res - > ntups are
* existing allocation . Note that the positions beyond res - > ntups are
* garbage , not necessarily NULL .
* garbage , not necessarily NULL .
*/
*/
int newSize = ( res - > tupArrSize > 0 ) ? res - > tupArrSize * 2 : 128 ;
int newSize ;
PGresAttValue * * newTuples ;
PGresAttValue * * newTuples ;
/*
* Since we use integers for row numbers , we can ' t support more than
* INT_MAX rows . Make sure we allow that many , though .
*/
if ( res - > tupArrSize < = INT_MAX / 2 )
newSize = ( res - > tupArrSize > 0 ) ? res - > tupArrSize * 2 : 128 ;
else if ( res - > tupArrSize < INT_MAX )
newSize = INT_MAX ;
else
{
* errmsgp = libpq_gettext ( " PGresult cannot support more than INT_MAX tuples " ) ;
return FALSE ;
}
/*
* Also , on 32 - bit platforms we could , in theory , overflow size_t even
* before newSize gets to INT_MAX . ( In practice we ' d doubtless hit
* OOM long before that , but let ' s check . )
*/
# if INT_MAX >= (SIZE_MAX / 2)
if ( newSize > SIZE_MAX / sizeof ( PGresAttValue * ) )
{
* errmsgp = libpq_gettext ( " size_t overflow " ) ;
return FALSE ;
}
# endif
if ( res - > tuples = = NULL )
if ( res - > tuples = = NULL )
newTuples = ( PGresAttValue * * )
newTuples = ( PGresAttValue * * )
malloc ( newSize * sizeof ( PGresAttValue * ) ) ;
malloc ( newSize * sizeof ( PGresAttValue * ) ) ;
@ -1093,7 +1144,7 @@ pqRowProcessor(PGconn *conn, const char **errmsgp)
}
}
/* And add the tuple to the PGresult's tuple array */
/* And add the tuple to the PGresult's tuple array */
if ( ! pqAddTuple ( res , tup ) )
if ( ! pqAddTuple ( res , tup , errmsgp ) )
goto fail ;
goto fail ;
/*
/*