@ -95,8 +95,17 @@
*/
# if defined(EEO_USE_COMPUTED_GOTO)
/* struct for jump target -> opcode lookup table */
typedef struct ExprEvalOpLookup
{
const void * opcode ;
ExprEvalOp op ;
} ExprEvalOpLookup ;
/* to make dispatch_table accessible outside ExecInterpExpr() */
static const void * * dispatch_table = NULL ;
/* jump target -> opcode lookup table */
static ExprEvalOpLookup reverse_dispatch_table [ EEOP_LAST ] ;
# define EEO_SWITCH()
# define EEO_CASE(name) CASE_##name:
@ -137,11 +146,8 @@ static void ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op,
ExprContext * econtext , bool checkisnull ) ;
/* fast-path evaluation functions */
static Datum ExecJustInnerVarFirst ( ExprState * state , ExprContext * econtext , bool * isnull ) ;
static Datum ExecJustInnerVar ( ExprState * state , ExprContext * econtext , bool * isnull ) ;
static Datum ExecJustOuterVarFirst ( ExprState * state , ExprContext * econtext , bool * isnull ) ;
static Datum ExecJustOuterVar ( ExprState * state , ExprContext * econtext , bool * isnull ) ;
static Datum ExecJustScanVarFirst ( ExprState * state , ExprContext * econtext , bool * isnull ) ;
static Datum ExecJustScanVar ( ExprState * state , ExprContext * econtext , bool * isnull ) ;
static Datum ExecJustConst ( ExprState * state , ExprContext * econtext , bool * isnull ) ;
static Datum ExecJustAssignInnerVar ( ExprState * state , ExprContext * econtext , bool * isnull ) ;
@ -171,6 +177,14 @@ ExecReadyInterpretedExpr(ExprState *state)
if ( state - > flags & EEO_FLAG_INTERPRETER_INITIALIZED )
return ;
/*
* First time through , check whether attribute matches Var . Might not be
* ok anymore , due to schema changes . We do that by setting up a callback
* that does checking on the first call , which then sets the evalfunc
* callback to the actual method of execution .
*/
state - > evalfunc = ExecInterpExprStillValid ;
/* DIRECT_THREADED should not already be set */
Assert ( ( state - > flags & EEO_FLAG_DIRECT_THREADED ) = = 0 ) ;
@ -192,53 +206,53 @@ ExecReadyInterpretedExpr(ExprState *state)
ExprEvalOp step1 = state - > steps [ 1 ] . opcode ;
if ( step0 = = EEOP_INNER_FETCHSOME & &
step1 = = EEOP_INNER_VAR_FIRST )
step1 = = EEOP_INNER_VAR )
{
state - > evalfunc = ExecJustInnerVarFirst ;
state - > evalfunc_private = ( void * ) ExecJustInnerVar ;
return ;
}
else if ( step0 = = EEOP_OUTER_FETCHSOME & &
step1 = = EEOP_OUTER_VAR_FIRST )
step1 = = EEOP_OUTER_VAR )
{
state - > evalfunc = ExecJustOuterVarFirst ;
state - > evalfunc_private = ( void * ) ExecJustOuterVar ;
return ;
}
else if ( step0 = = EEOP_SCAN_FETCHSOME & &
step1 = = EEOP_SCAN_VAR_FIRST )
step1 = = EEOP_SCAN_VAR )
{
state - > evalfunc = ExecJustScanVarFirst ;
state - > evalfunc_private = ( void * ) ExecJustScanVar ;
return ;
}
else if ( step0 = = EEOP_INNER_FETCHSOME & &
step1 = = EEOP_ASSIGN_INNER_VAR )
{
state - > evalfunc = ExecJustAssignInnerVar ;
state - > evalfunc_private = ( void * ) ExecJustAssignInnerVar ;
return ;
}
else if ( step0 = = EEOP_OUTER_FETCHSOME & &
step1 = = EEOP_ASSIGN_OUTER_VAR )
{
state - > evalfunc = ExecJustAssignOuterVar ;
state - > evalfunc_private = ( void * ) ExecJustAssignOuterVar ;
return ;
}
else if ( step0 = = EEOP_SCAN_FETCHSOME & &
step1 = = EEOP_ASSIGN_SCAN_VAR )
{
state - > evalfunc = ExecJustAssignScanVar ;
state - > evalfunc_private = ( void * ) ExecJustAssignScanVar ;
return ;
}
else if ( step0 = = EEOP_CASE_TESTVAL & &
step1 = = EEOP_FUNCEXPR_STRICT & &
state - > steps [ 0 ] . d . casetest . value )
{
state - > evalfunc = ExecJustApplyFuncToCase ;
state - > evalfunc_private = ( void * ) ExecJustApplyFuncToCase ;
return ;
}
}
else if ( state - > steps_len = = 2 & &
state - > steps [ 0 ] . opcode = = EEOP_CONST )
{
state - > evalfunc = ExecJustConst ;
state - > evalfunc_private = ( void * ) ExecJustConst ;
return ;
}
@ -262,7 +276,7 @@ ExecReadyInterpretedExpr(ExprState *state)
}
# endif /* EEO_USE_COMPUTED_GOTO */
state - > evalfunc = ExecInterpExpr ;
state - > evalfunc_private = ( void * ) ExecInterpExpr ;
}
@ -293,11 +307,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
& & CASE_EEOP_INNER_FETCHSOME ,
& & CASE_EEOP_OUTER_FETCHSOME ,
& & CASE_EEOP_SCAN_FETCHSOME ,
& & CASE_EEOP_INNER_VAR_FIRST ,
& & CASE_EEOP_INNER_VAR ,
& & CASE_EEOP_OUTER_VAR_FIRST ,
& & CASE_EEOP_OUTER_VAR ,
& & CASE_EEOP_SCAN_VAR_FIRST ,
& & CASE_EEOP_SCAN_VAR ,
& & CASE_EEOP_INNER_SYSVAR ,
& & CASE_EEOP_OUTER_SYSVAR ,
@ -420,22 +431,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
EEO_NEXT ( ) ;
}
EEO_CASE ( EEOP_INNER_VAR_FIRST )
{
int attnum = op - > d . var . attnum ;
/*
* First time through , check whether attribute matches Var . Might
* not be ok anymore , due to schema changes .
*/
CheckVarSlotCompatibility ( innerslot , attnum + 1 , op - > d . var . vartype ) ;
/* Skip that check on subsequent evaluations */
op - > opcode = EEO_OPCODE ( EEOP_INNER_VAR ) ;
/* FALL THROUGH to EEOP_INNER_VAR */
}
EEO_CASE ( EEOP_INNER_VAR )
{
int attnum = op - > d . var . attnum ;
@ -453,18 +448,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
EEO_NEXT ( ) ;
}
EEO_CASE ( EEOP_OUTER_VAR_FIRST )
{
int attnum = op - > d . var . attnum ;
/* See EEOP_INNER_VAR_FIRST comments */
CheckVarSlotCompatibility ( outerslot , attnum + 1 , op - > d . var . vartype ) ;
op - > opcode = EEO_OPCODE ( EEOP_OUTER_VAR ) ;
/* FALL THROUGH to EEOP_OUTER_VAR */
}
EEO_CASE ( EEOP_OUTER_VAR )
{
int attnum = op - > d . var . attnum ;
@ -478,18 +461,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
EEO_NEXT ( ) ;
}
EEO_CASE ( EEOP_SCAN_VAR_FIRST )
{
int attnum = op - > d . var . attnum ;
/* See EEOP_INNER_VAR_FIRST comments */
CheckVarSlotCompatibility ( scanslot , attnum + 1 , op - > d . var . vartype ) ;
op - > opcode = EEO_OPCODE ( EEOP_SCAN_VAR ) ;
/* FALL THROUGH to EEOP_SCAN_VAR */
}
EEO_CASE ( EEOP_SCAN_VAR )
{
int attnum = op - > d . var . attnum ;
@ -1556,6 +1527,78 @@ out:
return state - > resvalue ;
}
/*
* Expression evaluation callback that performs extra checks before executing
* the expression . Declared extern so other methods of execution can use it
* too .
*/
Datum
ExecInterpExprStillValid ( ExprState * state , ExprContext * econtext , bool * isNull )
{
/*
* First time through , check whether attribute matches Var . Might
* not be ok anymore , due to schema changes .
*/
CheckExprStillValid ( state , econtext ) ;
/* skip the check during further executions */
state - > evalfunc = ( ExprStateEvalFunc ) state - > evalfunc_private ;
/* and actually execute */
return state - > evalfunc ( state , econtext , isNull ) ;
}
/*
* Check that an expression is still valid in the face of potential schema
* changes since the plan has been created .
*/
void
CheckExprStillValid ( ExprState * state , ExprContext * econtext )
{
int i = 0 ;
TupleTableSlot * innerslot ;
TupleTableSlot * outerslot ;
TupleTableSlot * scanslot ;
innerslot = econtext - > ecxt_innertuple ;
outerslot = econtext - > ecxt_outertuple ;
scanslot = econtext - > ecxt_scantuple ;
for ( i = 0 ; i < state - > steps_len ; i + + )
{
ExprEvalStep * op = & state - > steps [ i ] ;
switch ( ExecEvalStepOp ( state , op ) )
{
case EEOP_INNER_VAR :
{
int attnum = op - > d . var . attnum ;
CheckVarSlotCompatibility ( innerslot , attnum + 1 , op - > d . var . vartype ) ;
break ;
}
case EEOP_OUTER_VAR :
{
int attnum = op - > d . var . attnum ;
CheckVarSlotCompatibility ( outerslot , attnum + 1 , op - > d . var . vartype ) ;
break ;
}
case EEOP_SCAN_VAR :
{
int attnum = op - > d . var . attnum ;
CheckVarSlotCompatibility ( scanslot , attnum + 1 , op - > d . var . vartype ) ;
break ;
}
default :
break ;
}
}
}
/*
* Check whether a user attribute in a slot can be referenced by a Var
* expression . This should succeed unless there have been schema changes
@ -1668,20 +1711,14 @@ ShutdownTupleDescRef(Datum arg)
* Fast - path functions , for very simple expressions
*/
/* Simple reference to inner Var, first time through */
/* Simple reference to inner Var */
static Datum
ExecJustInnerVarFirst ( ExprState * state , ExprContext * econtext , bool * isnull )
ExecJustInnerVar ( ExprState * state , ExprContext * econtext , bool * isnull )
{
ExprEvalStep * op = & state - > steps [ 1 ] ;
int attnum = op - > d . var . attnum + 1 ;
TupleTableSlot * slot = econtext - > ecxt_innertuple ;
/* See ExecInterpExpr()'s comments for EEOP_INNER_VAR_FIRST */
CheckVarSlotCompatibility ( slot , attnum , op - > d . var . vartype ) ;
op - > opcode = EEOP_INNER_VAR ; /* just for cleanliness */
state - > evalfunc = ExecJustInnerVar ;
/*
* Since we use slot_getattr ( ) , we don ' t need to implement the FETCHSOME
* step explicitly , and we also needn ' t Assert that the attnum is in range
@ -1690,34 +1727,6 @@ ExecJustInnerVarFirst(ExprState *state, ExprContext *econtext, bool *isnull)
return slot_getattr ( slot , attnum , isnull ) ;
}
/* Simple reference to inner Var */
static Datum
ExecJustInnerVar ( ExprState * state , ExprContext * econtext , bool * isnull )
{
ExprEvalStep * op = & state - > steps [ 1 ] ;
int attnum = op - > d . var . attnum + 1 ;
TupleTableSlot * slot = econtext - > ecxt_innertuple ;
/* See comments in ExecJustInnerVarFirst */
return slot_getattr ( slot , attnum , isnull ) ;
}
/* Simple reference to outer Var, first time through */
static Datum
ExecJustOuterVarFirst ( ExprState * state , ExprContext * econtext , bool * isnull )
{
ExprEvalStep * op = & state - > steps [ 1 ] ;
int attnum = op - > d . var . attnum + 1 ;
TupleTableSlot * slot = econtext - > ecxt_outertuple ;
CheckVarSlotCompatibility ( slot , attnum , op - > d . var . vartype ) ;
op - > opcode = EEOP_OUTER_VAR ; /* just for cleanliness */
state - > evalfunc = ExecJustOuterVar ;
/* See comments in ExecJustInnerVarFirst */
return slot_getattr ( slot , attnum , isnull ) ;
}
/* Simple reference to outer Var */
static Datum
ExecJustOuterVar ( ExprState * state , ExprContext * econtext , bool * isnull )
@ -1726,23 +1735,7 @@ ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
int attnum = op - > d . var . attnum + 1 ;
TupleTableSlot * slot = econtext - > ecxt_outertuple ;
/* See comments in ExecJustInnerVarFirst */
return slot_getattr ( slot , attnum , isnull ) ;
}
/* Simple reference to scan Var, first time through */
static Datum
ExecJustScanVarFirst ( ExprState * state , ExprContext * econtext , bool * isnull )
{
ExprEvalStep * op = & state - > steps [ 1 ] ;
int attnum = op - > d . var . attnum + 1 ;
TupleTableSlot * slot = econtext - > ecxt_scantuple ;
CheckVarSlotCompatibility ( slot , attnum , op - > d . var . vartype ) ;
op - > opcode = EEOP_SCAN_VAR ; /* just for cleanliness */
state - > evalfunc = ExecJustScanVar ;
/* See comments in ExecJustInnerVarFirst */
/* See comments in ExecJustInnerVar */
return slot_getattr ( slot , attnum , isnull ) ;
}
@ -1754,7 +1747,7 @@ ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
int attnum = op - > d . var . attnum + 1 ;
TupleTableSlot * slot = econtext - > ecxt_scantuple ;
/* See comments in ExecJustInnerVarFirst */
/* See comments in ExecJustInnerVar */
return slot_getattr ( slot , attnum , isnull ) ;
}
@ -1860,6 +1853,24 @@ ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull)
return d ;
}
# if defined(EEO_USE_COMPUTED_GOTO)
/*
* Comparator used when building address - > opcode lookup table for
* ExecEvalStepOp ( ) in the threaded dispatch case .
*/
static int
dispatch_compare_ptr ( const void * a , const void * b )
{
const ExprEvalOpLookup * la = ( const ExprEvalOpLookup * ) a ;
const ExprEvalOpLookup * lb = ( const ExprEvalOpLookup * ) b ;
if ( la - > opcode < lb - > opcode )
return - 1 ;
else if ( la - > opcode > lb - > opcode )
return 1 ;
return 0 ;
}
# endif
/*
* Do one - time initialization of interpretation machinery .
@ -1870,8 +1881,25 @@ ExecInitInterpreter(void)
# if defined(EEO_USE_COMPUTED_GOTO)
/* Set up externally-visible pointer to dispatch table */
if ( dispatch_table = = NULL )
{
int i ;
dispatch_table = ( const void * * )
DatumGetPointer ( ExecInterpExpr ( NULL , NULL , NULL ) ) ;
/* build reverse lookup table */
for ( i = 0 ; i < EEOP_LAST ; i + + )
{
reverse_dispatch_table [ i ] . opcode = dispatch_table [ i ] ;
reverse_dispatch_table [ i ] . op = ( ExprEvalOp ) i ;
}
/* make it bsearch()able */
qsort ( reverse_dispatch_table ,
EEOP_LAST /* nmembers */ ,
sizeof ( ExprEvalOpLookup ) ,
dispatch_compare_ptr ) ;
}
# endif
}
@ -1880,10 +1908,6 @@ ExecInitInterpreter(void)
*
* When direct - threading is in use , ExprState - > opcode isn ' t easily
* decipherable . This function returns the appropriate enum member .
*
* This currently is only supposed to be used in paths that aren ' t critical
* performance - wise . If that changes , we could add an inverse dispatch_table
* that ' s sorted on the address , so a binary search can be performed .
*/
ExprEvalOp
ExecEvalStepOp ( ExprState * state , ExprEvalStep * op )
@ -1891,16 +1915,17 @@ ExecEvalStepOp(ExprState *state, ExprEvalStep *op)
# if defined(EEO_USE_COMPUTED_GOTO)
if ( state - > flags & EEO_FLAG_DIRECT_THREADED )
{
int i ;
for ( i = 0 ; i < EEOP_LAST ; i + + )
{
if ( ( void * ) op - > opcode = = dispatch_table [ i ] )
{
return ( ExprEvalOp ) i ;
}
}
elog ( ERROR , " unknown opcode " ) ;
ExprEvalOpLookup key ;
ExprEvalOpLookup * res ;
key . opcode = ( void * ) op - > opcode ;
res = bsearch ( & key ,
reverse_dispatch_table ,
EEOP_LAST /* nmembers */ ,
sizeof ( ExprEvalOpLookup ) ,
dispatch_compare_ptr ) ;
Assert ( res ) ; /* unknown ops shouldn't get looked up */
return res - > op ;
}
# endif
return ( ExprEvalOp ) op - > opcode ;