PostgreSQL Source Code  git master
execExpr.c File Reference
#include "postgres.h"
#include "access/nbtree.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_type.h"
#include "executor/execExpr.h"
#include "executor/nodeSubplan.h"
#include "funcapi.h"
#include "jit/jit.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/subscripting.h"
#include "optimizer/optimizer.h"
#include "pgstat.h"
#include "utils/acl.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/typcache.h"
Include dependency graph for execExpr.c:

Go to the source code of this file.

Data Structures

struct  LastAttnumInfo
 

Typedefs

typedef struct LastAttnumInfo LastAttnumInfo
 

Functions

static void ExecReadyExpr (ExprState *state)
 
static void ExecInitExprRec (Expr *node, ExprState *state, Datum *resv, bool *resnull)
 
static void ExecInitFunc (ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, Oid inputcollid, ExprState *state)
 
static void ExecInitExprSlots (ExprState *state, Node *node)
 
static void ExecPushExprSlots (ExprState *state, LastAttnumInfo *info)
 
static bool get_last_attnums_walker (Node *node, LastAttnumInfo *info)
 
static bool ExecComputeSlotInfo (ExprState *state, ExprEvalStep *op)
 
static void ExecInitWholeRowVar (ExprEvalStep *scratch, Var *variable, ExprState *state)
 
static void ExecInitSubscriptingRef (ExprEvalStep *scratch, SubscriptingRef *sbsref, ExprState *state, Datum *resv, bool *resnull)
 
static bool isAssignmentIndirectionExpr (Expr *expr)
 
static void ExecInitCoerceToDomain (ExprEvalStep *scratch, CoerceToDomain *ctest, ExprState *state, Datum *resv, bool *resnull)
 
static void ExecBuildAggTransCall (ExprState *state, AggState *aggstate, ExprEvalStep *scratch, FunctionCallInfo fcinfo, AggStatePerTrans pertrans, int transno, int setno, int setoff, bool ishash, bool nullcheck)
 
ExprStateExecInitExpr (Expr *node, PlanState *parent)
 
ExprStateExecInitExprWithParams (Expr *node, ParamListInfo ext_params)
 
ExprStateExecInitQual (List *qual, PlanState *parent)
 
ExprStateExecInitCheck (List *qual, PlanState *parent)
 
ListExecInitExprList (List *nodes, PlanState *parent)
 
ProjectionInfoExecBuildProjectionInfo (List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
 
ProjectionInfoExecBuildUpdateProjection (List *targetList, bool evalTargetList, List *targetColnos, TupleDesc relDesc, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent)
 
ExprStateExecPrepareExpr (Expr *node, EState *estate)
 
ExprStateExecPrepareQual (List *qual, EState *estate)
 
ExprStateExecPrepareCheck (List *qual, EState *estate)
 
ListExecPrepareExprList (List *nodes, EState *estate)
 
bool ExecCheck (ExprState *state, ExprContext *econtext)
 
void ExprEvalPushStep (ExprState *es, const ExprEvalStep *s)
 
ExprStateExecBuildAggTrans (AggState *aggstate, AggStatePerPhase phase, bool doSort, bool doHash, bool nullcheck)
 
ExprStateExecBuildGroupingEqual (TupleDesc ldesc, TupleDesc rdesc, const TupleTableSlotOps *lops, const TupleTableSlotOps *rops, int numCols, const AttrNumber *keyColIdx, const Oid *eqfunctions, const Oid *collations, PlanState *parent)
 
ExprStateExecBuildParamSetEqual (TupleDesc desc, const TupleTableSlotOps *lops, const TupleTableSlotOps *rops, const Oid *eqfunctions, const Oid *collations, const List *param_exprs, PlanState *parent)
 

Typedef Documentation

◆ LastAttnumInfo

Function Documentation

◆ ExecBuildAggTrans()

ExprState* ExecBuildAggTrans ( AggState aggstate,
AggStatePerPhase  phase,
bool  doSort,
bool  doHash,
bool  nullcheck 
)

Definition at line 3290 of file execExpr.c.

References ExprEvalStep::agg_deserialize, AGG_HASHED, ExprEvalStep::agg_strict_input_check, Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggorder, AggStatePerTransData::aggref, AggState::aggsplit, AggState::aggstrategy, arg, FunctionCallInfoBaseData::args, Aggref::args, Assert, ExprEvalStep::d, AggStatePerTransData::deserialfn, AggStatePerTransData::deserialfn_fcinfo, AggStatePerTransData::deserialfn_oid, DO_AGGSPLIT_COMBINE, EEOP_AGG_DESERIALIZE, EEOP_AGG_STRICT_DESERIALIZE, EEOP_AGG_STRICT_INPUT_CHECK_ARGS, EEOP_AGG_STRICT_INPUT_CHECK_NULLS, EEOP_DONE, EEOP_JUMP_IF_NOT_TRUE, ExecBuildAggTransCall(), ExecInitExprRec(), ExecPushExprSlots(), ExecReadyExpr(), ExprState::expr, TargetEntry::expr, ExprEvalPushStep(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_strict, get_last_attnums_walker(), NullableDatum::isnull, ExprEvalStep::jump, lappend_int(), lfirst, lfirst_int, linitial, list_length(), makeNode, Max, AggState::maxsets, NIL, AggState::num_hashes, AggStatePerTransData::numInputs, AggStatePerPhaseData::numsets, AggStatePerTransData::numSortCols, AggState::numtrans, AggStatePerTransData::numTransInputs, OidIsValid, ExprEvalStep::opcode, ExprState::parent, AggState::pertrans, PointerGetDatum, ScanState::ps, ExprState::resnull, ExprEvalStep::resnull, ExprState::resvalue, ExprEvalStep::resvalue, AggStatePerTransData::sortslot, AggState::ss, ExprState::steps, ExprState::steps_len, AggStatePerTransData::transfn_fcinfo, TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, NullableDatum::value, and values.

Referenced by ExecInitAgg(), and hashagg_recompile_expressions().

3292 {
3294  PlanState *parent = &aggstate->ss.ps;
3295  ExprEvalStep scratch = {0};
3296  bool isCombine = DO_AGGSPLIT_COMBINE(aggstate->aggsplit);
3297  LastAttnumInfo deform = {0, 0, 0};
3298 
3299  state->expr = (Expr *) aggstate;
3300  state->parent = parent;
3301 
3302  scratch.resvalue = &state->resvalue;
3303  scratch.resnull = &state->resnull;
3304 
3305  /*
3306  * First figure out which slots, and how many columns from each, we're
3307  * going to need.
3308  */
3309  for (int transno = 0; transno < aggstate->numtrans; transno++)
3310  {
3311  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3312 
3314  &deform);
3315  get_last_attnums_walker((Node *) pertrans->aggref->args,
3316  &deform);
3318  &deform);
3320  &deform);
3322  &deform);
3323  }
3324  ExecPushExprSlots(state, &deform);
3325 
3326  /*
3327  * Emit instructions for each transition value / grouping set combination.
3328  */
3329  for (int transno = 0; transno < aggstate->numtrans; transno++)
3330  {
3331  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3332  FunctionCallInfo trans_fcinfo = pertrans->transfn_fcinfo;
3333  List *adjust_bailout = NIL;
3334  NullableDatum *strictargs = NULL;
3335  bool *strictnulls = NULL;
3336  int argno;
3337  ListCell *bail;
3338 
3339  /*
3340  * If filter present, emit. Do so before evaluating the input, to
3341  * avoid potentially unneeded computations, or even worse, unintended
3342  * side-effects. When combining, all the necessary filtering has
3343  * already been done.
3344  */
3345  if (pertrans->aggref->aggfilter && !isCombine)
3346  {
3347  /* evaluate filter expression */
3348  ExecInitExprRec(pertrans->aggref->aggfilter, state,
3349  &state->resvalue, &state->resnull);
3350  /* and jump out if false */
3351  scratch.opcode = EEOP_JUMP_IF_NOT_TRUE;
3352  scratch.d.jump.jumpdone = -1; /* adjust later */
3353  ExprEvalPushStep(state, &scratch);
3354  adjust_bailout = lappend_int(adjust_bailout,
3355  state->steps_len - 1);
3356  }
3357 
3358  /*
3359  * Evaluate arguments to aggregate/combine function.
3360  */
3361  argno = 0;
3362  if (isCombine)
3363  {
3364  /*
3365  * Combining two aggregate transition values. Instead of directly
3366  * coming from a tuple the input is a, potentially deserialized,
3367  * transition value.
3368  */
3369  TargetEntry *source_tle;
3370 
3371  Assert(pertrans->numSortCols == 0);
3372  Assert(list_length(pertrans->aggref->args) == 1);
3373 
3374  strictargs = trans_fcinfo->args + 1;
3375  source_tle = (TargetEntry *) linitial(pertrans->aggref->args);
3376 
3377  /*
3378  * deserialfn_oid will be set if we must deserialize the input
3379  * state before calling the combine function.
3380  */
3381  if (!OidIsValid(pertrans->deserialfn_oid))
3382  {
3383  /*
3384  * Start from 1, since the 0th arg will be the transition
3385  * value
3386  */
3387  ExecInitExprRec(source_tle->expr, state,
3388  &trans_fcinfo->args[argno + 1].value,
3389  &trans_fcinfo->args[argno + 1].isnull);
3390  }
3391  else
3392  {
3393  FunctionCallInfo ds_fcinfo = pertrans->deserialfn_fcinfo;
3394 
3395  /* evaluate argument */
3396  ExecInitExprRec(source_tle->expr, state,
3397  &ds_fcinfo->args[0].value,
3398  &ds_fcinfo->args[0].isnull);
3399 
3400  /* Dummy second argument for type-safety reasons */
3401  ds_fcinfo->args[1].value = PointerGetDatum(NULL);
3402  ds_fcinfo->args[1].isnull = false;
3403 
3404  /*
3405  * Don't call a strict deserialization function with NULL
3406  * input
3407  */
3408  if (pertrans->deserialfn.fn_strict)
3410  else
3411  scratch.opcode = EEOP_AGG_DESERIALIZE;
3412 
3413  scratch.d.agg_deserialize.fcinfo_data = ds_fcinfo;
3414  scratch.d.agg_deserialize.jumpnull = -1; /* adjust later */
3415  scratch.resvalue = &trans_fcinfo->args[argno + 1].value;
3416  scratch.resnull = &trans_fcinfo->args[argno + 1].isnull;
3417 
3418  ExprEvalPushStep(state, &scratch);
3419  /* don't add an adjustment unless the function is strict */
3420  if (pertrans->deserialfn.fn_strict)
3421  adjust_bailout = lappend_int(adjust_bailout,
3422  state->steps_len - 1);
3423 
3424  /* restore normal settings of scratch fields */
3425  scratch.resvalue = &state->resvalue;
3426  scratch.resnull = &state->resnull;
3427  }
3428  argno++;
3429  }
3430  else if (pertrans->numSortCols == 0)
3431  {
3432  ListCell *arg;
3433 
3434  /*
3435  * Normal transition function without ORDER BY / DISTINCT.
3436  */
3437  strictargs = trans_fcinfo->args + 1;
3438 
3439  foreach(arg, pertrans->aggref->args)
3440  {
3441  TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3442 
3443  /*
3444  * Start from 1, since the 0th arg will be the transition
3445  * value
3446  */
3447  ExecInitExprRec(source_tle->expr, state,
3448  &trans_fcinfo->args[argno + 1].value,
3449  &trans_fcinfo->args[argno + 1].isnull);
3450  argno++;
3451  }
3452  }
3453  else if (pertrans->numInputs == 1)
3454  {
3455  /*
3456  * DISTINCT and/or ORDER BY case, with a single column sorted on.
3457  */
3458  TargetEntry *source_tle =
3459  (TargetEntry *) linitial(pertrans->aggref->args);
3460 
3461  Assert(list_length(pertrans->aggref->args) == 1);
3462 
3463  ExecInitExprRec(source_tle->expr, state,
3464  &state->resvalue,
3465  &state->resnull);
3466  strictnulls = &state->resnull;
3467  argno++;
3468  }
3469  else
3470  {
3471  /*
3472  * DISTINCT and/or ORDER BY case, with multiple columns sorted on.
3473  */
3474  Datum *values = pertrans->sortslot->tts_values;
3475  bool *nulls = pertrans->sortslot->tts_isnull;
3476  ListCell *arg;
3477 
3478  strictnulls = nulls;
3479 
3480  foreach(arg, pertrans->aggref->args)
3481  {
3482  TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3483 
3484  ExecInitExprRec(source_tle->expr, state,
3485  &values[argno], &nulls[argno]);
3486  argno++;
3487  }
3488  }
3489  Assert(pertrans->numInputs == argno);
3490 
3491  /*
3492  * For a strict transfn, nothing happens when there's a NULL input; we
3493  * just keep the prior transValue. This is true for both plain and
3494  * sorted/distinct aggregates.
3495  */
3496  if (trans_fcinfo->flinfo->fn_strict && pertrans->numTransInputs > 0)
3497  {
3498  if (strictnulls)
3500  else
3502  scratch.d.agg_strict_input_check.nulls = strictnulls;
3503  scratch.d.agg_strict_input_check.args = strictargs;
3504  scratch.d.agg_strict_input_check.jumpnull = -1; /* adjust later */
3505  scratch.d.agg_strict_input_check.nargs = pertrans->numTransInputs;
3506  ExprEvalPushStep(state, &scratch);
3507  adjust_bailout = lappend_int(adjust_bailout,
3508  state->steps_len - 1);
3509  }
3510 
3511  /*
3512  * Call transition function (once for each concurrently evaluated
3513  * grouping set). Do so for both sort and hash based computations, as
3514  * applicable.
3515  */
3516  if (doSort)
3517  {
3518  int processGroupingSets = Max(phase->numsets, 1);
3519  int setoff = 0;
3520 
3521  for (int setno = 0; setno < processGroupingSets; setno++)
3522  {
3523  ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3524  pertrans, transno, setno, setoff, false,
3525  nullcheck);
3526  setoff++;
3527  }
3528  }
3529 
3530  if (doHash)
3531  {
3532  int numHashes = aggstate->num_hashes;
3533  int setoff;
3534 
3535  /* in MIXED mode, there'll be preceding transition values */
3536  if (aggstate->aggstrategy != AGG_HASHED)
3537  setoff = aggstate->maxsets;
3538  else
3539  setoff = 0;
3540 
3541  for (int setno = 0; setno < numHashes; setno++)
3542  {
3543  ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3544  pertrans, transno, setno, setoff, true,
3545  nullcheck);
3546  setoff++;
3547  }
3548  }
3549 
3550  /* adjust early bail out jump target(s) */
3551  foreach(bail, adjust_bailout)
3552  {
3553  ExprEvalStep *as = &state->steps[lfirst_int(bail)];
3554 
3555  if (as->opcode == EEOP_JUMP_IF_NOT_TRUE)
3556  {
3557  Assert(as->d.jump.jumpdone == -1);
3558  as->d.jump.jumpdone = state->steps_len;
3559  }
3560  else if (as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_ARGS ||
3562  {
3563  Assert(as->d.agg_strict_input_check.jumpnull == -1);
3564  as->d.agg_strict_input_check.jumpnull = state->steps_len;
3565  }
3566  else if (as->opcode == EEOP_AGG_STRICT_DESERIALIZE)
3567  {
3568  Assert(as->d.agg_deserialize.jumpnull == -1);
3569  as->d.agg_deserialize.jumpnull = state->steps_len;
3570  }
3571  else
3572  Assert(false);
3573  }
3574  }
3575 
3576  scratch.resvalue = NULL;
3577  scratch.resnull = NULL;
3578  scratch.opcode = EEOP_DONE;
3579  ExprEvalPushStep(state, &scratch);
3580 
3581  ExecReadyExpr(state);
3582 
3583  return state;
3584 }
List * aggdistinct
Definition: primnodes.h:332
#define NIL
Definition: pg_list.h:65
struct PlanState * parent
Definition: execnodes.h:109
Datum * resvalue
Definition: execExpr.h:273
#define PointerGetDatum(X)
Definition: postgres.h:600
struct ExprEvalStep * steps
Definition: execnodes.h:86
ScanState ss
Definition: execnodes.h:2277
bool * resnull
Definition: execExpr.h:274
Definition: nodes.h:536
AggSplit aggsplit
Definition: execnodes.h:2282
List * args
Definition: primnodes.h:330
Datum * tts_values
Definition: tuptable.h:126
AggStatePerTrans pertrans
Definition: execnodes.h:2287
#define OidIsValid(objectId)
Definition: c.h:710
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:799
FunctionCallInfo transfn_fcinfo
Definition: nodeAgg.h:162
int numtrans
Definition: execnodes.h:2280
Aggref * aggref
Definition: nodeAgg.h:44
PlanState ps
Definition: execnodes.h:1378
int maxsets
Definition: execnodes.h:2307
struct ExprEvalStep::@49::@88 agg_strict_input_check
#define linitial(l)
Definition: pg_list.h:174
AggStrategy aggstrategy
Definition: execnodes.h:2281
bool fn_strict
Definition: fmgr.h:61
bool resnull
Definition: execnodes.h:73
union ExprEvalStep::@49 d
Expr * expr
Definition: execnodes.h:95
#define lfirst_int(lc)
Definition: pg_list.h:170
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
bool * tts_isnull
Definition: tuptable.h:128
List * aggorder
Definition: primnodes.h:331
List * aggdirectargs
Definition: primnodes.h:329
Datum value
Definition: postgres.h:422
List * lappend_int(List *list, int datum)
Definition: list.c:354
static void ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
Definition: execExpr.c:2594
int num_hashes
Definition: execnodes.h:2318
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:900
uintptr_t Datum
Definition: postgres.h:411
FmgrInfo * flinfo
Definition: fmgr.h:87
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2445
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:883
FmgrInfo deserialfn
Definition: nodeAgg.h:87
#define Max(x, y)
Definition: c.h:980
#define makeNode(_type_)
Definition: nodes.h:584
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
FunctionCallInfo deserialfn_fcinfo
Definition: nodeAgg.h:167
Definition: regguts.h:317
intptr_t opcode
Definition: execExpr.h:270
Expr * expr
Definition: primnodes.h:1455
static int list_length(const List *l)
Definition: pg_list.h:149
Expr * aggfilter
Definition: primnodes.h:333
struct ExprEvalStep::@49::@59 jump
static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info)
Definition: execExpr.c:2638
static Datum values[MAXATTR]
Definition: bootstrap.c:156
int steps_len
Definition: execnodes.h:105
void * arg
struct ExprEvalStep::@49::@87 agg_deserialize
TupleTableSlot * sortslot
Definition: nodeAgg.h:136
Definition: pg_list.h:50
Datum resvalue
Definition: execnodes.h:75
static void ExecBuildAggTransCall(ExprState *state, AggState *aggstate, ExprEvalStep *scratch, FunctionCallInfo fcinfo, AggStatePerTrans pertrans, int transno, int setno, int setoff, bool ishash, bool nullcheck)
Definition: execExpr.c:3592

◆ ExecBuildAggTransCall()

static void ExecBuildAggTransCall ( ExprState state,
AggState aggstate,
ExprEvalStep scratch,
FunctionCallInfo  fcinfo,
AggStatePerTrans  pertrans,
int  transno,
int  setno,
int  setoff,
bool  ishash,
bool  nullcheck 
)
static

Definition at line 3592 of file execExpr.c.

References ExprEvalStep::agg_plain_pergroup_nullcheck, ExprEvalStep::agg_trans, AggState::aggcontexts, Assert, ExprEvalStep::d, EEOP_AGG_ORDERED_TRANS_DATUM, EEOP_AGG_ORDERED_TRANS_TUPLE, EEOP_AGG_PLAIN_PERGROUP_NULLCHECK, EEOP_AGG_PLAIN_TRANS_BYREF, EEOP_AGG_PLAIN_TRANS_BYVAL, EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF, EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL, EEOP_AGG_PLAIN_TRANS_STRICT_BYREF, EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL, ExprEvalPushStep(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_strict, AggState::hashcontext, AggStatePerTransData::initValueIsNull, AggStatePerTransData::numInputs, AggStatePerTransData::numSortCols, ExprEvalStep::opcode, ExprState::steps, ExprState::steps_len, and AggStatePerTransData::transtypeByVal.

Referenced by ExecBuildAggTrans().

3597 {
3598  ExprContext *aggcontext;
3599  int adjust_jumpnull = -1;
3600 
3601  if (ishash)
3602  aggcontext = aggstate->hashcontext;
3603  else
3604  aggcontext = aggstate->aggcontexts[setno];
3605 
3606  /* add check for NULL pointer? */
3607  if (nullcheck)
3608  {
3610  scratch->d.agg_plain_pergroup_nullcheck.setoff = setoff;
3611  /* adjust later */
3612  scratch->d.agg_plain_pergroup_nullcheck.jumpnull = -1;
3613  ExprEvalPushStep(state, scratch);
3614  adjust_jumpnull = state->steps_len - 1;
3615  }
3616 
3617  /*
3618  * Determine appropriate transition implementation.
3619  *
3620  * For non-ordered aggregates:
3621  *
3622  * If the initial value for the transition state doesn't exist in the
3623  * pg_aggregate table then we will let the first non-NULL value returned
3624  * from the outer procNode become the initial value. (This is useful for
3625  * aggregates like max() and min().) The noTransValue flag signals that we
3626  * need to do so. If true, generate a
3627  * EEOP_AGG_INIT_STRICT_PLAIN_TRANS{,_BYVAL} step. This step also needs to
3628  * do the work described next:
3629  *
3630  * If the function is strict, but does have an initial value, choose
3631  * EEOP_AGG_STRICT_PLAIN_TRANS{,_BYVAL}, which skips the transition
3632  * function if the transition value has become NULL (because a previous
3633  * transition function returned NULL). This step also needs to do the work
3634  * described next:
3635  *
3636  * Otherwise we call EEOP_AGG_PLAIN_TRANS{,_BYVAL}, which does not have to
3637  * perform either of the above checks.
3638  *
3639  * Having steps with overlapping responsibilities is not nice, but
3640  * aggregations are very performance sensitive, making this worthwhile.
3641  *
3642  * For ordered aggregates:
3643  *
3644  * Only need to choose between the faster path for a single ordered
3645  * column, and the one between multiple columns. Checking strictness etc
3646  * is done when finalizing the aggregate. See
3647  * process_ordered_aggregate_{single, multi} and
3648  * advance_transition_function.
3649  */
3650  if (pertrans->numSortCols == 0)
3651  {
3652  if (pertrans->transtypeByVal)
3653  {
3654  if (fcinfo->flinfo->fn_strict &&
3655  pertrans->initValueIsNull)
3657  else if (fcinfo->flinfo->fn_strict)
3659  else
3661  }
3662  else
3663  {
3664  if (fcinfo->flinfo->fn_strict &&
3665  pertrans->initValueIsNull)
3667  else if (fcinfo->flinfo->fn_strict)
3669  else
3671  }
3672  }
3673  else if (pertrans->numInputs == 1)
3675  else
3677 
3678  scratch->d.agg_trans.pertrans = pertrans;
3679  scratch->d.agg_trans.setno = setno;
3680  scratch->d.agg_trans.setoff = setoff;
3681  scratch->d.agg_trans.transno = transno;
3682  scratch->d.agg_trans.aggcontext = aggcontext;
3683  ExprEvalPushStep(state, scratch);
3684 
3685  /* fix up jumpnull */
3686  if (adjust_jumpnull != -1)
3687  {
3688  ExprEvalStep *as = &state->steps[adjust_jumpnull];
3689 
3691  Assert(as->d.agg_plain_pergroup_nullcheck.jumpnull == -1);
3692  as->d.agg_plain_pergroup_nullcheck.jumpnull = state->steps_len;
3693  }
3694 }
struct ExprEvalStep * steps
Definition: execnodes.h:86
struct ExprEvalStep::@49::@89 agg_plain_pergroup_nullcheck
bool fn_strict
Definition: fmgr.h:61
union ExprEvalStep::@49 d
struct ExprEvalStep::@49::@90 agg_trans
ExprContext * hashcontext
Definition: execnodes.h:2288
FmgrInfo * flinfo
Definition: fmgr.h:87
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2445
ExprContext ** aggcontexts
Definition: execnodes.h:2289
#define Assert(condition)
Definition: c.h:804
intptr_t opcode
Definition: execExpr.h:270
int steps_len
Definition: execnodes.h:105

◆ ExecBuildGroupingEqual()

ExprState* ExecBuildGroupingEqual ( TupleDesc  ldesc,
TupleDesc  rdesc,
const TupleTableSlotOps lops,
const TupleTableSlotOps rops,
int  numCols,
const AttrNumber keyColIdx,
const Oid eqfunctions,
const Oid collations,
PlanState parent 
)

Definition at line 3708 of file execExpr.c.

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, FunctionCallInfoBaseData::args, Assert, ExprEvalStep::d, EEO_FLAG_IS_QUAL, EEOP_DONE, EEOP_INNER_FETCHSOME, EEOP_INNER_VAR, EEOP_NOT_DISTINCT, EEOP_OUTER_FETCHSOME, EEOP_OUTER_VAR, EEOP_QUAL, ExecComputeSlotInfo(), ExecReadyExpr(), ExprState::expr, ExprEvalPushStep(), ExprEvalStep::fetch, ExprState::flags, fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_addr, ExprEvalStep::func, get_func_name(), GetUserId(), InitFunctionCallInfoData, InvokeFunctionExecuteHook, NullableDatum::isnull, lappend_int(), lfirst_int, makeNode, NIL, OBJECT_FUNCTION, ExprEvalStep::opcode, palloc0(), ExprState::parent, pg_proc_aclcheck(), ExprEvalStep::qualexpr, ExprState::resnull, ExprEvalStep::resnull, ExprState::resvalue, ExprEvalStep::resvalue, SizeForFunctionCallInfo, ExprState::steps, ExprState::steps_len, TupleDescAttr, NullableDatum::value, and ExprEvalStep::var.

Referenced by BuildTupleHashTableExt(), ExecInitSubPlan(), ExecProcNode(), and execTuplesMatchPrepare().

3715 {
3717  ExprEvalStep scratch = {0};
3718  int maxatt = -1;
3719  List *adjust_jumps = NIL;
3720  ListCell *lc;
3721 
3722  /*
3723  * When no columns are actually compared, the result's always true. See
3724  * special case in ExecQual().
3725  */
3726  if (numCols == 0)
3727  return NULL;
3728 
3729  state->expr = NULL;
3730  state->flags = EEO_FLAG_IS_QUAL;
3731  state->parent = parent;
3732 
3733  scratch.resvalue = &state->resvalue;
3734  scratch.resnull = &state->resnull;
3735 
3736  /* compute max needed attribute */
3737  for (int natt = 0; natt < numCols; natt++)
3738  {
3739  int attno = keyColIdx[natt];
3740 
3741  if (attno > maxatt)
3742  maxatt = attno;
3743  }
3744  Assert(maxatt >= 0);
3745 
3746  /* push deform steps */
3747  scratch.opcode = EEOP_INNER_FETCHSOME;
3748  scratch.d.fetch.last_var = maxatt;
3749  scratch.d.fetch.fixed = false;
3750  scratch.d.fetch.known_desc = ldesc;
3751  scratch.d.fetch.kind = lops;
3752  if (ExecComputeSlotInfo(state, &scratch))
3753  ExprEvalPushStep(state, &scratch);
3754 
3755  scratch.opcode = EEOP_OUTER_FETCHSOME;
3756  scratch.d.fetch.last_var = maxatt;
3757  scratch.d.fetch.fixed = false;
3758  scratch.d.fetch.known_desc = rdesc;
3759  scratch.d.fetch.kind = rops;
3760  if (ExecComputeSlotInfo(state, &scratch))
3761  ExprEvalPushStep(state, &scratch);
3762 
3763  /*
3764  * Start comparing at the last field (least significant sort key). That's
3765  * the most likely to be different if we are dealing with sorted input.
3766  */
3767  for (int natt = numCols; --natt >= 0;)
3768  {
3769  int attno = keyColIdx[natt];
3770  Form_pg_attribute latt = TupleDescAttr(ldesc, attno - 1);
3771  Form_pg_attribute ratt = TupleDescAttr(rdesc, attno - 1);
3772  Oid foid = eqfunctions[natt];
3773  Oid collid = collations[natt];
3774  FmgrInfo *finfo;
3775  FunctionCallInfo fcinfo;
3776  AclResult aclresult;
3777 
3778  /* Check permission to call function */
3779  aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
3780  if (aclresult != ACLCHECK_OK)
3781  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
3782 
3784 
3785  /* Set up the primary fmgr lookup information */
3786  finfo = palloc0(sizeof(FmgrInfo));
3787  fcinfo = palloc0(SizeForFunctionCallInfo(2));
3788  fmgr_info(foid, finfo);
3789  fmgr_info_set_expr(NULL, finfo);
3790  InitFunctionCallInfoData(*fcinfo, finfo, 2,
3791  collid, NULL, NULL);
3792 
3793  /* left arg */
3794  scratch.opcode = EEOP_INNER_VAR;
3795  scratch.d.var.attnum = attno - 1;
3796  scratch.d.var.vartype = latt->atttypid;
3797  scratch.resvalue = &fcinfo->args[0].value;
3798  scratch.resnull = &fcinfo->args[0].isnull;
3799  ExprEvalPushStep(state, &scratch);
3800 
3801  /* right arg */
3802  scratch.opcode = EEOP_OUTER_VAR;
3803  scratch.d.var.attnum = attno - 1;
3804  scratch.d.var.vartype = ratt->atttypid;
3805  scratch.resvalue = &fcinfo->args[1].value;
3806  scratch.resnull = &fcinfo->args[1].isnull;
3807  ExprEvalPushStep(state, &scratch);
3808 
3809  /* evaluate distinctness */
3810  scratch.opcode = EEOP_NOT_DISTINCT;
3811  scratch.d.func.finfo = finfo;
3812  scratch.d.func.fcinfo_data = fcinfo;
3813  scratch.d.func.fn_addr = finfo->fn_addr;
3814  scratch.d.func.nargs = 2;
3815  scratch.resvalue = &state->resvalue;
3816  scratch.resnull = &state->resnull;
3817  ExprEvalPushStep(state, &scratch);
3818 
3819  /* then emit EEOP_QUAL to detect if result is false (or null) */
3820  scratch.opcode = EEOP_QUAL;
3821  scratch.d.qualexpr.jumpdone = -1;
3822  scratch.resvalue = &state->resvalue;
3823  scratch.resnull = &state->resnull;
3824  ExprEvalPushStep(state, &scratch);
3825  adjust_jumps = lappend_int(adjust_jumps,
3826  state->steps_len - 1);
3827  }
3828 
3829  /* adjust jump targets */
3830  foreach(lc, adjust_jumps)
3831  {
3832  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
3833 
3834  Assert(as->opcode == EEOP_QUAL);
3835  Assert(as->d.qualexpr.jumpdone == -1);
3836  as->d.qualexpr.jumpdone = state->steps_len;
3837  }
3838 
3839  scratch.resvalue = NULL;
3840  scratch.resnull = NULL;
3841  scratch.opcode = EEOP_DONE;
3842  ExprEvalPushStep(state, &scratch);
3843 
3844  ExecReadyExpr(state);
3845 
3846  return state;
3847 }
#define NIL
Definition: pg_list.h:65
Definition: fmgr.h:56
struct PlanState * parent
Definition: execnodes.h:109
Datum * resvalue
Definition: execExpr.h:273
struct ExprEvalStep::@49::@50 fetch
Oid GetUserId(void)
Definition: miscinit.c:495
PGFunction fn_addr
Definition: fmgr.h:58
struct ExprEvalStep * steps
Definition: execnodes.h:86
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
struct ExprEvalStep::@49::@58 qualexpr
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
bool * resnull
Definition: execExpr.h:274
unsigned int Oid
Definition: postgres_ext.h:31
struct ExprEvalStep::@49::@51 var
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3308
bool resnull
Definition: execnodes.h:73
union ExprEvalStep::@49 d
Expr * expr
Definition: execnodes.h:95
#define lfirst_int(lc)
Definition: pg_list.h:170
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1579
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
#define EEO_FLAG_IS_QUAL
Definition: execnodes.h:60
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
Datum value
Definition: postgres.h:422
List * lappend_int(List *list, int datum)
Definition: list.c:354
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:191
void * palloc0(Size size)
Definition: mcxt.c:1093
AclResult
Definition: acl.h:177
static bool ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op)
Definition: execExpr.c:2692
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2445
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:883
struct ExprEvalStep::@49::@56 func
#define makeNode(_type_)
Definition: nodes.h:584
#define Assert(condition)
Definition: c.h:804
Definition: regguts.h:317
intptr_t opcode
Definition: execExpr.h:270
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
int steps_len
Definition: execnodes.h:105
#define ACL_EXECUTE
Definition: parsenodes.h:89
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4718
uint8 flags
Definition: execnodes.h:66
Definition: pg_list.h:50
Datum resvalue
Definition: execnodes.h:75

◆ ExecBuildParamSetEqual()

ExprState* ExecBuildParamSetEqual ( TupleDesc  desc,
const TupleTableSlotOps lops,
const TupleTableSlotOps rops,
const Oid eqfunctions,
const Oid collations,
const List param_exprs,
PlanState parent 
)

Definition at line 3865 of file execExpr.c.

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, FunctionCallInfoBaseData::args, Assert, ExprEvalStep::d, EEO_FLAG_IS_QUAL, EEOP_DONE, EEOP_INNER_FETCHSOME, EEOP_INNER_VAR, EEOP_NOT_DISTINCT, EEOP_OUTER_FETCHSOME, EEOP_OUTER_VAR, EEOP_QUAL, ExecComputeSlotInfo(), ExecReadyExpr(), ExprState::expr, ExprEvalPushStep(), ExprEvalStep::fetch, ExprState::flags, fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_addr, ExprEvalStep::func, get_func_name(), GetUserId(), InitFunctionCallInfoData, InvokeFunctionExecuteHook, NullableDatum::isnull, lappend_int(), lfirst_int, list_length(), makeNode, NIL, OBJECT_FUNCTION, ExprEvalStep::opcode, palloc0(), ExprState::parent, pg_proc_aclcheck(), ExprEvalStep::qualexpr, ExprState::resnull, ExprEvalStep::resnull, ExprState::resvalue, ExprEvalStep::resvalue, SizeForFunctionCallInfo, ExprState::steps, ExprState::steps_len, TupleDescAttr, NullableDatum::value, and ExprEvalStep::var.

Referenced by ExecInitMemoize(), and ExecProcNode().

3872 {
3874  ExprEvalStep scratch = {0};
3875  int maxatt = list_length(param_exprs);
3876  List *adjust_jumps = NIL;
3877  ListCell *lc;
3878 
3879  state->expr = NULL;
3880  state->flags = EEO_FLAG_IS_QUAL;
3881  state->parent = parent;
3882 
3883  scratch.resvalue = &state->resvalue;
3884  scratch.resnull = &state->resnull;
3885 
3886  /* push deform steps */
3887  scratch.opcode = EEOP_INNER_FETCHSOME;
3888  scratch.d.fetch.last_var = maxatt;
3889  scratch.d.fetch.fixed = false;
3890  scratch.d.fetch.known_desc = desc;
3891  scratch.d.fetch.kind = lops;
3892  if (ExecComputeSlotInfo(state, &scratch))
3893  ExprEvalPushStep(state, &scratch);
3894 
3895  scratch.opcode = EEOP_OUTER_FETCHSOME;
3896  scratch.d.fetch.last_var = maxatt;
3897  scratch.d.fetch.fixed = false;
3898  scratch.d.fetch.known_desc = desc;
3899  scratch.d.fetch.kind = rops;
3900  if (ExecComputeSlotInfo(state, &scratch))
3901  ExprEvalPushStep(state, &scratch);
3902 
3903  for (int attno = 0; attno < maxatt; attno++)
3904  {
3905  Form_pg_attribute att = TupleDescAttr(desc, attno);
3906  Oid foid = eqfunctions[attno];
3907  Oid collid = collations[attno];
3908  FmgrInfo *finfo;
3909  FunctionCallInfo fcinfo;
3910  AclResult aclresult;
3911 
3912  /* Check permission to call function */
3913  aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
3914  if (aclresult != ACLCHECK_OK)
3915  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
3916 
3918 
3919  /* Set up the primary fmgr lookup information */
3920  finfo = palloc0(sizeof(FmgrInfo));
3921  fcinfo = palloc0(SizeForFunctionCallInfo(2));
3922  fmgr_info(foid, finfo);
3923  fmgr_info_set_expr(NULL, finfo);
3924  InitFunctionCallInfoData(*fcinfo, finfo, 2,
3925  collid, NULL, NULL);
3926 
3927  /* left arg */
3928  scratch.opcode = EEOP_INNER_VAR;
3929  scratch.d.var.attnum = attno;
3930  scratch.d.var.vartype = att->atttypid;
3931  scratch.resvalue = &fcinfo->args[0].value;
3932  scratch.resnull = &fcinfo->args[0].isnull;
3933  ExprEvalPushStep(state, &scratch);
3934 
3935  /* right arg */
3936  scratch.opcode = EEOP_OUTER_VAR;
3937  scratch.d.var.attnum = attno;
3938  scratch.d.var.vartype = att->atttypid;
3939  scratch.resvalue = &fcinfo->args[1].value;
3940  scratch.resnull = &fcinfo->args[1].isnull;
3941  ExprEvalPushStep(state, &scratch);
3942 
3943  /* evaluate distinctness */
3944  scratch.opcode = EEOP_NOT_DISTINCT;
3945  scratch.d.func.finfo = finfo;
3946  scratch.d.func.fcinfo_data = fcinfo;
3947  scratch.d.func.fn_addr = finfo->fn_addr;
3948  scratch.d.func.nargs = 2;
3949  scratch.resvalue = &state->resvalue;
3950  scratch.resnull = &state->resnull;
3951  ExprEvalPushStep(state, &scratch);
3952 
3953  /* then emit EEOP_QUAL to detect if result is false (or null) */
3954  scratch.opcode = EEOP_QUAL;
3955  scratch.d.qualexpr.jumpdone = -1;
3956  scratch.resvalue = &state->resvalue;
3957  scratch.resnull = &state->resnull;
3958  ExprEvalPushStep(state, &scratch);
3959  adjust_jumps = lappend_int(adjust_jumps,
3960  state->steps_len - 1);
3961  }
3962 
3963  /* adjust jump targets */
3964  foreach(lc, adjust_jumps)
3965  {
3966  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
3967 
3968  Assert(as->opcode == EEOP_QUAL);
3969  Assert(as->d.qualexpr.jumpdone == -1);
3970  as->d.qualexpr.jumpdone = state->steps_len;
3971  }
3972 
3973  scratch.resvalue = NULL;
3974  scratch.resnull = NULL;
3975  scratch.opcode = EEOP_DONE;
3976  ExprEvalPushStep(state, &scratch);
3977 
3978  ExecReadyExpr(state);
3979 
3980  return state;
3981 }
#define NIL
Definition: pg_list.h:65
Definition: fmgr.h:56
struct PlanState * parent
Definition: execnodes.h:109
Datum * resvalue
Definition: execExpr.h:273
struct ExprEvalStep::@49::@50 fetch
Oid GetUserId(void)
Definition: miscinit.c:495
PGFunction fn_addr
Definition: fmgr.h:58
struct ExprEvalStep * steps
Definition: execnodes.h:86
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
struct ExprEvalStep::@49::@58 qualexpr
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
bool * resnull
Definition: execExpr.h:274
unsigned int Oid
Definition: postgres_ext.h:31
struct ExprEvalStep::@49::@51 var
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3308
bool resnull
Definition: execnodes.h:73
union ExprEvalStep::@49 d
Expr * expr
Definition: execnodes.h:95
#define lfirst_int(lc)
Definition: pg_list.h:170
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1579
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
#define EEO_FLAG_IS_QUAL
Definition: execnodes.h:60
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
Datum value
Definition: postgres.h:422
List * lappend_int(List *list, int datum)
Definition: list.c:354
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:191
void * palloc0(Size size)
Definition: mcxt.c:1093
AclResult
Definition: acl.h:177
static bool ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op)
Definition: execExpr.c:2692
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2445
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:883
struct ExprEvalStep::@49::@56 func
#define makeNode(_type_)
Definition: nodes.h:584
#define Assert(condition)
Definition: c.h:804
Definition: regguts.h:317
intptr_t opcode
Definition: execExpr.h:270
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
static int list_length(const List *l)
Definition: pg_list.h:149
int steps_len
Definition: execnodes.h:105
#define ACL_EXECUTE
Definition: parsenodes.h:89
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4718
uint8 flags
Definition: execnodes.h:66
Definition: pg_list.h:50
Datum resvalue
Definition: execnodes.h:75

◆ ExecBuildProjectionInfo()

ProjectionInfo* ExecBuildProjectionInfo ( List targetList,
ExprContext econtext,
TupleTableSlot slot,
PlanState parent,
TupleDesc  inputDesc 
)

Definition at line 353 of file execExpr.c.

References ExprEvalStep::assign_tmp, ExprEvalStep::assign_var, attnum, ExprEvalStep::d, EEOP_ASSIGN_INNER_VAR, EEOP_ASSIGN_OUTER_VAR, EEOP_ASSIGN_SCAN_VAR, EEOP_ASSIGN_TMP, EEOP_ASSIGN_TMP_MAKE_RO, EEOP_DONE, ExecInitExprRec(), ExecInitExprSlots(), ExecReadyExpr(), ExprState::expr, TargetEntry::expr, ExprEvalPushStep(), exprType(), ExprState::ext_params, get_typlen(), INNER_VAR, IsA, lfirst_node, makeNode, ExprEvalStep::opcode, OUTER_VAR, ExprState::parent, ProjectionInfo::pi_exprContext, ProjectionInfo::pi_state, TargetEntry::resno, ExprState::resnull, ExprState::resultslot, ExprState::resvalue, T_ExprState, TupleDescAttr, ExprState::type, Var::varattno, Var::varno, and Var::vartype.

Referenced by ExecAssignProjectionInfo(), ExecInitInsertProjection(), ExecInitModifyTable(), ExecInitPartitionInfo(), ExecInitSubPlan(), and ExecProcNode().

358 {
360  ExprState *state;
361  ExprEvalStep scratch = {0};
362  ListCell *lc;
363 
364  projInfo->pi_exprContext = econtext;
365  /* We embed ExprState into ProjectionInfo instead of doing extra palloc */
366  projInfo->pi_state.type = T_ExprState;
367  state = &projInfo->pi_state;
368  state->expr = (Expr *) targetList;
369  state->parent = parent;
370  state->ext_params = NULL;
371 
372  state->resultslot = slot;
373 
374  /* Insert EEOP_*_FETCHSOME steps as needed */
375  ExecInitExprSlots(state, (Node *) targetList);
376 
377  /* Now compile each tlist column */
378  foreach(lc, targetList)
379  {
380  TargetEntry *tle = lfirst_node(TargetEntry, lc);
381  Var *variable = NULL;
382  AttrNumber attnum = 0;
383  bool isSafeVar = false;
384 
385  /*
386  * If tlist expression is a safe non-system Var, use the fast-path
387  * ASSIGN_*_VAR opcodes. "Safe" means that we don't need to apply
388  * CheckVarSlotCompatibility() during plan startup. If a source slot
389  * was provided, we make the equivalent tests here; if a slot was not
390  * provided, we assume that no check is needed because we're dealing
391  * with a non-relation-scan-level expression.
392  */
393  if (tle->expr != NULL &&
394  IsA(tle->expr, Var) &&
395  ((Var *) tle->expr)->varattno > 0)
396  {
397  /* Non-system Var, but how safe is it? */
398  variable = (Var *) tle->expr;
399  attnum = variable->varattno;
400 
401  if (inputDesc == NULL)
402  isSafeVar = true; /* can't check, just assume OK */
403  else if (attnum <= inputDesc->natts)
404  {
405  Form_pg_attribute attr = TupleDescAttr(inputDesc, attnum - 1);
406 
407  /*
408  * If user attribute is dropped or has a type mismatch, don't
409  * use ASSIGN_*_VAR. Instead let the normal expression
410  * machinery handle it (which'll possibly error out).
411  */
412  if (!attr->attisdropped && variable->vartype == attr->atttypid)
413  {
414  isSafeVar = true;
415  }
416  }
417  }
418 
419  if (isSafeVar)
420  {
421  /* Fast-path: just generate an EEOP_ASSIGN_*_VAR step */
422  switch (variable->varno)
423  {
424  case INNER_VAR:
425  /* get the tuple from the inner node */
426  scratch.opcode = EEOP_ASSIGN_INNER_VAR;
427  break;
428 
429  case OUTER_VAR:
430  /* get the tuple from the outer node */
431  scratch.opcode = EEOP_ASSIGN_OUTER_VAR;
432  break;
433 
434  /* INDEX_VAR is handled by default case */
435 
436  default:
437  /* get the tuple from the relation being scanned */
438  scratch.opcode = EEOP_ASSIGN_SCAN_VAR;
439  break;
440  }
441 
442  scratch.d.assign_var.attnum = attnum - 1;
443  scratch.d.assign_var.resultnum = tle->resno - 1;
444  ExprEvalPushStep(state, &scratch);
445  }
446  else
447  {
448  /*
449  * Otherwise, compile the column expression normally.
450  *
451  * We can't tell the expression to evaluate directly into the
452  * result slot, as the result slot (and the exprstate for that
453  * matter) can change between executions. We instead evaluate
454  * into the ExprState's resvalue/resnull and then move.
455  */
456  ExecInitExprRec(tle->expr, state,
457  &state->resvalue, &state->resnull);
458 
459  /*
460  * Column might be referenced multiple times in upper nodes, so
461  * force value to R/O - but only if it could be an expanded datum.
462  */
463  if (get_typlen(exprType((Node *) tle->expr)) == -1)
465  else
466  scratch.opcode = EEOP_ASSIGN_TMP;
467  scratch.d.assign_tmp.resultnum = tle->resno - 1;
468  ExprEvalPushStep(state, &scratch);
469  }
470  }
471 
472  scratch.opcode = EEOP_DONE;
473  ExprEvalPushStep(state, &scratch);
474 
475  ExecReadyExpr(state);
476 
477  return projInfo;
478 }
int varno
Definition: primnodes.h:189
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
struct PlanState * parent
Definition: execnodes.h:109
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
ParamListInfo ext_params
Definition: execnodes.h:110
Definition: nodes.h:536
AttrNumber varattno
Definition: primnodes.h:191
TupleTableSlot * resultslot
Definition: execnodes.h:81
Definition: primnodes.h:186
bool resnull
Definition: execnodes.h:73
union ExprEvalStep::@49 d
Expr * expr
Definition: execnodes.h:95
Oid vartype
Definition: primnodes.h:193
static void ExecInitExprSlots(ExprState *state, Node *node)
Definition: execExpr.c:2576
#define lfirst_node(type, lc)
Definition: pg_list.h:172
AttrNumber resno
Definition: primnodes.h:1456
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
NodeTag type
Definition: execnodes.h:64
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:900
struct ExprEvalStep::@49::@53 assign_var
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2445
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:883
int16 attnum
Definition: pg_attribute.h:83
#define INNER_VAR
Definition: primnodes.h:175
#define makeNode(_type_)
Definition: nodes.h:584
Definition: regguts.h:317
intptr_t opcode
Definition: execExpr.h:270
Expr * expr
Definition: primnodes.h:1455
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2144
ExprState pi_state
Definition: execnodes.h:334
struct ExprEvalStep::@49::@54 assign_tmp
ExprContext * pi_exprContext
Definition: execnodes.h:336
Datum resvalue
Definition: execnodes.h:75
int16 AttrNumber
Definition: attnum.h:21
#define OUTER_VAR
Definition: primnodes.h:176

◆ ExecBuildUpdateProjection()

ProjectionInfo* ExecBuildUpdateProjection ( List targetList,
bool  evalTargetList,
List targetColnos,
TupleDesc  relDesc,
ExprContext econtext,
TupleTableSlot slot,
PlanState parent 
)

Definition at line 513 of file execExpr.c.

References Assert, ExprEvalStep::assign_tmp, ExprEvalStep::assign_var, attnum, bms_add_member(), bms_is_member(), ExprEvalStep::constval, ExprEvalStep::d, EEOP_ASSIGN_OUTER_VAR, EEOP_ASSIGN_SCAN_VAR, EEOP_ASSIGN_TMP, EEOP_CONST, EEOP_DONE, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, ExecInitExprRec(), ExecPushExprSlots(), ExecReadyExpr(), ExprState::expr, TargetEntry::expr, ExprEvalPushStep(), exprType(), ExprState::ext_params, for_each_cell, forboth, format_type_be(), get_last_attnums_walker(), LastAttnumInfo::last_outer, LastAttnumInfo::last_scan, lfirst_int, lfirst_node, list_length(), makeNode, TupleDescData::natts, ExprEvalStep::opcode, ExprState::parent, ProjectionInfo::pi_exprContext, ProjectionInfo::pi_state, TargetEntry::resjunk, ExprState::resnull, ExprEvalStep::resnull, ExprState::resultslot, ExprState::resvalue, ExprEvalStep::resvalue, T_ExprState, TupleDescAttr, and ExprState::type.

Referenced by ExecInitModifyTable(), ExecInitPartitionInfo(), ExecInitUpdateProjection(), and ExecProcNode().

520 {
522  ExprState *state;
523  int nAssignableCols;
524  bool sawJunk;
525  Bitmapset *assignedCols;
526  LastAttnumInfo deform = {0, 0, 0};
527  ExprEvalStep scratch = {0};
528  int outerattnum;
529  ListCell *lc,
530  *lc2;
531 
532  projInfo->pi_exprContext = econtext;
533  /* We embed ExprState into ProjectionInfo instead of doing extra palloc */
534  projInfo->pi_state.type = T_ExprState;
535  state = &projInfo->pi_state;
536  if (evalTargetList)
537  state->expr = (Expr *) targetList;
538  else
539  state->expr = NULL; /* not used */
540  state->parent = parent;
541  state->ext_params = NULL;
542 
543  state->resultslot = slot;
544 
545  /*
546  * Examine the targetList to see how many non-junk columns there are, and
547  * to verify that the non-junk columns come before the junk ones.
548  */
549  nAssignableCols = 0;
550  sawJunk = false;
551  foreach(lc, targetList)
552  {
553  TargetEntry *tle = lfirst_node(TargetEntry, lc);
554 
555  if (tle->resjunk)
556  sawJunk = true;
557  else
558  {
559  if (sawJunk)
560  elog(ERROR, "subplan target list is out of order");
561  nAssignableCols++;
562  }
563  }
564 
565  /* We should have one targetColnos entry per non-junk column */
566  if (nAssignableCols != list_length(targetColnos))
567  elog(ERROR, "targetColnos does not match subplan target list");
568 
569  /*
570  * Build a bitmapset of the columns in targetColnos. (We could just use
571  * list_member_int() tests, but that risks O(N^2) behavior with many
572  * columns.)
573  */
574  assignedCols = NULL;
575  foreach(lc, targetColnos)
576  {
577  AttrNumber targetattnum = lfirst_int(lc);
578 
579  assignedCols = bms_add_member(assignedCols, targetattnum);
580  }
581 
582  /*
583  * We need to insert EEOP_*_FETCHSOME steps to ensure the input tuples are
584  * sufficiently deconstructed. The scan tuple must be deconstructed at
585  * least as far as the last old column we need.
586  */
587  for (int attnum = relDesc->natts; attnum > 0; attnum--)
588  {
589  Form_pg_attribute attr = TupleDescAttr(relDesc, attnum - 1);
590 
591  if (attr->attisdropped)
592  continue;
593  if (bms_is_member(attnum, assignedCols))
594  continue;
595  deform.last_scan = attnum;
596  break;
597  }
598 
599  /*
600  * If we're actually evaluating the tlist, incorporate its input
601  * requirements too; otherwise, we'll just need to fetch the appropriate
602  * number of columns of the "outer" tuple.
603  */
604  if (evalTargetList)
605  get_last_attnums_walker((Node *) targetList, &deform);
606  else
607  deform.last_outer = nAssignableCols;
608 
609  ExecPushExprSlots(state, &deform);
610 
611  /*
612  * Now generate code to evaluate the tlist's assignable expressions or
613  * fetch them from the outer tuple, incidentally validating that they'll
614  * be of the right data type. The checks above ensure that the forboth()
615  * will iterate over exactly the non-junk columns.
616  */
617  outerattnum = 0;
618  forboth(lc, targetList, lc2, targetColnos)
619  {
620  TargetEntry *tle = lfirst_node(TargetEntry, lc);
621  AttrNumber targetattnum = lfirst_int(lc2);
622  Form_pg_attribute attr;
623 
624  Assert(!tle->resjunk);
625 
626  /*
627  * Apply sanity checks comparable to ExecCheckPlanOutput().
628  */
629  if (targetattnum <= 0 || targetattnum > relDesc->natts)
630  ereport(ERROR,
631  (errcode(ERRCODE_DATATYPE_MISMATCH),
632  errmsg("table row type and query-specified row type do not match"),
633  errdetail("Query has too many columns.")));
634  attr = TupleDescAttr(relDesc, targetattnum - 1);
635 
636  if (attr->attisdropped)
637  ereport(ERROR,
638  (errcode(ERRCODE_DATATYPE_MISMATCH),
639  errmsg("table row type and query-specified row type do not match"),
640  errdetail("Query provides a value for a dropped column at ordinal position %d.",
641  targetattnum)));
642  if (exprType((Node *) tle->expr) != attr->atttypid)
643  ereport(ERROR,
644  (errcode(ERRCODE_DATATYPE_MISMATCH),
645  errmsg("table row type and query-specified row type do not match"),
646  errdetail("Table has type %s at ordinal position %d, but query expects %s.",
647  format_type_be(attr->atttypid),
648  targetattnum,
649  format_type_be(exprType((Node *) tle->expr)))));
650 
651  /* OK, generate code to perform the assignment. */
652  if (evalTargetList)
653  {
654  /*
655  * We must evaluate the TLE's expression and assign it. We do not
656  * bother jumping through hoops for "safe" Vars like
657  * ExecBuildProjectionInfo does; this is a relatively less-used
658  * path and it doesn't seem worth expending code for that.
659  */
660  ExecInitExprRec(tle->expr, state,
661  &state->resvalue, &state->resnull);
662  /* Needn't worry about read-only-ness here, either. */
663  scratch.opcode = EEOP_ASSIGN_TMP;
664  scratch.d.assign_tmp.resultnum = targetattnum - 1;
665  ExprEvalPushStep(state, &scratch);
666  }
667  else
668  {
669  /* Just assign from the outer tuple. */
670  scratch.opcode = EEOP_ASSIGN_OUTER_VAR;
671  scratch.d.assign_var.attnum = outerattnum;
672  scratch.d.assign_var.resultnum = targetattnum - 1;
673  ExprEvalPushStep(state, &scratch);
674  }
675  outerattnum++;
676  }
677 
678  /*
679  * If we're evaluating the tlist, must evaluate any resjunk columns too.
680  * (This matters for things like MULTIEXPR_SUBLINK SubPlans.)
681  */
682  if (evalTargetList)
683  {
684  for_each_cell(lc, targetList, lc)
685  {
686  TargetEntry *tle = lfirst_node(TargetEntry, lc);
687 
688  Assert(tle->resjunk);
689  ExecInitExprRec(tle->expr, state,
690  &state->resvalue, &state->resnull);
691  }
692  }
693 
694  /*
695  * Now generate code to copy over any old columns that were not assigned
696  * to, and to ensure that dropped columns are set to NULL.
697  */
698  for (int attnum = 1; attnum <= relDesc->natts; attnum++)
699  {
700  Form_pg_attribute attr = TupleDescAttr(relDesc, attnum - 1);
701 
702  if (attr->attisdropped)
703  {
704  /* Put a null into the ExprState's resvalue/resnull ... */
705  scratch.opcode = EEOP_CONST;
706  scratch.resvalue = &state->resvalue;
707  scratch.resnull = &state->resnull;
708  scratch.d.constval.value = (Datum) 0;
709  scratch.d.constval.isnull = true;
710  ExprEvalPushStep(state, &scratch);
711  /* ... then assign it to the result slot */
712  scratch.opcode = EEOP_ASSIGN_TMP;
713  scratch.d.assign_tmp.resultnum = attnum - 1;
714  ExprEvalPushStep(state, &scratch);
715  }
716  else if (!bms_is_member(attnum, assignedCols))
717  {
718  /* Certainly the right type, so needn't check */
719  scratch.opcode = EEOP_ASSIGN_SCAN_VAR;
720  scratch.d.assign_var.attnum = attnum - 1;
721  scratch.d.assign_var.resultnum = attnum - 1;
722  ExprEvalPushStep(state, &scratch);
723  }
724  }
725 
726  scratch.opcode = EEOP_DONE;
727  ExprEvalPushStep(state, &scratch);
728 
729  ExecReadyExpr(state);
730 
731  return projInfo;
732 }
struct PlanState * parent
Definition: execnodes.h:109
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:446
Datum * resvalue
Definition: execExpr.h:273
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define for_each_cell(cell, lst, initcell)
Definition: pg_list.h:417
bool * resnull
Definition: execExpr.h:274
ParamListInfo ext_params
Definition: execnodes.h:110
Definition: nodes.h:536
int errcode(int sqlerrcode)
Definition: elog.c:698
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
TupleTableSlot * resultslot
Definition: execnodes.h:81
bool resjunk
Definition: primnodes.h:1462
#define ERROR
Definition: elog.h:46
bool resnull
Definition: execnodes.h:73
union ExprEvalStep::@49 d
Expr * expr
Definition: execnodes.h:95
#define lfirst_int(lc)
Definition: pg_list.h:170
#define lfirst_node(type, lc)
Definition: pg_list.h:172
struct ExprEvalStep::@49::@55 constval
AttrNumber last_scan
Definition: execExpr.c:58
int errdetail(const char *fmt,...)
Definition: elog.c:1042
AttrNumber last_outer
Definition: execExpr.c:57
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
NodeTag type
Definition: execnodes.h:64
static void ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
Definition: execExpr.c:2594
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:900
struct ExprEvalStep::@49::@53 assign_var
uintptr_t Datum
Definition: postgres.h:411
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2445
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:883
int16 attnum
Definition: pg_attribute.h:83
#define ereport(elevel,...)
Definition: elog.h:157
#define makeNode(_type_)
Definition: nodes.h:584
#define Assert(condition)
Definition: c.h:804
Definition: regguts.h:317
intptr_t opcode
Definition: execExpr.h:270
Expr * expr
Definition: primnodes.h:1455
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
static int list_length(const List *l)
Definition: pg_list.h:149
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info)
Definition: execExpr.c:2638
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
ExprState pi_state
Definition: execnodes.h:334
struct ExprEvalStep::@49::@54 assign_tmp
ExprContext * pi_exprContext
Definition: execnodes.h:336
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
Datum resvalue
Definition: execnodes.h:75
int16 AttrNumber
Definition: attnum.h:21

◆ ExecCheck()

bool ExecCheck ( ExprState state,
ExprContext econtext 
)

Definition at line 853 of file execExpr.c.

References Assert, DatumGetBool, EEO_FLAG_IS_QUAL, ExecEvalExprSwitchContext(), and ExprState::flags.

Referenced by ATRewriteTable(), check_default_partition_contents(), domain_check_input(), ExecPartitionCheck(), ExecQualAndReset(), and ExecRelCheck().

854 {
855  Datum ret;
856  bool isnull;
857 
858  /* short-circuit (here and in ExecInitCheck) for empty restriction list */
859  if (state == NULL)
860  return true;
861 
862  /* verify that expression was not compiled using ExecInitQual */
863  Assert(!(state->flags & EEO_FLAG_IS_QUAL));
864 
865  ret = ExecEvalExprSwitchContext(state, econtext, &isnull);
866 
867  if (isnull)
868  return true;
869 
870  return DatumGetBool(ret);
871 }
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:331
#define EEO_FLAG_IS_QUAL
Definition: execnodes.h:60
#define DatumGetBool(X)
Definition: postgres.h:437
uintptr_t Datum
Definition: postgres.h:411
#define Assert(condition)
Definition: c.h:804
uint8 flags
Definition: execnodes.h:66

◆ ExecComputeSlotInfo()

static bool ExecComputeSlotInfo ( ExprState state,
ExprEvalStep op 
)
static

Definition at line 2692 of file execExpr.c.

References Assert, ExprEvalStep::d, EEOP_INNER_FETCHSOME, EEOP_OUTER_FETCHSOME, EEOP_SCAN_FETCHSOME, ExecGetResultSlotOps(), ExecGetResultType(), ExprEvalStep::fetch, PlanState::innerops, PlanState::inneropsfixed, PlanState::inneropsset, innerPlanState, ExprEvalStep::opcode, PlanState::outerops, PlanState::outeropsfixed, PlanState::outeropsset, outerPlanState, ExprState::parent, PlanState::scandesc, PlanState::scanops, PlanState::scanopsfixed, PlanState::scanopsset, and TTSOpsVirtual.

Referenced by ExecBuildGroupingEqual(), ExecBuildParamSetEqual(), and ExecPushExprSlots().

2693 {
2694  PlanState *parent = state->parent;
2695  TupleDesc desc = NULL;
2696  const TupleTableSlotOps *tts_ops = NULL;
2697  bool isfixed = false;
2698  ExprEvalOp opcode = op->opcode;
2699 
2700  Assert(opcode == EEOP_INNER_FETCHSOME ||
2701  opcode == EEOP_OUTER_FETCHSOME ||
2702  opcode == EEOP_SCAN_FETCHSOME);
2703 
2704  if (op->d.fetch.known_desc != NULL)
2705  {
2706  desc = op->d.fetch.known_desc;
2707  tts_ops = op->d.fetch.kind;
2708  isfixed = op->d.fetch.kind != NULL;
2709  }
2710  else if (!parent)
2711  {
2712  isfixed = false;
2713  }
2714  else if (opcode == EEOP_INNER_FETCHSOME)
2715  {
2716  PlanState *is = innerPlanState(parent);
2717 
2718  if (parent->inneropsset && !parent->inneropsfixed)
2719  {
2720  isfixed = false;
2721  }
2722  else if (parent->inneropsset && parent->innerops)
2723  {
2724  isfixed = true;
2725  tts_ops = parent->innerops;
2726  desc = ExecGetResultType(is);
2727  }
2728  else if (is)
2729  {
2730  tts_ops = ExecGetResultSlotOps(is, &isfixed);
2731  desc = ExecGetResultType(is);
2732  }
2733  }
2734  else if (opcode == EEOP_OUTER_FETCHSOME)
2735  {
2736  PlanState *os = outerPlanState(parent);
2737 
2738  if (parent->outeropsset && !parent->outeropsfixed)
2739  {
2740  isfixed = false;
2741  }
2742  else if (parent->outeropsset && parent->outerops)
2743  {
2744  isfixed = true;
2745  tts_ops = parent->outerops;
2746  desc = ExecGetResultType(os);
2747  }
2748  else if (os)
2749  {
2750  tts_ops = ExecGetResultSlotOps(os, &isfixed);
2751  desc = ExecGetResultType(os);
2752  }
2753  }
2754  else if (opcode == EEOP_SCAN_FETCHSOME)
2755  {
2756  desc = parent->scandesc;
2757 
2758  if (parent->scanops)
2759  tts_ops = parent->scanops;
2760 
2761  if (parent->scanopsset)
2762  isfixed = parent->scanopsfixed;
2763  }
2764 
2765  if (isfixed && desc != NULL && tts_ops != NULL)
2766  {
2767  op->d.fetch.fixed = true;
2768  op->d.fetch.kind = tts_ops;
2769  op->d.fetch.known_desc = desc;
2770  }
2771  else
2772  {
2773  op->d.fetch.fixed = false;
2774  op->d.fetch.kind = NULL;
2775  op->d.fetch.known_desc = NULL;
2776  }
2777 
2778  /* if the slot is known to always virtual we never need to deform */
2779  if (op->d.fetch.fixed && op->d.fetch.kind == &TTSOpsVirtual)
2780  return false;
2781 
2782  return true;
2783 }
const TupleTableSlotOps * innerops
Definition: execnodes.h:1043
struct PlanState * parent
Definition: execnodes.h:109
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:499
struct ExprEvalStep::@49::@50 fetch
bool inneropsset
Definition: execnodes.h:1051
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
ExprEvalOp
Definition: execExpr.h:64
bool inneropsfixed
Definition: execnodes.h:1047
union ExprEvalStep::@49 d
#define outerPlanState(node)
Definition: execnodes.h:1063
const TupleTableSlotOps * scanops
Definition: execnodes.h:1041
bool outeropsset
Definition: execnodes.h:1050
TupleDesc scandesc
Definition: execnodes.h:1016
bool scanopsfixed
Definition: execnodes.h:1045
#define Assert(condition)
Definition: c.h:804
intptr_t opcode
Definition: execExpr.h:270
bool outeropsfixed
Definition: execnodes.h:1046
bool scanopsset
Definition: execnodes.h:1049
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:490
#define innerPlanState(node)
Definition: execnodes.h:1062
const TupleTableSlotOps * outerops
Definition: execnodes.h:1042

◆ ExecInitCheck()

ExprState* ExecInitCheck ( List qual,
PlanState parent 
)

Definition at line 298 of file execExpr.c.

References Assert, ExecInitExpr(), IsA, make_ands_explicit(), and NIL.

Referenced by ExecPrepareCheck(), and ExecProcNode().

299 {
300  /* short-circuit (here and in ExecCheck) for empty restriction list */
301  if (qual == NIL)
302  return NULL;
303 
304  Assert(IsA(qual, List));
305 
306  /*
307  * Just convert the implicit-AND list to an explicit AND (if there's more
308  * than one entry), and compile normally. Unlike ExecQual, we can't
309  * short-circuit on NULL results, so the regular AND behavior is needed.
310  */
311  return ExecInitExpr(make_ands_explicit(qual), parent);
312 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
Expr * make_ands_explicit(List *andclauses)
Definition: makefuncs.c:708
#define Assert(condition)
Definition: c.h:804
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:123
Definition: pg_list.h:50

◆ ExecInitCoerceToDomain()

static void ExecInitCoerceToDomain ( ExprEvalStep scratch,
CoerceToDomain ctest,
ExprState state,
Datum resv,
bool resnull 
)
static

Definition at line 3136 of file execExpr.c.

References CoerceToDomain::arg, DomainConstraintState::check_expr, DomainConstraintRef::constraints, DomainConstraintState::constrainttype, CurrentMemoryContext, ExprEvalStep::d, DOM_CONSTRAINT_CHECK, DOM_CONSTRAINT_NOTNULL, ExprEvalStep::domaincheck, EEOP_DOMAIN_CHECK, EEOP_DOMAIN_NOTNULL, EEOP_MAKE_READONLY, elog, ERROR, ExecInitExprRec(), ExprEvalPushStep(), get_typlen(), InitDomainConstraintRef(), ExprState::innermost_domainnull, ExprState::innermost_domainval, lfirst, ExprEvalStep::make_readonly, DomainConstraintState::name, ExprEvalStep::opcode, palloc(), ExprEvalStep::resnull, CoerceToDomain::resulttype, and ExprEvalStep::resvalue.

Referenced by ExecInitExprRec().

3138 {
3139  DomainConstraintRef *constraint_ref;
3140  ListCell *l;
3141 
3142  scratch->d.domaincheck.resulttype = ctest->resulttype;
3143  /* we'll allocate workspace only if needed */
3144  scratch->d.domaincheck.checkvalue = NULL;
3145  scratch->d.domaincheck.checknull = NULL;
3146 
3147  /*
3148  * Evaluate argument - it's fine to directly store it into resv/resnull,
3149  * if there's constraint failures there'll be errors, otherwise it's what
3150  * needs to be returned.
3151  */
3152  ExecInitExprRec(ctest->arg, state, resv, resnull);
3153 
3154  /*
3155  * Note: if the argument is of varlena type, it could be a R/W expanded
3156  * object. We want to return the R/W pointer as the final result, but we
3157  * have to pass a R/O pointer as the value to be tested by any functions
3158  * in check expressions. We don't bother to emit a MAKE_READONLY step
3159  * unless there's actually at least one check expression, though. Until
3160  * we've tested that, domainval/domainnull are NULL.
3161  */
3162 
3163  /*
3164  * Collect the constraints associated with the domain.
3165  *
3166  * Note: before PG v10 we'd recheck the set of constraints during each
3167  * evaluation of the expression. Now we bake them into the ExprState
3168  * during executor initialization. That means we don't need typcache.c to
3169  * provide compiled exprs.
3170  */
3171  constraint_ref = (DomainConstraintRef *)
3172  palloc(sizeof(DomainConstraintRef));
3174  constraint_ref,
3176  false);
3177 
3178  /*
3179  * Compile code to check each domain constraint. NOTNULL constraints can
3180  * just be applied on the resv/resnull value, but for CHECK constraints we
3181  * need more pushups.
3182  */
3183  foreach(l, constraint_ref->constraints)
3184  {
3186  Datum *domainval = NULL;
3187  bool *domainnull = NULL;
3188  Datum *save_innermost_domainval;
3189  bool *save_innermost_domainnull;
3190 
3191  scratch->d.domaincheck.constraintname = con->name;
3192 
3193  switch (con->constrainttype)
3194  {
3196  scratch->opcode = EEOP_DOMAIN_NOTNULL;
3197  ExprEvalPushStep(state, scratch);
3198  break;
3199  case DOM_CONSTRAINT_CHECK:
3200  /* Allocate workspace for CHECK output if we didn't yet */
3201  if (scratch->d.domaincheck.checkvalue == NULL)
3202  {
3203  scratch->d.domaincheck.checkvalue =
3204  (Datum *) palloc(sizeof(Datum));
3205  scratch->d.domaincheck.checknull =
3206  (bool *) palloc(sizeof(bool));
3207  }
3208 
3209  /*
3210  * If first time through, determine where CoerceToDomainValue
3211  * nodes should read from.
3212  */
3213  if (domainval == NULL)
3214  {
3215  /*
3216  * Since value might be read multiple times, force to R/O
3217  * - but only if it could be an expanded datum.
3218  */
3219  if (get_typlen(ctest->resulttype) == -1)
3220  {
3221  ExprEvalStep scratch2 = {0};
3222 
3223  /* Yes, so make output workspace for MAKE_READONLY */
3224  domainval = (Datum *) palloc(sizeof(Datum));
3225  domainnull = (bool *) palloc(sizeof(bool));
3226 
3227  /* Emit MAKE_READONLY */
3228  scratch2.opcode = EEOP_MAKE_READONLY;
3229  scratch2.resvalue = domainval;
3230  scratch2.resnull = domainnull;
3231  scratch2.d.make_readonly.value = resv;
3232  scratch2.d.make_readonly.isnull = resnull;
3233  ExprEvalPushStep(state, &scratch2);
3234  }
3235  else
3236  {
3237  /* No, so it's fine to read from resv/resnull */
3238  domainval = resv;
3239  domainnull = resnull;
3240  }
3241  }
3242 
3243  /*
3244  * Set up value to be returned by CoerceToDomainValue nodes.
3245  * We must save and restore innermost_domainval/null fields,
3246  * in case this node is itself within a check expression for
3247  * another domain.
3248  */
3249  save_innermost_domainval = state->innermost_domainval;
3250  save_innermost_domainnull = state->innermost_domainnull;
3251  state->innermost_domainval = domainval;
3252  state->innermost_domainnull = domainnull;
3253 
3254  /* evaluate check expression value */
3255  ExecInitExprRec(con->check_expr, state,
3256  scratch->d.domaincheck.checkvalue,
3257  scratch->d.domaincheck.checknull);
3258 
3259  state->innermost_domainval = save_innermost_domainval;
3260  state->innermost_domainnull = save_innermost_domainnull;
3261 
3262  /* now test result */
3263  scratch->opcode = EEOP_DOMAIN_CHECK;
3264  ExprEvalPushStep(state, scratch);
3265 
3266  break;
3267  default:
3268  elog(ERROR, "unrecognized constraint type: %d",
3269  (int) con->constrainttype);
3270  break;
3271  }
3272  }
3273 }
Datum * resvalue
Definition: execExpr.h:273
DomainConstraintType constrainttype
Definition: execnodes.h:931
bool * resnull
Definition: execExpr.h:274
Datum * innermost_domainval
Definition: execnodes.h:115
bool * innermost_domainnull
Definition: execnodes.h:116
#define ERROR
Definition: elog.h:46
union ExprEvalStep::@49 d
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
struct ExprEvalStep::@49::@78 domaincheck
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:900
uintptr_t Datum
Definition: postgres.h:411
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2445
struct ExprEvalStep::@49::@64 make_readonly
#define lfirst(lc)
Definition: pg_list.h:169
intptr_t opcode
Definition: execExpr.h:270
void InitDomainConstraintRef(Oid type_id, DomainConstraintRef *ref, MemoryContext refctx, bool need_exprstate)
Definition: typcache.c:1305
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2144
void * palloc(Size size)
Definition: mcxt.c:1062
#define elog(elevel,...)
Definition: elog.h:232

◆ ExecInitExpr()

ExprState* ExecInitExpr ( Expr node,
PlanState parent 
)

Definition at line 123 of file execExpr.c.

References EEOP_DONE, ExecInitExprRec(), ExecInitExprSlots(), ExecReadyExpr(), ExprState::expr, ExprEvalPushStep(), ExprState::ext_params, makeNode, ExprEvalStep::opcode, ExprState::parent, ExprState::resnull, and ExprState::resvalue.

Referenced by ATRewriteTable(), BeginCopyFrom(), evaluate_expr(), ExecIndexBuildScanKeys(), ExecInitCheck(), ExecInitExprList(), ExecInitExprRec(), ExecInitLimit(), ExecInitMemoize(), ExecInitProjectSet(), ExecInitPruningContext(), ExecInitSampleScan(), ExecInitSubPlan(), ExecInitTableFuncScan(), ExecInitTableFunctionResult(), ExecInitWindowAgg(), ExecPrepareExpr(), ExecProcNode(), get_cast_hashentry(), get_qual_for_range(), MakeTidOpExpr(), MJExamineQuals(), operator_predicate_proof(), prep_domain_constraints(), slot_fill_defaults(), and TidExprListCreate().

124 {
125  ExprState *state;
126  ExprEvalStep scratch = {0};
127 
128  /* Special case: NULL expression produces a NULL ExprState pointer */
129  if (node == NULL)
130  return NULL;
131 
132  /* Initialize ExprState with empty step list */
133  state = makeNode(ExprState);
134  state->expr = node;
135  state->parent = parent;
136  state->ext_params = NULL;
137 
138  /* Insert EEOP_*_FETCHSOME steps as needed */
139  ExecInitExprSlots(state, (Node *) node);
140 
141  /* Compile the expression proper */
142  ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
143 
144  /* Finally, append a DONE step */
145  scratch.opcode = EEOP_DONE;
146  ExprEvalPushStep(state, &scratch);
147 
148  ExecReadyExpr(state);
149 
150  return state;
151 }
struct PlanState * parent
Definition: execnodes.h:109
ParamListInfo ext_params
Definition: execnodes.h:110
Definition: nodes.h:536
bool resnull
Definition: execnodes.h:73
Expr * expr
Definition: execnodes.h:95
static void ExecInitExprSlots(ExprState *state, Node *node)
Definition: execExpr.c:2576
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:900
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2445
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:883
#define makeNode(_type_)
Definition: nodes.h:584
Definition: regguts.h:317
intptr_t opcode
Definition: execExpr.h:270
Datum resvalue
Definition: execnodes.h:75

◆ ExecInitExprList()

List* ExecInitExprList ( List nodes,
PlanState parent 
)

Definition at line 318 of file execExpr.c.

References ExecInitExpr(), lappend(), lfirst, and NIL.

Referenced by ExecInitAgg(), ExecInitExprRec(), ExecInitFunctionResultSet(), ExecInitHash(), ExecInitHashJoin(), ExecInitIndexScan(), ExecInitSampleScan(), ExecInitSubPlan(), ExecInitTableFuncScan(), ExecInitTableFunctionResult(), ExecInitValuesScan(), ExecProcNode(), prepare_query_params(), and ValuesNext().

319 {
320  List *result = NIL;
321  ListCell *lc;
322 
323  foreach(lc, nodes)
324  {
325  Expr *e = lfirst(lc);
326 
327  result = lappend(result, ExecInitExpr(e, parent));
328  }
329 
330  return result;
331 }
#define NIL
Definition: pg_list.h:65
List * lappend(List *list, void *datum)
Definition: list.c:336
#define lfirst(lc)
Definition: pg_list.h:169
e
Definition: preproc-init.c:82
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:123
Definition: pg_list.h:50

◆ ExecInitExprRec()

static void ExecInitExprRec ( Expr node,
ExprState state,
Datum resv,
bool resnull 
)
static

Definition at line 900 of file execExpr.c.

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, WindowFunc::aggfilter, WindowFuncExprState::aggfilter, Aggref::aggno, ExprEvalStep::aggref, AggState::aggs, AND_EXPR, arg, FieldSelect::arg, FieldStore::arg, RelabelType::arg, CoerceViaIO::arg, ArrayCoerceExpr::arg, ConvertRowtypeExpr::arg, CaseExpr::arg, NullTest::arg, BooleanTest::arg, NullTest::argisrow, FunctionCallInfoBaseData::args, WindowFunc::args, FuncExpr::args, OpExpr::args, ScalarArrayOpExpr::args, BoolExpr::args, WindowFuncExprState::args, CaseExpr::args, RowExpr::args, CoalesceExpr::args, MinMaxExpr::args, XmlExpr::args, ExprEvalStep::arraycoerce, ExprEvalStep::arrayexpr, Assert, BlessTupleDesc(), ExprEvalStep::boolexpr, BoolExpr::boolop, BooleanTest::booltesttype, BTORDER_PROC, ExprEvalRowtypeCache::cacheptr, ExprEvalStep::casetest, check_stack_depth(), TypeCacheEntry::cmp_proc, RowExpr::colnames, GroupingFunc::cols, Const::constisnull, ExprEvalStep::constval, Const::constvalue, convert(), ExprEvalStep::convert_rowtype, ExprEvalStep::d, DecrTupleDescRefCount(), CaseExpr::defresult, EEOP_AGGREF, EEOP_ARRAYCOERCE, EEOP_ARRAYEXPR, EEOP_BOOL_AND_STEP, EEOP_BOOL_AND_STEP_FIRST, EEOP_BOOL_AND_STEP_LAST, EEOP_BOOL_NOT_STEP, EEOP_BOOL_OR_STEP, EEOP_BOOL_OR_STEP_FIRST, EEOP_BOOL_OR_STEP_LAST, EEOP_BOOLTEST_IS_FALSE, EEOP_BOOLTEST_IS_NOT_FALSE, EEOP_BOOLTEST_IS_NOT_TRUE, EEOP_BOOLTEST_IS_TRUE, EEOP_CASE_TESTVAL, EEOP_CONST, EEOP_CONVERT_ROWTYPE, EEOP_CURRENTOFEXPR, EEOP_DISTINCT, EEOP_DOMAIN_TESTVAL, EEOP_DONE, EEOP_FIELDSELECT, EEOP_FIELDSTORE_DEFORM, EEOP_FIELDSTORE_FORM, EEOP_GROUPING_FUNC, EEOP_HASHED_SCALARARRAYOP, EEOP_INNER_SYSVAR, EEOP_INNER_VAR, EEOP_IOCOERCE, EEOP_JUMP, EEOP_JUMP_IF_NOT_NULL, EEOP_JUMP_IF_NOT_TRUE, EEOP_MAKE_READONLY, EEOP_MINMAX, EEOP_NEXTVALUEEXPR, EEOP_NULLIF, EEOP_NULLTEST_ISNOTNULL, EEOP_NULLTEST_ISNULL, EEOP_NULLTEST_ROWISNOTNULL, EEOP_NULLTEST_ROWISNULL, EEOP_OUTER_SYSVAR, EEOP_OUTER_VAR, EEOP_PARAM_EXEC, EEOP_PARAM_EXTERN, EEOP_ROW, EEOP_ROWCOMPARE_FINAL, EEOP_ROWCOMPARE_STEP, EEOP_SCALARARRAYOP, EEOP_SCAN_SYSVAR, EEOP_SCAN_VAR, EEOP_SQLVALUEFUNCTION, EEOP_SUBPLAN, EEOP_WINDOW_FUNC, EEOP_XMLEXPR, ArrayExpr::element_typeid, ArrayExpr::elements, ArrayCoerceExpr::elemexpr, elog, ereport, errcode(), errmsg(), ERROR, EState::es_param_list_info, ExecInitCoerceToDomain(), ExecInitExpr(), ExecInitExprList(), ExecInitFunc(), ExecInitSubPlan(), ExecInitSubscriptingRef(), ExecInitWholeRowVar(), ExecReadyExpr(), ExecTypeFromExprList(), ExecTypeSetColNames(), ExprState::expr, CaseWhen::expr, ExprEvalPushStep(), exprType(), ExprState::ext_params, FieldSelect::fieldnum, FieldStore::fieldnums, ExprEvalStep::fieldselect, ExprEvalStep::fieldstore, fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_addr, forboth, forfive, format_type_be(), FuncExpr::funcid, WindowAggState::funcs, get_element_type(), get_func_name(), get_op_opfamily_properties(), get_opfamily_proc(), get_typlen(), get_typlenbyvalalign(), getTypeInputInfo(), getTypeOutputInfo(), GetUserId(), ExprEvalStep::grouping_func, Agg::groupingSets, ExprEvalStep::hashedscalararrayop, ScalarArrayOpExpr::hashfuncid, i, InitFunctionCallInfoData, INNER_VAR, ExprState::innermost_casenull, ExprState::innermost_caseval, ExprState::innermost_domainnull, ExprState::innermost_domainval, FuncExpr::inputcollid, OpExpr::inputcollid, ScalarArrayOpExpr::inputcollid, MinMaxExpr::inputcollid, RowCompareExpr::inputcollids, Int32GetDatum, InvalidAttrNumber, InvalidOid, InvokeFunctionExecuteHook, ExprEvalStep::iocoerce, IS_FALSE, IS_NOT_FALSE, IS_NOT_NULL, IS_NOT_TRUE, IS_NOT_UNKNOWN, IS_NULL, IS_TRUE, IS_UNKNOWN, IsA, NullableDatum::isnull, ExprEvalStep::jump, lappend(), lappend_int(), RowCompareExpr::largs, lfirst, lfirst_int, lfirst_oid, linitial, list_length(), lookup_rowtype_tupdesc(), lookup_rowtype_tupdesc_copy(), lookup_type_cache(), lsecond, ExprEvalStep::make_readonly, makeNode, makeNullConst(), Max, ExprEvalStep::minmax, MinMaxExpr::minmaxtype, ArrayExpr::multidims, XmlExpr::named_args, TupleDescData::natts, ScalarArrayOpExpr::negfuncid, FieldStore::newvals, ExprEvalStep::nextvalueexpr, NIL, nodeTag, NOT_EXPR, ExprEvalStep::nulltest_row, NullTest::nulltesttype, WindowAggState::numaggs, WindowAggState::numfuncs, OBJECT_FUNCTION, ObjectIdGetDatum, OidIsValid, MinMaxExpr::op, ExprEvalStep::opcode, RowCompareExpr::opfamilies, OpExpr::opfuncid, ScalarArrayOpExpr::opfuncid, RowCompareExpr::opnos, OR_EXPR, OUTER_VAR, palloc(), palloc0(), ExprEvalStep::param, PARAM_EXEC, PARAM_EXTERN, ParamListInfoData::paramCompile, Param::paramid, Param::paramkind, Param::paramtype, ExprState::parent, pg_proc_aclcheck(), PlanState::plan, RowCompareExpr::rargs, RowCompareExpr::rctype, ExprState::resnull, ExprEvalStep::resnull, CaseWhen::result, FieldSelect::resulttype, FieldStore::resulttype, CoerceViaIO::resulttype, ArrayCoerceExpr::resulttype, ConvertRowtypeExpr::resulttype, ExprState::resvalue, ExprEvalStep::resvalue, ExprEvalStep::row, RowExpr::row_typeid, ExprEvalStep::rowcompare_final, ExprEvalStep::rowcompare_step, ExprEvalStep::scalararrayop, NextValueExpr::seqid, SizeForFunctionCallInfo, ExprEvalStep::sqlvaluefunction, PlanState::state, ExprState::steps, ExprState::steps_len, ExprEvalStep::subplan, PlanState::subPlan, T_Aggref, T_ArrayCoerceExpr, T_ArrayExpr, T_BooleanTest, T_BoolExpr, T_CaseExpr, T_CaseTestExpr, T_CoalesceExpr, T_CoerceToDomain, T_CoerceToDomainValue, T_CoerceViaIO, T_Const, T_ConvertRowtypeExpr, T_CurrentOfExpr, T_DistinctExpr, T_FieldSelect, T_FieldStore, T_FuncExpr, T_GroupingFunc, T_MinMaxExpr, T_NextValueExpr, T_NullIfExpr, T_NullTest, T_OpExpr, T_Param, T_RelabelType, T_RowCompareExpr, T_RowExpr, T_ScalarArrayOpExpr, T_SQLValueFunction, T_SubPlan, T_SubscriptingRef, T_Var, T_WindowFunc, T_XmlExpr, TupleDescAttr, TYPECACHE_CMP_PROC, NextValueExpr::typeId, ScalarArrayOpExpr::useOr, NullableDatum::value, values, ExprEvalStep::var, Var::varattno, Var::varno, Var::vartype, WindowFuncExprState::wfunc, WindowFunc::winagg, ExprEvalStep::window_func, and ExprEvalStep::xmlexpr.

Referenced by ExecBuildAggTrans(), ExecBuildProjectionInfo(), ExecBuildUpdateProjection(), ExecInitCoerceToDomain(), ExecInitExpr(), ExecInitExprWithParams(), ExecInitFunc(), ExecInitQual(), and ExecInitSubscriptingRef().

902 {
903  ExprEvalStep scratch = {0};
904 
905  /* Guard against stack overflow due to overly complex expressions */
907 
908  /* Step's output location is always what the caller gave us */
909  Assert(resv != NULL && resnull != NULL);
910  scratch.resvalue = resv;
911  scratch.resnull = resnull;
912 
913  /* cases should be ordered as they are in enum NodeTag */
914  switch (nodeTag(node))
915  {
916  case T_Var:
917  {
918  Var *variable = (Var *) node;
919 
920  if (variable->varattno == InvalidAttrNumber)
921  {
922  /* whole-row Var */
923  ExecInitWholeRowVar(&scratch, variable, state);
924  }
925  else if (variable->varattno <= 0)
926  {
927  /* system column */
928  scratch.d.var.attnum = variable->varattno;
929  scratch.d.var.vartype = variable->vartype;
930  switch (variable->varno)
931  {
932  case INNER_VAR:
933  scratch.opcode = EEOP_INNER_SYSVAR;
934  break;
935  case OUTER_VAR:
936  scratch.opcode = EEOP_OUTER_SYSVAR;
937  break;
938 
939  /* INDEX_VAR is handled by default case */
940 
941  default:
942  scratch.opcode = EEOP_SCAN_SYSVAR;
943  break;
944  }
945  }
946  else
947  {
948  /* regular user column */
949  scratch.d.var.attnum = variable->varattno - 1;
950  scratch.d.var.vartype = variable->vartype;
951  switch (variable->varno)
952  {
953  case INNER_VAR:
954  scratch.opcode = EEOP_INNER_VAR;
955  break;
956  case OUTER_VAR:
957  scratch.opcode = EEOP_OUTER_VAR;
958  break;
959 
960  /* INDEX_VAR is handled by default case */
961 
962  default:
963  scratch.opcode = EEOP_SCAN_VAR;
964  break;
965  }
966  }
967 
968  ExprEvalPushStep(state, &scratch);
969  break;
970  }
971 
972  case T_Const:
973  {
974  Const *con = (Const *) node;
975 
976  scratch.opcode = EEOP_CONST;
977  scratch.d.constval.value = con->constvalue;
978  scratch.d.constval.isnull = con->constisnull;
979 
980  ExprEvalPushStep(state, &scratch);
981  break;
982  }
983 
984  case T_Param:
985  {
986  Param *param = (Param *) node;
987  ParamListInfo params;
988 
989  switch (param->paramkind)
990  {
991  case PARAM_EXEC:
992  scratch.opcode = EEOP_PARAM_EXEC;
993  scratch.d.param.paramid = param->paramid;
994  scratch.d.param.paramtype = param->paramtype;
995  ExprEvalPushStep(state, &scratch);
996  break;
997  case PARAM_EXTERN:
998 
999  /*
1000  * If we have a relevant ParamCompileHook, use it;
1001  * otherwise compile a standard EEOP_PARAM_EXTERN
1002  * step. ext_params, if supplied, takes precedence
1003  * over info from the parent node's EState (if any).
1004  */
1005  if (state->ext_params)
1006  params = state->ext_params;
1007  else if (state->parent &&
1008  state->parent->state)
1009  params = state->parent->state->es_param_list_info;
1010  else
1011  params = NULL;
1012  if (params && params->paramCompile)
1013  {
1014  params->paramCompile(params, param, state,
1015  resv, resnull);
1016  }
1017  else
1018  {
1019  scratch.opcode = EEOP_PARAM_EXTERN;
1020  scratch.d.param.paramid = param->paramid;
1021  scratch.d.param.paramtype = param->paramtype;
1022  ExprEvalPushStep(state, &scratch);
1023  }
1024  break;
1025  default:
1026  elog(ERROR, "unrecognized paramkind: %d",
1027  (int) param->paramkind);
1028  break;
1029  }
1030  break;
1031  }
1032 
1033  case T_Aggref:
1034  {
1035  Aggref *aggref = (Aggref *) node;
1036 
1037  scratch.opcode = EEOP_AGGREF;
1038  scratch.d.aggref.aggno = aggref->aggno;
1039 
1040  if (state->parent && IsA(state->parent, AggState))
1041  {
1042  AggState *aggstate = (AggState *) state->parent;
1043 
1044  aggstate->aggs = lappend(aggstate->aggs, aggref);
1045  }
1046  else
1047  {
1048  /* planner messed up */
1049  elog(ERROR, "Aggref found in non-Agg plan node");
1050  }
1051 
1052  ExprEvalPushStep(state, &scratch);
1053  break;
1054  }
1055 
1056  case T_GroupingFunc:
1057  {
1058  GroupingFunc *grp_node = (GroupingFunc *) node;
1059  Agg *agg;
1060 
1061  if (!state->parent || !IsA(state->parent, AggState) ||
1062  !IsA(state->parent->plan, Agg))
1063  elog(ERROR, "GroupingFunc found in non-Agg plan node");
1064 
1065  scratch.opcode = EEOP_GROUPING_FUNC;
1066 
1067  agg = (Agg *) (state->parent->plan);
1068 
1069  if (agg->groupingSets)
1070  scratch.d.grouping_func.clauses = grp_node->cols;
1071  else
1072  scratch.d.grouping_func.clauses = NIL;
1073 
1074  ExprEvalPushStep(state, &scratch);
1075  break;
1076  }
1077 
1078  case T_WindowFunc:
1079  {
1080  WindowFunc *wfunc = (WindowFunc *) node;
1082 
1083  wfstate->wfunc = wfunc;
1084 
1085  if (state->parent && IsA(state->parent, WindowAggState))
1086  {
1087  WindowAggState *winstate = (WindowAggState *) state->parent;
1088  int nfuncs;
1089 
1090  winstate->funcs = lappend(winstate->funcs, wfstate);
1091  nfuncs = ++winstate->numfuncs;
1092  if (wfunc->winagg)
1093  winstate->numaggs++;
1094 
1095  /* for now initialize agg using old style expressions */
1096  wfstate->args = ExecInitExprList(wfunc->args,
1097  state->parent);
1098  wfstate->aggfilter = ExecInitExpr(wfunc->aggfilter,
1099  state->parent);
1100 
1101  /*
1102  * Complain if the windowfunc's arguments contain any
1103  * windowfuncs; nested window functions are semantically
1104  * nonsensical. (This should have been caught earlier,
1105  * but we defend against it here anyway.)
1106  */
1107  if (nfuncs != winstate->numfuncs)
1108  ereport(ERROR,
1109  (errcode(ERRCODE_WINDOWING_ERROR),
1110  errmsg("window function calls cannot be nested")));
1111  }
1112  else
1113  {
1114  /* planner messed up */
1115  elog(ERROR, "WindowFunc found in non-WindowAgg plan node");
1116  }
1117 
1118  scratch.opcode = EEOP_WINDOW_FUNC;
1119  scratch.d.window_func.wfstate = wfstate;
1120  ExprEvalPushStep(state, &scratch);
1121  break;
1122  }
1123 
1124  case T_SubscriptingRef:
1125  {
1126  SubscriptingRef *sbsref = (SubscriptingRef *) node;
1127 
1128  ExecInitSubscriptingRef(&scratch, sbsref, state, resv, resnull);
1129  break;
1130  }
1131 
1132  case T_FuncExpr:
1133  {
1134  FuncExpr *func = (FuncExpr *) node;
1135 
1136  ExecInitFunc(&scratch, node,
1137  func->args, func->funcid, func->inputcollid,
1138  state);
1139  ExprEvalPushStep(state, &scratch);
1140  break;
1141  }
1142 
1143  case T_OpExpr:
1144  {
1145  OpExpr *op = (OpExpr *) node;
1146 
1147  ExecInitFunc(&scratch, node,
1148  op->args, op->opfuncid, op->inputcollid,
1149  state);
1150  ExprEvalPushStep(state, &scratch);
1151  break;
1152  }
1153 
1154  case T_DistinctExpr:
1155  {
1156  DistinctExpr *op = (DistinctExpr *) node;
1157 
1158  ExecInitFunc(&scratch, node,
1159  op->args, op->opfuncid, op->inputcollid,
1160  state);
1161 
1162  /*
1163  * Change opcode of call instruction to EEOP_DISTINCT.
1164  *
1165  * XXX: historically we've not called the function usage
1166  * pgstat infrastructure - that seems inconsistent given that
1167  * we do so for normal function *and* operator evaluation. If
1168  * we decided to do that here, we'd probably want separate
1169  * opcodes for FUSAGE or not.
1170  */
1171  scratch.opcode = EEOP_DISTINCT;
1172  ExprEvalPushStep(state, &scratch);
1173  break;
1174  }
1175 
1176  case T_NullIfExpr:
1177  {
1178  NullIfExpr *op = (NullIfExpr *) node;
1179 
1180  ExecInitFunc(&scratch, node,
1181  op->args, op->opfuncid, op->inputcollid,
1182  state);
1183 
1184  /*
1185  * Change opcode of call instruction to EEOP_NULLIF.
1186  *
1187  * XXX: historically we've not called the function usage
1188  * pgstat infrastructure - that seems inconsistent given that
1189  * we do so for normal function *and* operator evaluation. If
1190  * we decided to do that here, we'd probably want separate
1191  * opcodes for FUSAGE or not.
1192  */
1193  scratch.opcode = EEOP_NULLIF;
1194  ExprEvalPushStep(state, &scratch);
1195  break;
1196  }
1197 
1198  case T_ScalarArrayOpExpr:
1199  {
1200  ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
1201  Expr *scalararg;
1202  Expr *arrayarg;
1203  FmgrInfo *finfo;
1204  FunctionCallInfo fcinfo;
1205  AclResult aclresult;
1206  FmgrInfo *hash_finfo;
1207  FunctionCallInfo hash_fcinfo;
1208  Oid cmpfuncid;
1209 
1210  /*
1211  * Select the correct comparison function. When we do hashed
1212  * NOT IN clauses, the opfuncid will be the inequality
1213  * comparison function and negfuncid will be set to equality.
1214  * We need to use the equality function for hash probes.
1215  */
1216  if (OidIsValid(opexpr->negfuncid))
1217  {
1218  Assert(OidIsValid(opexpr->hashfuncid));
1219  cmpfuncid = opexpr->negfuncid;
1220  }
1221  else
1222  cmpfuncid = opexpr->opfuncid;
1223 
1224  Assert(list_length(opexpr->args) == 2);
1225  scalararg = (Expr *) linitial(opexpr->args);
1226  arrayarg = (Expr *) lsecond(opexpr->args);
1227 
1228  /* Check permission to call function */
1229  aclresult = pg_proc_aclcheck(cmpfuncid,
1230  GetUserId(),
1231  ACL_EXECUTE);
1232  if (aclresult != ACLCHECK_OK)
1233  aclcheck_error(aclresult, OBJECT_FUNCTION,
1234  get_func_name(cmpfuncid));
1235  InvokeFunctionExecuteHook(cmpfuncid);
1236 
1237  if (OidIsValid(opexpr->hashfuncid))
1238  {
1239  aclresult = pg_proc_aclcheck(opexpr->hashfuncid,
1240  GetUserId(),
1241  ACL_EXECUTE);
1242  if (aclresult != ACLCHECK_OK)
1243  aclcheck_error(aclresult, OBJECT_FUNCTION,
1244  get_func_name(opexpr->hashfuncid));
1246  }
1247 
1248  /* Set up the primary fmgr lookup information */
1249  finfo = palloc0(sizeof(FmgrInfo));
1250  fcinfo = palloc0(SizeForFunctionCallInfo(2));
1251  fmgr_info(cmpfuncid, finfo);
1252  fmgr_info_set_expr((Node *) node, finfo);
1253  InitFunctionCallInfoData(*fcinfo, finfo, 2,
1254  opexpr->inputcollid, NULL, NULL);
1255 
1256  /*
1257  * If hashfuncid is set, we create a EEOP_HASHED_SCALARARRAYOP
1258  * step instead of a EEOP_SCALARARRAYOP. This provides much
1259  * faster lookup performance than the normal linear search
1260  * when the number of items in the array is anything but very
1261  * small.
1262  */
1263  if (OidIsValid(opexpr->hashfuncid))
1264  {
1265  hash_finfo = palloc0(sizeof(FmgrInfo));
1266  hash_fcinfo = palloc0(SizeForFunctionCallInfo(1));
1267  fmgr_info(opexpr->hashfuncid, hash_finfo);
1268  fmgr_info_set_expr((Node *) node, hash_finfo);
1269  InitFunctionCallInfoData(*hash_fcinfo, hash_finfo,
1270  1, opexpr->inputcollid, NULL,
1271  NULL);
1272 
1273  scratch.d.hashedscalararrayop.hash_finfo = hash_finfo;
1274  scratch.d.hashedscalararrayop.hash_fcinfo_data = hash_fcinfo;
1275  scratch.d.hashedscalararrayop.hash_fn_addr = hash_finfo->fn_addr;
1276 
1277  /* Evaluate scalar directly into left function argument */
1278  ExecInitExprRec(scalararg, state,
1279  &fcinfo->args[0].value, &fcinfo->args[0].isnull);
1280 
1281  /*
1282  * Evaluate array argument into our return value. There's
1283  * no danger in that, because the return value is
1284  * guaranteed to be overwritten by
1285  * EEOP_HASHED_SCALARARRAYOP, and will not be passed to
1286  * any other expression.
1287  */
1288  ExecInitExprRec(arrayarg, state, resv, resnull);
1289 
1290  /* And perform the operation */
1292  scratch.d.hashedscalararrayop.inclause = opexpr->useOr;
1293  scratch.d.hashedscalararrayop.finfo = finfo;
1294  scratch.d.hashedscalararrayop.fcinfo_data = fcinfo;
1295  scratch.d.hashedscalararrayop.fn_addr = finfo->fn_addr;
1296 
1297  scratch.d.hashedscalararrayop.hash_finfo = hash_finfo;
1298  scratch.d.hashedscalararrayop.hash_fcinfo_data = hash_fcinfo;
1299  scratch.d.hashedscalararrayop.hash_fn_addr = hash_finfo->fn_addr;
1300 
1301  ExprEvalPushStep(state, &scratch);
1302  }
1303  else
1304  {
1305  /* Evaluate scalar directly into left function argument */
1306  ExecInitExprRec(scalararg, state,
1307  &fcinfo->args[0].value,
1308  &fcinfo->args[0].isnull);
1309 
1310  /*
1311  * Evaluate array argument into our return value. There's
1312  * no danger in that, because the return value is
1313  * guaranteed to be overwritten by EEOP_SCALARARRAYOP, and
1314  * will not be passed to any other expression.
1315  */
1316  ExecInitExprRec(arrayarg, state, resv, resnull);
1317 
1318  /* And perform the operation */
1319  scratch.opcode = EEOP_SCALARARRAYOP;
1320  scratch.d.scalararrayop.element_type = InvalidOid;
1321  scratch.d.scalararrayop.useOr = opexpr->useOr;
1322  scratch.d.scalararrayop.finfo = finfo;
1323  scratch.d.scalararrayop.fcinfo_data = fcinfo;
1324  scratch.d.scalararrayop.fn_addr = finfo->fn_addr;
1325  ExprEvalPushStep(state, &scratch);
1326  }
1327  break;
1328  }
1329 
1330  case T_BoolExpr:
1331  {
1332  BoolExpr *boolexpr = (BoolExpr *) node;
1333  int nargs = list_length(boolexpr->args);
1334  List *adjust_jumps = NIL;
1335  int off;
1336  ListCell *lc;
1337 
1338  /* allocate scratch memory used by all steps of AND/OR */
1339  if (boolexpr->boolop != NOT_EXPR)
1340  scratch.d.boolexpr.anynull = (bool *) palloc(sizeof(bool));
1341 
1342  /*
1343  * For each argument evaluate the argument itself, then
1344  * perform the bool operation's appropriate handling.
1345  *
1346  * We can evaluate each argument into our result area, since
1347  * the short-circuiting logic means we only need to remember
1348  * previous NULL values.
1349  *
1350  * AND/OR is split into separate STEP_FIRST (one) / STEP (zero
1351  * or more) / STEP_LAST (one) steps, as each of those has to
1352  * perform different work. The FIRST/LAST split is valid
1353  * because AND/OR have at least two arguments.
1354  */
1355  off = 0;
1356  foreach(lc, boolexpr->args)
1357  {
1358  Expr *arg = (Expr *) lfirst(lc);
1359 
1360  /* Evaluate argument into our output variable */
1361  ExecInitExprRec(arg, state, resv, resnull);
1362 
1363  /* Perform the appropriate step type */
1364  switch (boolexpr->boolop)
1365  {
1366  case AND_EXPR:
1367  Assert(nargs >= 2);
1368 
1369  if (off == 0)
1370  scratch.opcode = EEOP_BOOL_AND_STEP_FIRST;
1371  else if (off + 1 == nargs)
1372  scratch.opcode = EEOP_BOOL_AND_STEP_LAST;
1373  else
1374  scratch.opcode = EEOP_BOOL_AND_STEP;
1375  break;
1376  case OR_EXPR:
1377  Assert(nargs >= 2);
1378 
1379  if (off == 0)
1380  scratch.opcode = EEOP_BOOL_OR_STEP_FIRST;
1381  else if (off + 1 == nargs)
1382  scratch.opcode = EEOP_BOOL_OR_STEP_LAST;
1383  else
1384  scratch.opcode = EEOP_BOOL_OR_STEP;
1385  break;
1386  case NOT_EXPR:
1387  Assert(nargs == 1);
1388 
1389  scratch.opcode = EEOP_BOOL_NOT_STEP;
1390  break;
1391  default:
1392  elog(ERROR, "unrecognized boolop: %d",
1393  (int) boolexpr->boolop);
1394  break;
1395  }
1396 
1397  scratch.d.boolexpr.jumpdone = -1;
1398  ExprEvalPushStep(state, &scratch);
1399  adjust_jumps = lappend_int(adjust_jumps,
1400  state->steps_len - 1);
1401  off++;
1402  }
1403 
1404  /* adjust jump targets */
1405  foreach(lc, adjust_jumps)
1406  {
1407  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
1408 
1409  Assert(as->d.boolexpr.jumpdone == -1);
1410  as->d.boolexpr.jumpdone = state->steps_len;
1411  }
1412 
1413  break;
1414  }
1415 
1416  case T_SubPlan:
1417  {
1418  SubPlan *subplan = (SubPlan *) node;
1419  SubPlanState *sstate;
1420 
1421  if (!state->parent)
1422  elog(ERROR, "SubPlan found with no parent plan");
1423 
1424  sstate = ExecInitSubPlan(subplan, state->parent);
1425 
1426  /* add SubPlanState nodes to state->parent->subPlan */
1427  state->parent->subPlan = lappend(state->parent->subPlan,
1428  sstate);
1429 
1430  scratch.opcode = EEOP_SUBPLAN;
1431  scratch.d.subplan.sstate = sstate;
1432 
1433  ExprEvalPushStep(state, &scratch);
1434  break;
1435  }
1436 
1437  case T_FieldSelect:
1438  {
1439  FieldSelect *fselect = (FieldSelect *) node;
1440 
1441  /* evaluate row/record argument into result area */
1442  ExecInitExprRec(fselect->arg, state, resv, resnull);
1443 
1444  /* and extract field */
1445  scratch.opcode = EEOP_FIELDSELECT;
1446  scratch.d.fieldselect.fieldnum = fselect->fieldnum;
1447  scratch.d.fieldselect.resulttype = fselect->resulttype;
1448  scratch.d.fieldselect.rowcache.cacheptr = NULL;
1449 
1450  ExprEvalPushStep(state, &scratch);
1451  break;
1452  }
1453 
1454  case T_FieldStore:
1455  {
1456  FieldStore *fstore = (FieldStore *) node;
1457  TupleDesc tupDesc;
1458  ExprEvalRowtypeCache *rowcachep;
1459  Datum *values;
1460  bool *nulls;
1461  int ncolumns;
1462  ListCell *l1,
1463  *l2;
1464 
1465  /* find out the number of columns in the composite type */
1466  tupDesc = lookup_rowtype_tupdesc(fstore->resulttype, -1);
1467  ncolumns = tupDesc->natts;
1468  DecrTupleDescRefCount(tupDesc);
1469 
1470  /* create workspace for column values */
1471  values = (Datum *) palloc(sizeof(Datum) * ncolumns);
1472  nulls = (bool *) palloc(sizeof(bool) * ncolumns);
1473 
1474  /* create shared composite-type-lookup cache struct */
1475  rowcachep = palloc(sizeof(ExprEvalRowtypeCache));
1476  rowcachep->cacheptr = NULL;
1477 
1478  /* emit code to evaluate the composite input value */
1479  ExecInitExprRec(fstore->arg, state, resv, resnull);
1480 
1481  /* next, deform the input tuple into our workspace */
1482  scratch.opcode = EEOP_FIELDSTORE_DEFORM;
1483  scratch.d.fieldstore.fstore = fstore;
1484  scratch.d.fieldstore.rowcache = rowcachep;
1485  scratch.d.fieldstore.values = values;
1486  scratch.d.fieldstore.nulls = nulls;
1487  scratch.d.fieldstore.ncolumns = ncolumns;
1488  ExprEvalPushStep(state, &scratch);
1489 
1490  /* evaluate new field values, store in workspace columns */
1491  forboth(l1, fstore->newvals, l2, fstore->fieldnums)
1492  {
1493  Expr *e = (Expr *) lfirst(l1);
1494  AttrNumber fieldnum = lfirst_int(l2);
1495  Datum *save_innermost_caseval;
1496  bool *save_innermost_casenull;
1497 
1498  if (fieldnum <= 0 || fieldnum > ncolumns)
1499  elog(ERROR, "field number %d is out of range in FieldStore",
1500  fieldnum);
1501 
1502  /*
1503  * Use the CaseTestExpr mechanism to pass down the old
1504  * value of the field being replaced; this is needed in
1505  * case the newval is itself a FieldStore or
1506  * SubscriptingRef that has to obtain and modify the old
1507  * value. It's safe to reuse the CASE mechanism because
1508  * there cannot be a CASE between here and where the value
1509  * would be needed, and a field assignment can't be within
1510  * a CASE either. (So saving and restoring
1511  * innermost_caseval is just paranoia, but let's do it
1512  * anyway.)
1513  *
1514  * Another non-obvious point is that it's safe to use the
1515  * field's values[]/nulls[] entries as both the caseval
1516  * source and the result address for this subexpression.
1517  * That's okay only because (1) both FieldStore and
1518  * SubscriptingRef evaluate their arg or refexpr inputs
1519  * first, and (2) any such CaseTestExpr is directly the
1520  * arg or refexpr input. So any read of the caseval will
1521  * occur before there's a chance to overwrite it. Also,
1522  * if multiple entries in the newvals/fieldnums lists
1523  * target the same field, they'll effectively be applied
1524  * left-to-right which is what we want.
1525  */
1526  save_innermost_caseval = state->innermost_caseval;
1527  save_innermost_casenull = state->innermost_casenull;
1528  state->innermost_caseval = &values[fieldnum - 1];
1529  state->innermost_casenull = &nulls[fieldnum - 1];
1530 
1531  ExecInitExprRec(e, state,
1532  &values[fieldnum - 1],
1533  &nulls[fieldnum - 1]);
1534 
1535  state->innermost_caseval = save_innermost_caseval;
1536  state->innermost_casenull = save_innermost_casenull;
1537  }
1538 
1539  /* finally, form result tuple */
1540  scratch.opcode = EEOP_FIELDSTORE_FORM;
1541  scratch.d.fieldstore.fstore = fstore;
1542  scratch.d.fieldstore.rowcache = rowcachep;
1543  scratch.d.fieldstore.values = values;
1544  scratch.d.fieldstore.nulls = nulls;
1545  scratch.d.fieldstore.ncolumns = ncolumns;
1546  ExprEvalPushStep(state, &scratch);
1547  break;
1548  }
1549 
1550  case T_RelabelType:
1551  {
1552  /* relabel doesn't need to do anything at runtime */
1553  RelabelType *relabel = (RelabelType *) node;
1554 
1555  ExecInitExprRec(relabel->arg, state, resv, resnull);
1556  break;
1557  }
1558 
1559  case T_CoerceViaIO:
1560  {
1561  CoerceViaIO *iocoerce = (CoerceViaIO *) node;
1562  Oid iofunc;
1563  bool typisvarlena;
1564  Oid typioparam;
1565  FunctionCallInfo fcinfo_in;
1566 
1567  /* evaluate argument into step's result area */
1568  ExecInitExprRec(iocoerce->arg, state, resv, resnull);
1569 
1570  /*
1571  * Prepare both output and input function calls, to be
1572  * evaluated inside a single evaluation step for speed - this
1573  * can be a very common operation.
1574  *
1575  * We don't check permissions here as a type's input/output
1576  * function are assumed to be executable by everyone.
1577  */
1578  scratch.opcode = EEOP_IOCOERCE;
1579 
1580  /* lookup the source type's output function */
1581  scratch.d.iocoerce.finfo_out = palloc0(sizeof(FmgrInfo));
1582  scratch.d.iocoerce.fcinfo_data_out = palloc0(SizeForFunctionCallInfo(1));
1583 
1584  getTypeOutputInfo(exprType((Node *) iocoerce->arg),
1585  &iofunc, &typisvarlena);
1586  fmgr_info(iofunc, scratch.d.iocoerce.finfo_out);
1587  fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_out);
1588  InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_out,
1589  scratch.d.iocoerce.finfo_out,
1590  1, InvalidOid, NULL, NULL);
1591 
1592  /* lookup the result type's input function */
1593  scratch.d.iocoerce.finfo_in = palloc0(sizeof(FmgrInfo));
1594  scratch.d.iocoerce.fcinfo_data_in = palloc0(SizeForFunctionCallInfo(3));
1595 
1596  getTypeInputInfo(iocoerce->resulttype,
1597  &iofunc, &typioparam);
1598  fmgr_info(iofunc, scratch.d.iocoerce.finfo_in);
1599  fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_in);
1600  InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_in,
1601  scratch.d.iocoerce.finfo_in,
1602  3, InvalidOid, NULL, NULL);
1603 
1604  /*
1605  * We can preload the second and third arguments for the input
1606  * function, since they're constants.
1607  */
1608  fcinfo_in = scratch.d.iocoerce.fcinfo_data_in;
1609  fcinfo_in->args[1].value = ObjectIdGetDatum(typioparam);
1610  fcinfo_in->args[1].isnull = false;
1611  fcinfo_in->args[2].value = Int32GetDatum(-1);
1612  fcinfo_in->args[2].isnull = false;
1613 
1614  ExprEvalPushStep(state, &scratch);
1615  break;
1616  }
1617 
1618  case T_ArrayCoerceExpr:
1619  {
1620  ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
1621  Oid resultelemtype;
1622  ExprState *elemstate;
1623 
1624  /* evaluate argument into step's result area */
1625  ExecInitExprRec(acoerce->arg, state, resv, resnull);
1626 
1627  resultelemtype = get_element_type(acoerce->resulttype);
1628  if (!OidIsValid(resultelemtype))
1629  ereport(ERROR,
1630  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1631  errmsg("target type is not an array")));
1632 
1633  /*
1634  * Construct a sub-expression for the per-element expression;
1635  * but don't ready it until after we check it for triviality.
1636  * We assume it hasn't any Var references, but does have a
1637  * CaseTestExpr representing the source array element values.
1638  */
1639  elemstate = makeNode(ExprState);
1640  elemstate->expr = acoerce->elemexpr;
1641  elemstate->parent = state->parent;
1642  elemstate->ext_params = state->ext_params;
1643 
1644  elemstate->innermost_caseval = (Datum *) palloc(sizeof(Datum));
1645  elemstate->innermost_casenull = (bool *) palloc(sizeof(bool));
1646 
1647  ExecInitExprRec(acoerce->elemexpr, elemstate,
1648  &elemstate->resvalue, &elemstate->resnull);
1649 
1650  if (elemstate->steps_len == 1 &&
1651  elemstate->steps[0].opcode == EEOP_CASE_TESTVAL)
1652  {
1653  /* Trivial, so we need no per-element work at runtime */
1654  elemstate = NULL;
1655  }
1656  else
1657  {
1658  /* Not trivial, so append a DONE step */
1659  scratch.opcode = EEOP_DONE;
1660  ExprEvalPushStep(elemstate, &scratch);
1661  /* and ready the subexpression */
1662  ExecReadyExpr(elemstate);
1663  }
1664 
1665  scratch.opcode = EEOP_ARRAYCOERCE;
1666  scratch.d.arraycoerce.elemexprstate = elemstate;
1667  scratch.d.arraycoerce.resultelemtype = resultelemtype;
1668 
1669  if (elemstate)
1670  {
1671  /* Set up workspace for array_map */
1672  scratch.d.arraycoerce.amstate =
1673  (ArrayMapState *) palloc0(sizeof(ArrayMapState));
1674  }
1675  else
1676  {
1677  /* Don't need workspace if there's no subexpression */
1678  scratch.d.arraycoerce.amstate = NULL;
1679  }
1680 
1681  ExprEvalPushStep(state, &scratch);
1682  break;
1683  }
1684 
1685  case T_ConvertRowtypeExpr:
1686  {
1688  ExprEvalRowtypeCache *rowcachep;
1689 
1690  /* cache structs must be out-of-line for space reasons */
1691  rowcachep = palloc(2 * sizeof(ExprEvalRowtypeCache));
1692  rowcachep[0].cacheptr = NULL;
1693  rowcachep[1].cacheptr = NULL;
1694 
1695  /* evaluate argument into step's result area */
1696  ExecInitExprRec(convert->arg, state, resv, resnull);
1697 
1698  /* and push conversion step */
1699  scratch.opcode = EEOP_CONVERT_ROWTYPE;
1700  scratch.d.convert_rowtype.inputtype =
1701  exprType((Node *) convert->arg);
1702  scratch.d.convert_rowtype.outputtype = convert->resulttype;
1703  scratch.d.convert_rowtype.incache = &rowcachep[0];
1704  scratch.d.convert_rowtype.outcache = &rowcachep[1];
1705  scratch.d.convert_rowtype.map = NULL;
1706 
1707  ExprEvalPushStep(state, &scratch);
1708  break;
1709  }
1710 
1711  /* note that CaseWhen expressions are handled within this block */
1712  case T_CaseExpr:
1713  {
1714  CaseExpr *caseExpr = (CaseExpr *) node;
1715  List *adjust_jumps = NIL;
1716  Datum *caseval = NULL;
1717  bool *casenull = NULL;
1718  ListCell *lc;
1719 
1720  /*
1721  * If there's a test expression, we have to evaluate it and
1722  * save the value where the CaseTestExpr placeholders can find
1723  * it.
1724  */
1725  if (caseExpr->arg != NULL)
1726  {
1727  /* Evaluate testexpr into caseval/casenull workspace */
1728  caseval = palloc(sizeof(Datum));
1729  casenull = palloc(sizeof(bool));
1730 
1731  ExecInitExprRec(caseExpr->arg, state,
1732  caseval, casenull);
1733 
1734  /*
1735  * Since value might be read multiple times, force to R/O
1736  * - but only if it could be an expanded datum.
1737  */
1738  if (get_typlen(exprType((Node *) caseExpr->arg)) == -1)
1739  {
1740  /* change caseval in-place */
1741  scratch.opcode = EEOP_MAKE_READONLY;
1742  scratch.resvalue = caseval;
1743  scratch.resnull = casenull;
1744  scratch.d.make_readonly.value = caseval;
1745  scratch.d.make_readonly.isnull = casenull;
1746  ExprEvalPushStep(state, &scratch);
1747  /* restore normal settings of scratch fields */
1748  scratch.resvalue = resv;
1749  scratch.resnull = resnull;
1750  }
1751  }
1752 
1753  /*
1754  * Prepare to evaluate each of the WHEN clauses in turn; as
1755  * soon as one is true we return the value of the
1756  * corresponding THEN clause. If none are true then we return
1757  * the value of the ELSE clause, or NULL if there is none.
1758  */
1759  foreach(lc, caseExpr->args)
1760  {
1761  CaseWhen *when = (CaseWhen *) lfirst(lc);
1762  Datum *save_innermost_caseval;
1763  bool *save_innermost_casenull;
1764  int whenstep;
1765 
1766  /*
1767  * Make testexpr result available to CaseTestExpr nodes
1768  * within the condition. We must save and restore prior
1769  * setting of innermost_caseval fields, in case this node
1770  * is itself within a larger CASE.
1771  *
1772  * If there's no test expression, we don't actually need
1773  * to save and restore these fields; but it's less code to
1774  * just do so unconditionally.
1775  */
1776  save_innermost_caseval = state->innermost_caseval;
1777  save_innermost_casenull = state->innermost_casenull;
1778  state->innermost_caseval = caseval;
1779  state->innermost_casenull = casenull;
1780 
1781  /* evaluate condition into CASE's result variables */
1782  ExecInitExprRec(when->expr, state, resv, resnull);
1783 
1784  state->innermost_caseval = save_innermost_caseval;
1785  state->innermost_casenull = save_innermost_casenull;
1786 
1787  /* If WHEN result isn't true, jump to next CASE arm */
1788  scratch.opcode = EEOP_JUMP_IF_NOT_TRUE;
1789  scratch.d.jump.jumpdone = -1; /* computed later */
1790  ExprEvalPushStep(state, &scratch);
1791  whenstep = state->steps_len - 1;
1792 
1793  /*
1794  * If WHEN result is true, evaluate THEN result, storing
1795  * it into the CASE's result variables.
1796  */
1797  ExecInitExprRec(when->result, state, resv, resnull);
1798 
1799  /* Emit JUMP step to jump to end of CASE's code */
1800  scratch.opcode = EEOP_JUMP;
1801  scratch.d.jump.jumpdone = -1; /* computed later */
1802  ExprEvalPushStep(state, &scratch);
1803 
1804  /*
1805  * Don't know address for that jump yet, compute once the
1806  * whole CASE expression is built.
1807  */
1808  adjust_jumps = lappend_int(adjust_jumps,
1809  state->steps_len - 1);
1810 
1811  /*
1812  * But we can set WHEN test's jump target now, to make it
1813  * jump to the next WHEN subexpression or the ELSE.
1814  */
1815  state->steps[whenstep].d.jump.jumpdone = state->steps_len;
1816  }
1817 
1818  /* transformCaseExpr always adds a default */
1819  Assert(caseExpr->defresult);
1820 
1821  /* evaluate ELSE expr into CASE's result variables */
1822  ExecInitExprRec(caseExpr->defresult, state,
1823  resv, resnull);
1824 
1825  /* adjust jump targets */
1826  foreach(lc, adjust_jumps)
1827  {
1828  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
1829 
1830  Assert(as->opcode == EEOP_JUMP);
1831  Assert(as->d.jump.jumpdone == -1);
1832  as->d.jump.jumpdone = state->steps_len;
1833  }
1834 
1835  break;
1836  }
1837 
1838  case T_CaseTestExpr:
1839  {
1840  /*
1841  * Read from location identified by innermost_caseval. Note
1842  * that innermost_caseval could be NULL, if this node isn't
1843  * actually within a CaseExpr, ArrayCoerceExpr, etc structure.
1844  * That can happen because some parts of the system abuse
1845  * CaseTestExpr to cause a read of a value externally supplied
1846  * in econtext->caseValue_datum. We'll take care of that
1847  * scenario at runtime.
1848  */
1849  scratch.opcode = EEOP_CASE_TESTVAL;
1850  scratch.d.casetest.value = state->innermost_caseval;
1851  scratch.d.casetest.isnull = state->innermost_casenull;
1852 
1853  ExprEvalPushStep(state, &scratch);
1854  break;
1855  }
1856 
1857  case T_ArrayExpr:
1858  {
1859  ArrayExpr *arrayexpr = (ArrayExpr *) node;
1860  int nelems = list_length(arrayexpr->elements);
1861  ListCell *lc;
1862  int elemoff;
1863 
1864  /*
1865  * Evaluate by computing each element, and then forming the
1866  * array. Elements are computed into scratch arrays
1867  * associated with the ARRAYEXPR step.
1868  */
1869  scratch.opcode = EEOP_ARRAYEXPR;
1870  scratch.d.arrayexpr.elemvalues =
1871  (Datum *) palloc(sizeof(Datum) * nelems);
1872  scratch.d.arrayexpr.elemnulls =
1873  (bool *) palloc(sizeof(bool) * nelems);
1874  scratch.d.arrayexpr.nelems = nelems;
1875 
1876  /* fill remaining fields of step */
1877  scratch.d.arrayexpr.multidims = arrayexpr->multidims;
1878  scratch.d.arrayexpr.elemtype = arrayexpr->element_typeid;
1879 
1880  /* do one-time catalog lookup for type info */
1882  &scratch.d.arrayexpr.elemlength,
1883  &scratch.d.arrayexpr.elembyval,
1884  &scratch.d.arrayexpr.elemalign);
1885 
1886  /* prepare to evaluate all arguments */
1887  elemoff = 0;
1888  foreach(lc, arrayexpr->elements)
1889  {
1890  Expr *e = (Expr *) lfirst(lc);
1891 
1892  ExecInitExprRec(e, state,
1893  &scratch.d.arrayexpr.elemvalues[elemoff],
1894  &scratch.d.arrayexpr.elemnulls[elemoff]);
1895  elemoff++;
1896  }
1897 
1898  /* and then collect all into an array */
1899  ExprEvalPushStep(state, &scratch);
1900  break;
1901  }
1902 
1903  case T_RowExpr:
1904  {
1905  RowExpr *rowexpr = (RowExpr *) node;
1906  int nelems = list_length(rowexpr->args);
1907  TupleDesc tupdesc;
1908  int i;
1909  ListCell *l;
1910 
1911  /* Build tupdesc to describe result tuples */
1912  if (rowexpr->row_typeid == RECORDOID)
1913  {
1914  /* generic record, use types of given expressions */
1915  tupdesc = ExecTypeFromExprList(rowexpr->args);
1916  }
1917  else
1918  {
1919  /* it's been cast to a named type, use that */
1920  tupdesc = lookup_rowtype_tupdesc_copy(rowexpr->row_typeid, -1);
1921  }
1922  /* In either case, adopt RowExpr's column aliases */
1923  ExecTypeSetColNames(tupdesc, rowexpr->colnames);
1924  /* Bless the tupdesc in case it's now of type RECORD */
1925  BlessTupleDesc(tupdesc);
1926 
1927  /*
1928  * In the named-type case, the tupdesc could have more columns
1929  * than are in the args list, since the type might have had
1930  * columns added since the ROW() was parsed. We want those
1931  * extra columns to go to nulls, so we make sure that the
1932  * workspace arrays are large enough and then initialize any
1933  * extra columns to read as NULLs.
1934  */
1935  Assert(nelems <= tupdesc->natts);
1936  nelems = Max(nelems, tupdesc->natts);
1937 
1938  /*
1939  * Evaluate by first building datums for each field, and then
1940  * a final step forming the composite datum.
1941  */
1942  scratch.opcode = EEOP_ROW;
1943  scratch.d.row.tupdesc = tupdesc;
1944 
1945  /* space for the individual field datums */
1946  scratch.d.row.elemvalues =
1947  (Datum *) palloc(sizeof(Datum) * nelems);
1948  scratch.d.row.elemnulls =
1949  (bool *) palloc(sizeof(bool) * nelems);
1950  /* as explained above, make sure any extra columns are null */
1951  memset(scratch.d.row.elemnulls, true, sizeof(bool) * nelems);
1952 
1953  /* Set up evaluation, skipping any deleted columns */
1954  i = 0;
1955  foreach(l, rowexpr->args)
1956  {
1957  Form_pg_attribute att = TupleDescAttr(tupdesc, i);
1958  Expr *e = (Expr *) lfirst(l);
1959 
1960  if (!att->attisdropped)
1961  {
1962  /*
1963  * Guard against ALTER COLUMN TYPE on rowtype since
1964  * the RowExpr was created. XXX should we check
1965  * typmod too? Not sure we can be sure it'll be the
1966  * same.
1967  */
1968  if (exprType((Node *) e) != att->atttypid)
1969  ereport(ERROR,
1970  (errcode(ERRCODE_DATATYPE_MISMATCH),
1971  errmsg("ROW() column has type %s instead of type %s",
1972  format_type_be(exprType((Node *) e)),
1973  format_type_be(att->atttypid))));
1974  }
1975  else
1976  {
1977  /*
1978  * Ignore original expression and insert a NULL. We
1979  * don't really care what type of NULL it is, so
1980  * always make an int4 NULL.
1981  */
1982  e = (Expr *) makeNullConst(INT4OID, -1, InvalidOid);
1983  }
1984 
1985  /* Evaluate column expr into appropriate workspace slot */
1986  ExecInitExprRec(e, state,
1987  &scratch.d.row.elemvalues[i],
1988  &scratch.d.row.elemnulls[i]);
1989  i++;
1990  }
1991 
1992  /* And finally build the row value */
1993  ExprEvalPushStep(state, &scratch);
1994  break;
1995  }
1996 
1997  case T_RowCompareExpr:
1998  {
1999  RowCompareExpr *rcexpr = (RowCompareExpr *) node;
2000  int nopers = list_length(rcexpr->opnos);
2001  List *adjust_jumps = NIL;
2002  ListCell *l_left_expr,
2003  *l_right_expr,
2004  *l_opno,
2005  *l_opfamily,
2006  *l_inputcollid;
2007  ListCell *lc;
2008 
2009  /*
2010  * Iterate over each field, prepare comparisons. To handle
2011  * NULL results, prepare jumps to after the expression. If a
2012  * comparison yields a != 0 result, jump to the final step.
2013  */
2014  Assert(list_length(rcexpr->largs) == nopers);
2015  Assert(list_length(rcexpr->rargs) == nopers);
2016  Assert(list_length(rcexpr->opfamilies) == nopers);
2017  Assert(list_length(rcexpr->inputcollids) == nopers);
2018 
2019  forfive(l_left_expr, rcexpr->largs,
2020  l_right_expr, rcexpr->rargs,
2021  l_opno, rcexpr->opnos,
2022  l_opfamily, rcexpr->opfamilies,
2023  l_inputcollid, rcexpr->inputcollids)
2024  {
2025  Expr *left_expr = (Expr *) lfirst(l_left_expr);
2026  Expr *right_expr = (Expr *) lfirst(l_right_expr);
2027  Oid opno = lfirst_oid(l_opno);
2028  Oid opfamily = lfirst_oid(l_opfamily);
2029  Oid inputcollid = lfirst_oid(l_inputcollid);
2030  int strategy;
2031  Oid lefttype;
2032  Oid righttype;
2033  Oid proc;
2034  FmgrInfo *finfo;
2035  FunctionCallInfo fcinfo;
2036 
2037  get_op_opfamily_properties(opno, opfamily, false,
2038  &strategy,
2039  &lefttype,
2040  &righttype);
2041  proc = get_opfamily_proc(opfamily,
2042  lefttype,
2043  righttype,
2044  BTORDER_PROC);
2045  if (!OidIsValid(proc))
2046  elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
2047  BTORDER_PROC, lefttype, righttype, opfamily);
2048 
2049  /* Set up the primary fmgr lookup information */
2050  finfo = palloc0(sizeof(FmgrInfo));
2051  fcinfo = palloc0(SizeForFunctionCallInfo(2));
2052  fmgr_info(proc, finfo);
2053  fmgr_info_set_expr((Node *) node, finfo);
2054  InitFunctionCallInfoData(*fcinfo, finfo, 2,
2055  inputcollid, NULL, NULL);
2056 
2057  /*
2058  * If we enforced permissions checks on index support
2059  * functions, we'd need to make a check here. But the
2060  * index support machinery doesn't do that, and thus
2061  * neither does this code.
2062  */
2063 
2064  /* evaluate left and right args directly into fcinfo */
2065  ExecInitExprRec(left_expr, state,
2066  &fcinfo->args[0].value, &fcinfo->args[0].isnull);
2067  ExecInitExprRec(right_expr, state,
2068  &fcinfo->args[1].value, &fcinfo->args[1].isnull);
2069 
2070  scratch.opcode = EEOP_ROWCOMPARE_STEP;
2071  scratch.d.rowcompare_step.finfo = finfo;
2072  scratch.d.rowcompare_step.fcinfo_data = fcinfo;
2073  scratch.d.rowcompare_step.fn_addr = finfo->fn_addr;
2074  /* jump targets filled below */
2075  scratch.d.rowcompare_step.jumpnull = -1;
2076  scratch.d.rowcompare_step.jumpdone = -1;
2077 
2078  ExprEvalPushStep(state, &scratch);
2079  adjust_jumps = lappend_int(adjust_jumps,
2080  state->steps_len - 1);
2081  }
2082 
2083  /*
2084  * We could have a zero-column rowtype, in which case the rows
2085  * necessarily compare equal.
2086  */
2087  if (nopers == 0)
2088  {
2089  scratch.opcode = EEOP_CONST;
2090  scratch.d.constval.value = Int32GetDatum(0);
2091  scratch.d.constval.isnull = false;
2092  ExprEvalPushStep(state, &scratch);
2093  }
2094 
2095  /* Finally, examine the last comparison result */
2096  scratch.opcode = EEOP_ROWCOMPARE_FINAL;
2097  scratch.d.rowcompare_final.rctype = rcexpr->rctype;
2098  ExprEvalPushStep(state, &scratch);
2099 
2100  /* adjust jump targets */
2101  foreach(lc, adjust_jumps)
2102  {
2103  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
2104 
2106  Assert(as->d.rowcompare_step.jumpdone == -1);
2107  Assert(as->d.rowcompare_step.jumpnull == -1);
2108 
2109  /* jump to comparison evaluation */
2110  as->d.rowcompare_step.jumpdone = state->steps_len - 1;
2111  /* jump to the following expression */
2112  as->d.rowcompare_step.jumpnull = state->steps_len;
2113  }
2114 
2115  break;
2116  }
2117 
2118  case T_CoalesceExpr:
2119  {
2120  CoalesceExpr *coalesce = (CoalesceExpr *) node;
2121  List *adjust_jumps = NIL;
2122  ListCell *lc;
2123 
2124  /* We assume there's at least one arg */
2125  Assert(coalesce->args != NIL);
2126 
2127  /*
2128  * Prepare evaluation of all coalesced arguments, after each
2129  * one push a step that short-circuits if not null.
2130  */
2131  foreach(lc, coalesce->args)
2132  {
2133  Expr *e = (Expr *) lfirst(lc);
2134 
2135  /* evaluate argument, directly into result datum */
2136  ExecInitExprRec(e, state, resv, resnull);
2137 
2138  /* if it's not null, skip to end of COALESCE expr */
2139  scratch.opcode = EEOP_JUMP_IF_NOT_NULL;
2140  scratch.d.jump.jumpdone = -1; /* adjust later */
2141  ExprEvalPushStep(state, &scratch);
2142 
2143  adjust_jumps = lappend_int(adjust_jumps,
2144  state->steps_len - 1);
2145  }
2146 
2147  /*
2148  * No need to add a constant NULL return - we only can get to
2149  * the end of the expression if a NULL already is being
2150  * returned.
2151  */
2152 
2153  /* adjust jump targets */
2154  foreach(lc, adjust_jumps)
2155  {
2156  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
2157 
2159  Assert(as->d.jump.jumpdone == -1);
2160  as->d.jump.jumpdone = state->steps_len;
2161  }
2162 
2163  break;
2164  }
2165 
2166  case T_MinMaxExpr:
2167  {
2168  MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
2169  int nelems = list_length(minmaxexpr->args);
2170  TypeCacheEntry *typentry;
2171  FmgrInfo *finfo;
2172  FunctionCallInfo fcinfo;
2173  ListCell *lc;
2174  int off;
2175 
2176  /* Look up the btree comparison function for the datatype */
2177  typentry = lookup_type_cache(minmaxexpr->minmaxtype,
2179  if (!OidIsValid(typentry->cmp_proc))
2180  ereport(ERROR,
2181  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2182  errmsg("could not identify a comparison function for type %s",
2183  format_type_be(minmaxexpr->minmaxtype))));
2184 
2185  /*
2186  * If we enforced permissions checks on index support
2187  * functions, we'd need to make a check here. But the index
2188  * support machinery doesn't do that, and thus neither does
2189  * this code.
2190  */
2191 
2192  /* Perform function lookup */
2193  finfo = palloc0(sizeof(FmgrInfo));
2194  fcinfo = palloc0(SizeForFunctionCallInfo(2));
2195  fmgr_info(typentry->cmp_proc, finfo);
2196  fmgr_info_set_expr((Node *) node, finfo);
2197  InitFunctionCallInfoData(*fcinfo, finfo, 2,
2198  minmaxexpr->inputcollid, NULL, NULL);
2199 
2200  scratch.opcode = EEOP_MINMAX;
2201  /* allocate space to store arguments */
2202  scratch.d.minmax.values =
2203  (Datum *) palloc(sizeof(Datum) * nelems);
2204  scratch.d.minmax.nulls =
2205  (bool *) palloc(sizeof(bool) * nelems);
2206  scratch.d.minmax.nelems = nelems;
2207 
2208  scratch.d.minmax.op = minmaxexpr->op;
2209  scratch.d.minmax.finfo = finfo;
2210  scratch.d.minmax.fcinfo_data = fcinfo;
2211 
2212  /* evaluate expressions into minmax->values/nulls */
2213  off = 0;
2214  foreach(lc, minmaxexpr->args)
2215  {
2216  Expr *e = (Expr *) lfirst(lc);
2217 
2218  ExecInitExprRec(e, state,
2219  &scratch.d.minmax.values[off],
2220  &scratch.d.minmax.nulls[off]);
2221  off++;
2222  }
2223 
2224  /* and push the final comparison */
2225  ExprEvalPushStep(state, &scratch);
2226  break;
2227  }
2228 
2229  case T_SQLValueFunction:
2230  {
2231  SQLValueFunction *svf = (SQLValueFunction *) node;
2232 
2233  scratch.opcode = EEOP_SQLVALUEFUNCTION;
2234  scratch.d.sqlvaluefunction.svf = svf;
2235 
2236  ExprEvalPushStep(state, &scratch);
2237  break;
2238  }
2239 
2240  case T_XmlExpr:
2241  {
2242  XmlExpr *xexpr = (XmlExpr *) node;
2243  int nnamed = list_length(xexpr->named_args);
2244  int nargs = list_length(xexpr->args);
2245  int off;
2246  ListCell *arg;
2247 
2248  scratch.opcode = EEOP_XMLEXPR;
2249  scratch.d.xmlexpr.xexpr = xexpr;
2250 
2251  /* allocate space for storing all the arguments */
2252  if (nnamed)
2253  {
2254  scratch.d.xmlexpr.named_argvalue =
2255  (Datum *) palloc(sizeof(Datum) * nnamed);
2256  scratch.d.xmlexpr.named_argnull =
2257  (bool *) palloc(sizeof(bool) * nnamed);
2258  }
2259  else
2260  {
2261  scratch.d.xmlexpr.named_argvalue = NULL;
2262  scratch.d.xmlexpr.named_argnull = NULL;
2263  }
2264 
2265  if (nargs)
2266  {
2267  scratch.d.xmlexpr.argvalue =
2268  (Datum *) palloc(sizeof(Datum) * nargs);
2269  scratch.d.xmlexpr.argnull =
2270  (bool *) palloc(sizeof(bool) * nargs);
2271  }
2272  else
2273  {
2274  scratch.d.xmlexpr.argvalue = NULL;
2275  scratch.d.xmlexpr.argnull = NULL;
2276  }
2277 
2278  /* prepare argument execution */
2279  off = 0;
2280  foreach(arg, xexpr->named_args)
2281  {
2282  Expr *e = (Expr *) lfirst(arg);
2283 
2284  ExecInitExprRec(e, state,
2285  &scratch.d.xmlexpr.named_argvalue[off],
2286  &scratch.d.xmlexpr.named_argnull[off]);
2287  off++;
2288  }
2289 
2290  off = 0;
2291  foreach(arg, xexpr->args)
2292  {
2293  Expr *e = (Expr *) lfirst(arg);
2294 
2295  ExecInitExprRec(e, state,
2296  &scratch.d.xmlexpr.argvalue[off],
2297  &scratch.d.xmlexpr.argnull[off]);
2298  off++;
2299  }
2300 
2301  /* and evaluate the actual XML expression */
2302  ExprEvalPushStep(state, &scratch);
2303  break;
2304  }
2305 
2306  case T_NullTest:
2307  {
2308  NullTest *ntest = (NullTest *) node;
2309 
2310  if (ntest->nulltesttype == IS_NULL)
2311  {
2312  if (ntest->argisrow)
2313  scratch.opcode = EEOP_NULLTEST_ROWISNULL;
2314  else
2315  scratch.opcode = EEOP_NULLTEST_ISNULL;
2316  }
2317  else if (ntest->nulltesttype == IS_NOT_NULL)
2318  {
2319  if (ntest->argisrow)
2321  else
2322  scratch.opcode = EEOP_NULLTEST_ISNOTNULL;
2323  }
2324  else
2325  {
2326  elog(ERROR, "unrecognized nulltesttype: %d",
2327  (int) ntest->nulltesttype);
2328  }
2329  /* initialize cache in case it's a row test */
2330  scratch.d.nulltest_row.rowcache.cacheptr = NULL;
2331 
2332  /* first evaluate argument into result variable */
2333  ExecInitExprRec(ntest->arg, state,
2334  resv, resnull);
2335 
2336  /* then push the test of that argument */
2337  ExprEvalPushStep(state, &scratch);
2338  break;
2339  }
2340 
2341  case T_BooleanTest:
2342  {
2343  BooleanTest *btest = (BooleanTest *) node;
2344 
2345  /*
2346  * Evaluate argument, directly into result datum. That's ok,
2347  * because resv/resnull is definitely not used anywhere else,
2348  * and will get overwritten by the below EEOP_BOOLTEST_IS_*
2349  * step.
2350  */
2351  ExecInitExprRec(btest->arg, state, resv, resnull);
2352 
2353  switch (btest->booltesttype)
2354  {
2355  case IS_TRUE:
2356  scratch.opcode = EEOP_BOOLTEST_IS_TRUE;
2357  break;
2358  case IS_NOT_TRUE:
2360  break;
2361  case IS_FALSE:
2362  scratch.opcode = EEOP_BOOLTEST_IS_FALSE;
2363  break;
2364  case IS_NOT_FALSE:
2366  break;
2367  case IS_UNKNOWN:
2368  /* Same as scalar IS NULL test */
2369  scratch.opcode = EEOP_NULLTEST_ISNULL;
2370  break;
2371  case IS_NOT_UNKNOWN:
2372  /* Same as scalar IS NOT NULL test */
2373  scratch.opcode = EEOP_NULLTEST_ISNOTNULL;
2374  break;
2375  default:
2376  elog(ERROR, "unrecognized booltesttype: %d",
2377  (int) btest->booltesttype);
2378  }
2379 
2380  ExprEvalPushStep(state, &scratch);
2381  break;
2382  }
2383 
2384  case T_CoerceToDomain:
2385  {
2386  CoerceToDomain *ctest = (CoerceToDomain *) node;
2387 
2388  ExecInitCoerceToDomain(&scratch, ctest, state,
2389  resv, resnull);
2390  break;
2391  }
2392 
2393  case T_CoerceToDomainValue:
2394  {
2395  /*
2396  * Read from location identified by innermost_domainval. Note
2397  * that innermost_domainval could be NULL, if we're compiling
2398  * a standalone domain check rather than one embedded in a
2399  * larger expression. In that case we must read from
2400  * econtext->domainValue_datum. We'll take care of that
2401  * scenario at runtime.
2402  */
2403  scratch.opcode = EEOP_DOMAIN_TESTVAL;
2404  /* we share instruction union variant with case testval */
2405  scratch.d.casetest.value = state->innermost_domainval;
2406  scratch.d.casetest.isnull = state->innermost_domainnull;
2407 
2408  ExprEvalPushStep(state, &scratch);
2409  break;
2410  }
2411 
2412  case T_CurrentOfExpr:
2413  {
2414  scratch.opcode = EEOP_CURRENTOFEXPR;
2415  ExprEvalPushStep(state, &scratch);
2416  break;
2417  }
2418 
2419  case T_NextValueExpr:
2420  {
2421  NextValueExpr *nve = (NextValueExpr *) node;
2422 
2423  scratch.opcode = EEOP_NEXTVALUEEXPR;
2424  scratch.d.nextvalueexpr.seqid = nve->seqid;
2425  scratch.d.nextvalueexpr.seqtypid = nve->typeId;
2426 
2427  ExprEvalPushStep(state, &scratch);
2428  break;
2429  }
2430 
2431  default:
2432  elog(ERROR, "unrecognized node type: %d",
2433  (int) nodeTag(node));
2434  break;
2435  }
2436 }
Datum constvalue
Definition: primnodes.h:219
Oid minmaxtype
Definition: primnodes.h:1148
struct ExprEvalStep::@49::@86 subplan
bool multidims
Definition: primnodes.h:1038
int varno
Definition: primnodes.h:189
#define NIL
Definition: pg_list.h:65
static void ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:3136
Definition: fmgr.h:56
List * args
Definition: primnodes.h:1152
struct ExprEvalStep::@49::@80 scalararrayop
List * args
Definition: primnodes.h:1068
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
static void ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, ExprState *state)
Definition: execExpr.c:2790
#define BTORDER_PROC
Definition: nbtree.h:700
Expr * arg
Definition: primnodes.h:837
struct PlanState * parent
Definition: execnodes.h:109
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:446
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2854
ExprState * aggfilter
Definition: execnodes.h:797
List * args
Definition: primnodes.h:390
List * args
Definition: primnodes.h:503
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1827
Datum * resvalue
Definition: execExpr.h:273
Oid GetUserId(void)
Definition: miscinit.c:495
Oid resulttype
Definition: primnodes.h:810
PGFunction fn_addr
Definition: fmgr.h:58
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2706
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2218
struct ExprEvalStep * steps
Definition: execnodes.h:86
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
struct ExprEvalStep::@49::@57 boolexpr
bool * innermost_casenull
Definition: execnodes.h:113
Oid resulttype
Definition: primnodes.h:881
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
RowCompareType rctype
Definition: primnodes.h:1116
List * opfamilies
Definition: primnodes.h:1118
bool * resnull
Definition: execExpr.h:274
List * subPlan
Definition: execnodes.h:994
ParamListInfo ext_params
Definition: execnodes.h:110
Expr * arg
Definition: primnodes.h:860
ParamKind paramkind
Definition: primnodes.h:267
struct ExprEvalStep::@49::@72 rowcompare_final
Definition: nodes.h:536
int errcode(int sqlerrcode)
Definition: elog.c:698
struct ExprEvalStep::@49::@74 fieldselect
AttrNumber varattno
Definition: primnodes.h:191
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
Expr * arg
Definition: primnodes.h:808
struct ExprEvalStep::@49::@83 aggref
struct ExprEvalStep::@49::@67 nextvalueexpr
Datum * innermost_domainval
Definition: execnodes.h:115
EState * state
Definition: execnodes.h:969
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:186
#define OidIsValid(objectId)
Definition: c.h:710
struct ExprEvalStep::@49::@71 rowcompare_step
#define lsecond(l)
Definition: pg_list.h:179
struct ExprEvalStep::@49::@51 var
bool * innermost_domainnull
Definition: execnodes.h:116
SubPlanState * ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
Definition: nodeSubplan.c:789
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:337
static void ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:2863
ParamCompileHook paramCompile
Definition: params.h:114
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3308
static void convert(const int32 val, char *const buf)
Definition: zic.c:1990
#define linitial(l)
Definition: pg_list.h:174
struct ExprEvalStep::@49::@85 window_func
Oid funcid
Definition: primnodes.h:495
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
List * colnames
Definition: primnodes.h:1084
bool resnull
Definition: execnodes.h:73
union ExprEvalStep::@49 d
Expr * expr
Definition: execnodes.h:95
#define lfirst_int(lc)
Definition: pg_list.h:170
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1579
Oid vartype
Definition: primnodes.h:193
List * args
Definition: primnodes.h:1132
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
struct ExprEvalStep::@49::@61 param
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
BoolExprType boolop
Definition: primnodes.h:625
Expr * arg
Definition: primnodes.h:1265
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2082
struct ExprEvalStep::@49::@55 constval
struct ExprEvalStep::@49::@79 convert_rowtype
void check_stack_depth(void)
Definition: postgres.c:3469
Expr * arg
Definition: primnodes.h:1288
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:318
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
Oid resulttype
Definition: primnodes.h:840
Expr * arg
Definition: primnodes.h:880
List * elements
Definition: primnodes.h:1037
Expr * elemexpr
Definition: primnodes.h:905
Definition: type.h:82
Datum * innermost_caseval
Definition: execnodes.h:112
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2821
Datum value
Definition: postgres.h:422
List * lappend_int(List *list, int datum)
Definition: list.c:354
List * newvals
Definition: primnodes.h:838
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:191
List * cols
Definition: primnodes.h:375
Definition: nodes.h:157
List * lappend(List *list, void *datum)
Definition: list.c:336
struct ExprEvalStep::@49::@84 grouping_func
Definition: nodes.h:156
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:900
struct ExprEvalStep::@49::@69 arraycoerce
List * args
Definition: primnodes.h:979
void * palloc0(Size size)
Definition: mcxt.c:1093
AclResult
Definition: acl.h:177
struct ExprEvalStep::@49::@75 fieldstore
BoolTestType booltesttype
Definition: primnodes.h:1289
uintptr_t Datum
Definition: postgres.h:411
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2445
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:883
Oid opfuncid
Definition: primnodes.h:543
struct ExprEvalStep::@49::@63 casetest
List * groupingSets
Definition: plannodes.h:873
NullTestType nulltesttype
Definition: primnodes.h:1266
struct ExprEvalStep::@49::@64 make_readonly
Plan * plan
Definition: execnodes.h:967
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:339
#define InvalidOid
Definition: postgres_ext.h:36
List * named_args
Definition: primnodes.h:1229
#define ereport(elevel,...)
Definition: elog.h:157
#define INNER_VAR
Definition: primnodes.h:175
List * args
Definition: primnodes.h:1231
#define TYPECACHE_CMP_PROC
Definition: typcache.h:139
struct ExprEvalStep::@49::@82 xmlexpr
int aggno
Definition: primnodes.h:340
#define Max(x, y)
Definition: c.h:980
#define makeNode(_type_)
Definition: nodes.h:584
Oid inputcollid
Definition: primnodes.h:502
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
struct ExprEvalStep::@49::@81 hashedscalararrayop
intptr_t opcode
Definition: execExpr.h:270
Expr * aggfilter
Definition: primnodes.h:391
void DecrTupleDescRefCount(TupleDesc tupdesc)
Definition: tupdesc.c:384
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:794
int paramid
Definition: primnodes.h:268
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
struct ExprEvalStep::@49::@60 nulltest_row
Oid row_typeid
Definition: primnodes.h:1069
static int list_length(const List *l)
Definition: pg_list.h:149
Oid inputcollid
Definition: primnodes.h:1150
Oid inputcollid
Definition: primnodes.h:547
static void ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, Oid inputcollid, ExprState *state)
Definition: execExpr.c:2471
struct ExprEvalStep::@49::@66 sqlvaluefunction
List * args
Definition: primnodes.h:626
#define InvalidAttrNumber
Definition: attnum.h:23
#define nodeTag(nodeptr)
Definition: nodes.h:541
Oid element_typeid
Definition: primnodes.h:1036
struct ExprEvalStep::@49::@59 jump
struct ExprEvalStep::@49::@70 row
static Datum values[MAXATTR]
Definition: bootstrap.c:156
struct ExprEvalStep::@49::@68 arrayexpr
#define Int32GetDatum(X)
Definition: postgres.h:523
e
Definition: preproc-init.c:82
void get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op, int *strategy, Oid *lefttype, Oid *righttype)
Definition: lsyscache.c:134
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2144
TupleDesc ExecTypeFromExprList(List *exprList)
Definition: execTuples.c:1997
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
int steps_len
Definition: execnodes.h:105
#define ACL_EXECUTE
Definition: parsenodes.h:89
List * fieldnums
Definition: primnodes.h:839
bool winagg
Definition: primnodes.h:394
#define elog(elevel,...)
Definition: elog.h:232
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4718
#define forfive(cell1, list1, cell2, list2, cell3, list3, cell4, list4, cell5, list5)
Definition: pg_list.h:516
int i
void * arg
ParamListInfo es_param_list_info
Definition: execnodes.h:595
bool argisrow
Definition: primnodes.h:1267
MinMaxOp op
Definition: primnodes.h:1151
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:123
Expr * arg
Definition: primnodes.h:978
Definition: plannodes.h:860
struct ExprEvalStep::@49::@65 iocoerce
WindowFunc * wfunc
Definition: execnodes.h:795
List * aggs
Definition: execnodes.h:2278
Expr * result
Definition: primnodes.h:991
List * args
Definition: primnodes.h:548
List * inputcollids
Definition: primnodes.h:1119
Expr * defresult
Definition: primnodes.h:980
Expr * expr
Definition: primnodes.h:990
Definition: pg_list.h:50
Datum resvalue
Definition: execnodes.h:75
int16 AttrNumber
Definition: attnum.h:21
#define OUTER_VAR
Definition: primnodes.h:176
void ExecTypeSetColNames(TupleDesc typeInfo, List *namesList)
Definition: execTuples.c:2036
Oid paramtype
Definition: primnodes.h:269
struct ExprEvalStep::@49::@73 minmax
bool constisnull
Definition: primnodes.h:220
#define lfirst_oid(lc)
Definition: pg_list.h:171
TupleDesc lookup_rowtype_tupdesc_copy(Oid type_id, int32 typmod)
Definition: typcache.c:1861
Definition: nodes.h:158
AttrNumber fieldnum
Definition: primnodes.h:809

◆ ExecInitExprSlots()

static void ExecInitExprSlots ( ExprState state,
Node node 
)
static

Definition at line 2576 of file execExpr.c.

References ExecPushExprSlots(), and get_last_attnums_walker().

Referenced by ExecBuildProjectionInfo(), ExecInitExpr(), ExecInitExprWithParams(), and ExecInitQual().

2577 {
2578  LastAttnumInfo info = {0, 0, 0};
2579 
2580  /*
2581  * Figure out which attributes we're going to need.
2582  */
2583  get_last_attnums_walker(node, &info);
2584 
2585  ExecPushExprSlots(state, &info);
2586 }
static void ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
Definition: execExpr.c:2594
static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info)
Definition: execExpr.c:2638

◆ ExecInitExprWithParams()

ExprState* ExecInitExprWithParams ( Expr node,
ParamListInfo  ext_params 
)

Definition at line 160 of file execExpr.c.

References EEOP_DONE, ExecInitExprRec(), ExecInitExprSlots(), ExecReadyExpr(), ExprState::expr, ExprEvalPushStep(), ExprState::ext_params, makeNode, ExprEvalStep::opcode, ExprState::parent, ExprState::resnull, and ExprState::resvalue.

Referenced by exec_eval_simple_expr(), and ExecProcNode().

161 {
162  ExprState *state;
163  ExprEvalStep scratch = {0};
164 
165  /* Special case: NULL expression produces a NULL ExprState pointer */
166  if (node == NULL)
167  return NULL;
168 
169  /* Initialize ExprState with empty step list */
170  state = makeNode(ExprState);
171  state->expr = node;
172  state->parent = NULL;
173  state->ext_params = ext_params;
174 
175  /* Insert EEOP_*_FETCHSOME steps as needed */
176  ExecInitExprSlots(state, (Node *) node);
177 
178  /* Compile the expression proper */
179  ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
180 
181  /* Finally, append a DONE step */
182  scratch.opcode = EEOP_DONE;
183  ExprEvalPushStep(state, &scratch);
184 
185  ExecReadyExpr(state);
186 
187  return state;
188 }
struct PlanState * parent
Definition: execnodes.h:109
ParamListInfo ext_params
Definition: execnodes.h:110
Definition: nodes.h:536
bool resnull
Definition: execnodes.h:73
Expr * expr
Definition: execnodes.h:95
static void ExecInitExprSlots(ExprState *state, Node *node)
Definition: execExpr.c:2576
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:900
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2445
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:883
#define makeNode(_type_)
Definition: nodes.h:584
Definition: regguts.h:317
intptr_t opcode
Definition: execExpr.h:270
Datum resvalue
Definition: execnodes.h:75

◆ ExecInitFunc()

static void ExecInitFunc ( ExprEvalStep scratch,
Expr node,
List args,
Oid  funcid,
Oid  inputcollid,
ExprState state 
)
static

Definition at line 2471 of file execExpr.c.

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, arg, FunctionCallInfoBaseData::args, Const::constisnull, Const::constvalue, ExprEvalStep::d, EEOP_FUNCEXPR, EEOP_FUNCEXPR_FUSAGE, EEOP_FUNCEXPR_STRICT, EEOP_FUNCEXPR_STRICT_FUSAGE, ereport, errcode(), errmsg(), errmsg_plural(), ERROR, ExecInitExprRec(), executor_errposition(), exprLocation(), fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_addr, FmgrInfo::fn_retset, FmgrInfo::fn_strict, ExprEvalStep::func, FUNC_MAX_ARGS, get_func_name(), GetUserId(), InitFunctionCallInfoData, InvokeFunctionExecuteHook, IsA, NullableDatum::isnull, lfirst, list_length(), OBJECT_FUNCTION, ExprEvalStep::opcode, palloc0(), ExprState::parent, pg_proc_aclcheck(), SizeForFunctionCallInfo, PlanState::state, and NullableDatum::value.

Referenced by ExecInitExprRec().

2473 {
2474  int nargs = list_length(args);
2475  AclResult aclresult;
2476  FmgrInfo *flinfo;
2477  FunctionCallInfo fcinfo;
2478  int argno;
2479  ListCell *lc;
2480 
2481  /* Check permission to call function */
2482  aclresult = pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE);
2483  if (aclresult != ACLCHECK_OK)
2484  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(funcid));
2485  InvokeFunctionExecuteHook(funcid);
2486 
2487  /*
2488  * Safety check on nargs. Under normal circumstances this should never
2489  * fail, as parser should check sooner. But possibly it might fail if
2490  * server has been compiled with FUNC_MAX_ARGS smaller than some functions
2491  * declared in pg_proc?
2492  */
2493  if (nargs > FUNC_MAX_ARGS)
2494  ereport(ERROR,
2495  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2496  errmsg_plural("cannot pass more than %d argument to a function",
2497  "cannot pass more than %d arguments to a function",
2498  FUNC_MAX_ARGS,
2499  FUNC_MAX_ARGS)));
2500 
2501  /* Allocate function lookup data and parameter workspace for this call */
2502  scratch->d.func.finfo = palloc0(sizeof(FmgrInfo));
2503  scratch->d.func.fcinfo_data = palloc0(SizeForFunctionCallInfo(nargs));
2504  flinfo = scratch->d.func.finfo;
2505  fcinfo = scratch->d.func.fcinfo_data;
2506 
2507  /* Set up the primary fmgr lookup information */
2508  fmgr_info(funcid, flinfo);
2509  fmgr_info_set_expr((Node *) node, flinfo);
2510 
2511  /* Initialize function call parameter structure too */
2512  InitFunctionCallInfoData(*fcinfo, flinfo,
2513  nargs, inputcollid, NULL, NULL);
2514 
2515  /* Keep extra copies of this info to save an indirection at runtime */
2516  scratch->d.func.fn_addr = flinfo->fn_addr;
2517  scratch->d.func.nargs = nargs;
2518 
2519  /* We only support non-set functions here */
2520  if (flinfo->fn_retset)
2521  ereport(ERROR,
2522  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2523  errmsg("set-valued function called in context that cannot accept a set"),
2524  state->parent ?
2526  exprLocation((Node *) node)) : 0));
2527 
2528  /* Build code to evaluate arguments directly into the fcinfo struct */
2529  argno = 0;
2530  foreach(lc, args)
2531  {
2532  Expr *arg = (Expr *) lfirst(lc);
2533 
2534  if (IsA(arg, Const))
2535  {
2536  /*
2537  * Don't evaluate const arguments every round; especially
2538  * interesting for constants in comparisons.
2539  */
2540  Const *con = (Const *) arg;
2541 
2542  fcinfo->args[argno].value = con->constvalue;
2543  fcinfo->args[argno].isnull = con->constisnull;
2544  }
2545  else
2546  {
2547  ExecInitExprRec(arg, state,
2548  &fcinfo->args[argno].value,
2549  &fcinfo->args[argno].isnull);
2550  }
2551  argno++;
2552  }
2553 
2554  /* Insert appropriate opcode depending on strictness and stats level */
2555  if (pgstat_track_functions <= flinfo->fn_stats)
2556  {
2557  if (flinfo->fn_strict && nargs > 0)
2558  scratch->opcode = EEOP_FUNCEXPR_STRICT;
2559  else
2560  scratch->opcode = EEOP_FUNCEXPR;
2561  }
2562  else
2563  {
2564  if (flinfo->fn_strict && nargs > 0)
2566  else
2567  scratch->opcode = EEOP_FUNCEXPR_FUSAGE;
2568  }
2569 }
Datum constvalue
Definition: primnodes.h:219
Definition: fmgr.h:56
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
struct PlanState * parent
Definition: execnodes.h:109
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1250
Oid GetUserId(void)
Definition: miscinit.c:495
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1019
PGFunction fn_addr
Definition: fmgr.h:58
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
Definition: nodes.h:536
int errcode(int sqlerrcode)
Definition: elog.c:698
EState * state
Definition: execnodes.h:969
#define FUNC_MAX_ARGS
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3308
bool fn_retset
Definition: fmgr.h:62
#define ERROR
Definition: elog.h:46
bool fn_strict
Definition: fmgr.h:61
union ExprEvalStep::@49 d
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1579
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
Datum value
Definition: postgres.h:422
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:191
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:900
void * palloc0(Size size)
Definition: mcxt.c:1093
AclResult
Definition: acl.h:177
struct ExprEvalStep::@49::@56 func
#define ereport(elevel,...)
Definition: elog.h:157
int executor_errposition(EState *estate, int location)
Definition: execUtils.c:898
#define lfirst(lc)
Definition: pg_list.h:169
intptr_t opcode
Definition: execExpr.h:270
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
static int list_length(const List *l)
Definition: pg_list.h:149
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define ACL_EXECUTE
Definition: parsenodes.h:89
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4718
void * arg
bool constisnull
Definition: primnodes.h:220

◆ ExecInitQual()

ExprState* ExecInitQual ( List qual,
PlanState parent 
)

Definition at line 209 of file execExpr.c.

References Assert, ExprEvalStep::d, EEO_FLAG_IS_QUAL, EEOP_DONE, EEOP_QUAL, ExecInitExprRec(), ExecInitExprSlots(), ExecReadyExpr(), ExprState::expr, ExprEvalPushStep(), ExprState::ext_params, ExprState::flags, IsA, lappend_int(), lfirst, lfirst_int, makeNode, NIL, ExprEvalStep::opcode, ExprState::parent, ExprEvalStep::qualexpr, ExprState::resnull, ExprEvalStep::resnull, ExprState::resvalue, ExprEvalStep::resvalue, ExprState::steps, and ExprState::steps_len.

Referenced by CopyFrom(), ExecInitAgg(), ExecInitBitmapHeapScan(), ExecInitCteScan(), ExecInitCustomScan(), ExecInitForeignScan(), ExecInitFunctionScan(), ExecInitGroup(), ExecInitHashJoin(), ExecInitIndexOnlyScan(), ExecInitIndexScan(), ExecInitMergeJoin(), ExecInitModifyTable(), ExecInitNamedTuplestoreScan(), ExecInitNestLoop(), ExecInitPartitionInfo(), ExecInitResult(), ExecInitSampleScan(), ExecInitSeqScan(), ExecInitSubqueryScan(), ExecInitTableFuncScan(), ExecInitTidRangeScan(), ExecInitTidScan(), ExecInitValuesScan(), ExecInitWorkTableScan(), ExecPrepareQual(), and ExecProcNode().

210 {
211  ExprState *state;
212  ExprEvalStep scratch = {0};
213  List *adjust_jumps = NIL;
214  ListCell *lc;
215 
216  /* short-circuit (here and in ExecQual) for empty restriction list */
217  if (qual == NIL)
218  return NULL;
219 
220  Assert(IsA(qual, List));
221 
222  state = makeNode(ExprState);
223  state->expr = (Expr *) qual;
224  state->parent = parent;
225  state->ext_params = NULL;
226 
227  /* mark expression as to be used with ExecQual() */
228  state->flags = EEO_FLAG_IS_QUAL;
229 
230  /* Insert EEOP_*_FETCHSOME steps as needed */
231  ExecInitExprSlots(state, (Node *) qual);
232 
233  /*
234  * ExecQual() needs to return false for an expression returning NULL. That
235  * allows us to short-circuit the evaluation the first time a NULL is
236  * encountered. As qual evaluation is a hot-path this warrants using a
237  * special opcode for qual evaluation that's simpler than BOOL_AND (which
238  * has more complex NULL handling).
239  */
240  scratch.opcode = EEOP_QUAL;
241 
242  /*
243  * We can use ExprState's resvalue/resnull as target for each qual expr.
244  */
245  scratch.resvalue = &state->resvalue;
246  scratch.resnull = &state->resnull;
247 
248  foreach(lc, qual)
249  {
250  Expr *node = (Expr *) lfirst(lc);
251 
252  /* first evaluate expression */
253  ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
254 
255  /* then emit EEOP_QUAL to detect if it's false (or null) */
256  scratch.d.qualexpr.jumpdone = -1;
257  ExprEvalPushStep(state, &scratch);
258  adjust_jumps = lappend_int(adjust_jumps,
259  state->steps_len - 1);
260  }
261 
262  /* adjust jump targets */
263  foreach(lc, adjust_jumps)
264  {
265  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
266 
267  Assert(as->opcode == EEOP_QUAL);
268  Assert(as->d.qualexpr.jumpdone == -1);
269  as->d.qualexpr.jumpdone = state->steps_len;
270  }
271 
272  /*
273  * At the end, we don't need to do anything more. The last qual expr must
274  * have yielded TRUE, and since its result is stored in the desired output
275  * location, we're done.
276  */
277  scratch.opcode = EEOP_DONE;
278  ExprEvalPushStep(state, &scratch);
279 
280  ExecReadyExpr(state);
281 
282  return state;
283 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
struct PlanState * parent
Definition: execnodes.h:109
Datum * resvalue
Definition: execExpr.h:273
struct ExprEvalStep * steps
Definition: execnodes.h:86
struct ExprEvalStep::@49::@58 qualexpr
bool * resnull
Definition: execExpr.h:274
ParamListInfo ext_params
Definition: execnodes.h:110
Definition: nodes.h:536
bool resnull
Definition: execnodes.h:73
union ExprEvalStep::@49 d
Expr * expr
Definition: execnodes.h:95
#define lfirst_int(lc)
Definition: pg_list.h:170
static void ExecInitExprSlots(ExprState *state, Node *node)
Definition: execExpr.c:2576
#define EEO_FLAG_IS_QUAL
Definition: execnodes.h:60
List * lappend_int(List *list, int datum)
Definition: list.c:354
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:900
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2445
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:883
#define makeNode(_type_)
Definition: nodes.h:584
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
Definition: regguts.h:317
intptr_t opcode
Definition: execExpr.h:270
int steps_len
Definition: execnodes.h:105
uint8 flags
Definition: execnodes.h:66
Definition: pg_list.h:50
Datum resvalue
Definition: execnodes.h:75

◆ ExecInitSubscriptingRef()

static void ExecInitSubscriptingRef ( ExprEvalStep scratch,
SubscriptingRef sbsref,
ExprState state,
Datum resv,
bool resnull 
)
static

Definition at line 2863 of file execExpr.c.

References Assert, ExprEvalStep::d, EEOP_JUMP_IF_NULL, EEOP_SBSREF_ASSIGN, EEOP_SBSREF_FETCH, EEOP_SBSREF_OLD, EEOP_SBSREF_SUBSCRIPTS, ereport, errcode(), errmsg(), ERROR, SubscriptRoutines::exec_setup, ExecInitExprRec(), executor_errposition(), ExprEvalPushStep(), exprLocation(), SubscriptRoutines::fetch_strict, format_type_be(), getSubscriptingRoutines(), i, ExprState::innermost_casenull, ExprState::innermost_caseval, SubscriptingRefState::isassignment, isAssignmentIndirectionExpr(), ExprEvalStep::jump, lappend_int(), lfirst, lfirst_int, list_length(), SubscriptingRefState::lowerindex, SubscriptingRefState::lowerindexnull, SubscriptingRefState::lowerprovided, MAXALIGN, NIL, SubscriptingRefState::numlower, SubscriptingRefState::numupper, ExprEvalStep::opcode, palloc0(), ExprState::parent, SubscriptingRefState::prevnull, SubscriptingRefState::prevvalue, SubscriptingRef::refassgnexpr, SubscriptingRef::refcontainertype, SubscriptingRef::reflowerindexpr, SubscriptingRef::refupperindexpr, SubscriptingRefState::replacenull, SubscriptingRefState::replacevalue, SubscriptExecSteps::sbs_assign, SubscriptExecSteps::sbs_check_subscripts, SubscriptExecSteps::sbs_fetch, SubscriptExecSteps::sbs_fetch_old, ExprEvalStep::sbsref, ExprEvalStep::sbsref_subscript, PlanState::state, ExprState::steps, ExprState::steps_len, SubscriptingRefState::upperindex, SubscriptingRefState::upperindexnull, and SubscriptingRefState::upperprovided.

Referenced by ExecInitExprRec().

2865 {
2866  bool isAssignment = (sbsref->refassgnexpr != NULL);
2867  int nupper = list_length(sbsref->refupperindexpr);
2868  int nlower = list_length(sbsref->reflowerindexpr);
2869  const SubscriptRoutines *sbsroutines;
2870  SubscriptingRefState *sbsrefstate;
2871  SubscriptExecSteps methods;
2872  char *ptr;
2873  List *adjust_jumps = NIL;
2874  ListCell *lc;
2875  int i;
2876 
2877  /* Look up the subscripting support methods */
2878  sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype, NULL);
2879  if (!sbsroutines)
2880  ereport(ERROR,
2881  (errcode(ERRCODE_DATATYPE_MISMATCH),
2882  errmsg("cannot subscript type %s because it does not support subscripting",
2883  format_type_be(sbsref->refcontainertype)),
2884  state->parent ?
2886  exprLocation((Node *) sbsref)) : 0));
2887 
2888  /* Allocate sbsrefstate, with enough space for per-subscript arrays too */
2889  sbsrefstate = palloc0(MAXALIGN(sizeof(SubscriptingRefState)) +
2890  (nupper + nlower) * (sizeof(Datum) +
2891  2 * sizeof(bool)));
2892 
2893  /* Fill constant fields of SubscriptingRefState */
2894  sbsrefstate->isassignment = isAssignment;
2895  sbsrefstate->numupper = nupper;
2896  sbsrefstate->numlower = nlower;
2897  /* Set up per-subscript arrays */
2898  ptr = ((char *) sbsrefstate) + MAXALIGN(sizeof(SubscriptingRefState));
2899  sbsrefstate->upperindex = (Datum *) ptr;
2900  ptr += nupper * sizeof(Datum);
2901  sbsrefstate->lowerindex = (Datum *) ptr;
2902  ptr += nlower * sizeof(Datum);
2903  sbsrefstate->upperprovided = (bool *) ptr;
2904  ptr += nupper * sizeof(bool);
2905  sbsrefstate->lowerprovided = (bool *) ptr;
2906  ptr += nlower * sizeof(bool);
2907  sbsrefstate->upperindexnull = (bool *) ptr;
2908  ptr += nupper * sizeof(bool);
2909  sbsrefstate->lowerindexnull = (bool *) ptr;
2910  /* ptr += nlower * sizeof(bool); */
2911 
2912  /*
2913  * Let the container-type-specific code have a chance. It must fill the
2914  * "methods" struct with function pointers for us to possibly use in
2915  * execution steps below; and it can optionally set up some data pointed
2916  * to by the workspace field.
2917  */
2918  memset(&methods, 0, sizeof(methods));
2919  sbsroutines->exec_setup(sbsref, sbsrefstate, &methods);
2920 
2921  /*
2922  * Evaluate array input. It's safe to do so into resv/resnull, because we
2923  * won't use that as target for any of the other subexpressions, and it'll
2924  * be overwritten by the final EEOP_SBSREF_FETCH/ASSIGN step, which is
2925  * pushed last.
2926  */
2927  ExecInitExprRec(sbsref->refexpr, state, resv, resnull);
2928 
2929  /*
2930  * If refexpr yields NULL, and the operation should be strict, then result
2931  * is NULL. We can implement this with just JUMP_IF_NULL, since we
2932  * evaluated the array into the desired target location.
2933  */
2934  if (!isAssignment &a