@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $ PostgreSQL : pgsql / src / backend / executor / spi . c , v 1.191 2008 / 03 / 26 18 : 48 : 59 alvherre Exp $
* $ PostgreSQL : pgsql / src / backend / executor / spi . c , v 1.192 2008 / 04 / 01 03 : 09 : 30 tgl Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
@ -35,13 +35,17 @@ static int _SPI_stack_depth = 0; /* allocated size of _SPI_stack */
static int _SPI_connected = - 1 ;
static int _SPI_curid = - 1 ;
static void _SPI_prepare_plan ( const char * src , SPIPlanPtr plan ) ;
static void _SPI_prepare_plan ( const char * src , SPIPlanPtr plan ,
ParamListInfo boundParams ) ;
static int _SPI_execute_plan ( SPIPlanPtr plan ,
Datum * Values , const char * Nulls ,
static int _SPI_execute_plan ( SPIPlanPtr plan , ParamListInfo paramLI ,
Snapshot snapshot , Snapshot crosscheck_snapshot ,
bool read_only , bool fire_triggers , long tcount ) ;
static ParamListInfo _SPI_convert_params ( int nargs , Oid * argtypes ,
Datum * Values , const char * Nulls ,
int pflags ) ;
static int _SPI_pquery ( QueryDesc * queryDesc , bool fire_triggers , long tcount ) ;
static void _SPI_error_callback ( void * arg ) ;
@ -313,9 +317,9 @@ SPI_execute(const char *src, bool read_only, long tcount)
plan . magic = _SPI_PLAN_MAGIC ;
plan . cursor_options = 0 ;
_SPI_prepare_plan ( src , & plan ) ;
_SPI_prepare_plan ( src , & plan , NULL ) ;
res = _SPI_execute_plan ( & plan , NULL , NULL ,
res = _SPI_execute_plan ( & plan , NULL ,
InvalidSnapshot , InvalidSnapshot ,
read_only , true , tcount ) ;
@ -348,7 +352,9 @@ SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
return res ;
res = _SPI_execute_plan ( plan ,
Values , Nulls ,
_SPI_convert_params ( plan - > nargs , plan - > argtypes ,
Values , Nulls ,
0 ) ,
InvalidSnapshot , InvalidSnapshot ,
read_only , true , tcount ) ;
@ -394,7 +400,9 @@ SPI_execute_snapshot(SPIPlanPtr plan,
return res ;
res = _SPI_execute_plan ( plan ,
Values , Nulls ,
_SPI_convert_params ( plan - > nargs , plan - > argtypes ,
Values , Nulls ,
0 ) ,
snapshot , crosscheck_snapshot ,
read_only , fire_triggers , tcount ) ;
@ -402,6 +410,57 @@ SPI_execute_snapshot(SPIPlanPtr plan,
return res ;
}
/*
* SPI_execute_with_args - - plan and execute a query with supplied arguments
*
* This is functionally comparable to SPI_prepare followed by
* SPI_execute_plan , except that since we know the plan will be used only
* once , we can tell the planner to rely on the parameter values as constants .
* This eliminates potential performance disadvantages compared to
* inserting the parameter values directly into the query text .
*/
int
SPI_execute_with_args ( const char * src ,
int nargs , Oid * argtypes ,
Datum * Values , const char * Nulls ,
bool read_only , long tcount )
{
int res ;
_SPI_plan plan ;
ParamListInfo paramLI ;
if ( src = = NULL | | nargs < 0 | | tcount < 0 )
return SPI_ERROR_ARGUMENT ;
if ( nargs > 0 & & ( argtypes = = NULL | | Values = = NULL ) )
return SPI_ERROR_PARAM ;
res = _SPI_begin_call ( true ) ;
if ( res < 0 )
return res ;
memset ( & plan , 0 , sizeof ( _SPI_plan ) ) ;
plan . magic = _SPI_PLAN_MAGIC ;
plan . cursor_options = 0 ;
plan . nargs = nargs ;
plan . argtypes = argtypes ;
paramLI = _SPI_convert_params ( nargs , argtypes ,
Values , Nulls ,
PARAM_FLAG_CONST ) ;
_SPI_prepare_plan ( src , & plan , paramLI ) ;
/* We don't need to copy the plan since it will be thrown away anyway */
res = _SPI_execute_plan ( & plan , paramLI ,
InvalidSnapshot , InvalidSnapshot ,
read_only , true , tcount ) ;
_SPI_end_call ( true ) ;
return res ;
}
SPIPlanPtr
SPI_prepare ( const char * src , int nargs , Oid * argtypes )
{
@ -431,7 +490,7 @@ SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
plan . nargs = nargs ;
plan . argtypes = argtypes ;
_SPI_prepare_plan ( src , & plan ) ;
_SPI_prepare_plan ( src , & plan , NULL ) ;
/* copy plan to procedure context */
result = _SPI_copy_plan ( & plan , _SPI_current - > procCxt ) ;
@ -1054,6 +1113,64 @@ SPI_cursor_open(const char *name, SPIPlanPtr plan,
}
/*
* SPI_cursor_open_with_args ( )
*
* Parse and plan a query and open it as a portal . Like SPI_execute_with_args ,
* we can tell the planner to rely on the parameter values as constants ,
* because the plan will only be used once .
*/
Portal
SPI_cursor_open_with_args ( const char * name ,
const char * src ,
int nargs , Oid * argtypes ,
Datum * Values , const char * Nulls ,
bool read_only , int cursorOptions )
{
Portal result ;
_SPI_plan plan ;
ParamListInfo paramLI ;
if ( src = = NULL | | nargs < 0 )
elog ( ERROR , " SPI_cursor_open_with_args called with invalid arguments " ) ;
if ( nargs > 0 & & ( argtypes = = NULL | | Values = = NULL ) )
elog ( ERROR , " SPI_cursor_open_with_args called with missing parameters " ) ;
SPI_result = _SPI_begin_call ( true ) ;
if ( SPI_result < 0 )
elog ( ERROR , " SPI_cursor_open_with_args called while not connected " ) ;
memset ( & plan , 0 , sizeof ( _SPI_plan ) ) ;
plan . magic = _SPI_PLAN_MAGIC ;
plan . cursor_options = cursorOptions ;
plan . nargs = nargs ;
plan . argtypes = argtypes ;
paramLI = _SPI_convert_params ( nargs , argtypes ,
Values , Nulls ,
PARAM_FLAG_CONST ) ;
_SPI_prepare_plan ( src , & plan , paramLI ) ;
/* We needn't copy the plan; SPI_cursor_open will do so */
/* Adjust stack so that SPI_cursor_open doesn't complain */
_SPI_curid - - ;
/* SPI_cursor_open expects to be called in procedure memory context */
_SPI_procmem ( ) ;
result = SPI_cursor_open ( name , & plan , Values , Nulls , read_only ) ;
/* And clean up */
_SPI_curid + + ;
_SPI_end_call ( true ) ;
return result ;
}
/*
* SPI_cursor_find ( )
*
@ -1376,14 +1493,17 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self)
* Parse and plan a querystring .
*
* At entry , plan - > argtypes , plan - > nargs , and plan - > cursor_options must be
* valid .
* valid . If boundParams isn ' t NULL then it represents parameter values
* that are made available to the planner ( as either estimates or hard values
* depending on their PARAM_FLAG_CONST marking ) . The boundParams had better
* match the param types embedded in the plan !
*
* Results are stored into * plan ( specifically , plan - > plancache_list ) .
* Note however that the result trees are all in CurrentMemoryContext
* and need to be copied somewhere to survive .
*/
static void
_SPI_prepare_plan ( const char * src , SPIPlanPtr plan )
_SPI_prepare_plan ( const char * src , SPIPlanPtr plan , ParamListInfo boundParams )
{
List * raw_parsetree_list ;
List * plancache_list ;
@ -1422,7 +1542,8 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
/* Need a copyObject here to keep parser from modifying raw tree */
stmt_list = pg_analyze_and_rewrite ( copyObject ( parsetree ) ,
src , argtypes , nargs ) ;
stmt_list = pg_plan_queries ( stmt_list , cursor_options , NULL , false ) ;
stmt_list = pg_plan_queries ( stmt_list , cursor_options ,
boundParams , false ) ;
plansource = ( CachedPlanSource * ) palloc0 ( sizeof ( CachedPlanSource ) ) ;
cplan = ( CachedPlan * ) palloc0 ( sizeof ( CachedPlan ) ) ;
@ -1465,7 +1586,7 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
* tcount : execution tuple - count limit , or 0 for none
*/
static int
_SPI_execute_plan ( SPIPlanPtr plan , Datum * Values , const char * Nulls ,
_SPI_execute_plan ( SPIPlanPtr plan , ParamListInfo paramLI ,
Snapshot snapshot , Snapshot crosscheck_snapshot ,
bool read_only , bool fire_triggers , long tcount )
{
@ -1480,34 +1601,9 @@ _SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
saveActiveSnapshot = ActiveSnapshot ;
PG_TRY ( ) ;
{
ListCell * lc1 ;
ErrorContextCallback spierrcontext ;
int nargs = plan - > nargs ;
ParamListInfo paramLI ;
CachedPlan * cplan = NULL ;
/* Convert parameters to form wanted by executor */
if ( nargs > 0 )
{
int k ;
/* sizeof(ParamListInfoData) includes the first array element */
paramLI = ( ParamListInfo ) palloc ( sizeof ( ParamListInfoData ) +
( nargs - 1 ) * sizeof ( ParamExternData ) ) ;
paramLI - > numParams = nargs ;
for ( k = 0 ; k < nargs ; k + + )
{
ParamExternData * prm = & paramLI - > params [ k ] ;
prm - > value = Values [ k ] ;
prm - > isnull = ( Nulls & & Nulls [ k ] = = ' n ' ) ;
prm - > pflags = 0 ;
prm - > ptype = plan - > argtypes [ k ] ;
}
}
else
paramLI = NULL ;
ListCell * lc1 ;
/*
* Setup error traceback support for ereport ( )
@ -1723,6 +1819,40 @@ fail:
return my_res ;
}
/*
* Convert query parameters to form wanted by planner and executor
*/
static ParamListInfo
_SPI_convert_params ( int nargs , Oid * argtypes ,
Datum * Values , const char * Nulls ,
int pflags )
{
ParamListInfo paramLI ;
if ( nargs > 0 )
{
int i ;
/* sizeof(ParamListInfoData) includes the first array element */
paramLI = ( ParamListInfo ) palloc ( sizeof ( ParamListInfoData ) +
( nargs - 1 ) * sizeof ( ParamExternData ) ) ;
paramLI - > numParams = nargs ;
for ( i = 0 ; i < nargs ; i + + )
{
ParamExternData * prm = & paramLI - > params [ i ] ;
prm - > value = Values [ i ] ;
prm - > isnull = ( Nulls & & Nulls [ i ] = = ' n ' ) ;
prm - > pflags = pflags ;
prm - > ptype = argtypes [ i ] ;
}
}
else
paramLI = NULL ;
return paramLI ;
}
static int
_SPI_pquery ( QueryDesc * queryDesc , bool fire_triggers , long tcount )
{