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 3281 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().

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

◆ 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 3583 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().

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

◆ 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 3699 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().

3706 {
3708  ExprEvalStep scratch = {0};
3709  int maxatt = -1;
3710  List *adjust_jumps = NIL;
3711  ListCell *lc;
3712 
3713  /*
3714  * When no columns are actually compared, the result's always true. See
3715  * special case in ExecQual().
3716  */
3717  if (numCols == 0)
3718  return NULL;
3719 
3720  state->expr = NULL;
3721  state->flags = EEO_FLAG_IS_QUAL;
3722  state->parent = parent;
3723 
3724  scratch.resvalue = &state->resvalue;
3725  scratch.resnull = &state->resnull;
3726 
3727  /* compute max needed attribute */
3728  for (int natt = 0; natt < numCols; natt++)
3729  {
3730  int attno = keyColIdx[natt];
3731 
3732  if (attno > maxatt)
3733  maxatt = attno;
3734  }
3735  Assert(maxatt >= 0);
3736 
3737  /* push deform steps */
3738  scratch.opcode = EEOP_INNER_FETCHSOME;
3739  scratch.d.fetch.last_var = maxatt;
3740  scratch.d.fetch.fixed = false;
3741  scratch.d.fetch.known_desc = ldesc;
3742  scratch.d.fetch.kind = lops;
3743  if (ExecComputeSlotInfo(state, &scratch))
3744  ExprEvalPushStep(state, &scratch);
3745 
3746  scratch.opcode = EEOP_OUTER_FETCHSOME;
3747  scratch.d.fetch.last_var = maxatt;
3748  scratch.d.fetch.fixed = false;
3749  scratch.d.fetch.known_desc = rdesc;
3750  scratch.d.fetch.kind = rops;
3751  if (ExecComputeSlotInfo(state, &scratch))
3752  ExprEvalPushStep(state, &scratch);
3753 
3754  /*
3755  * Start comparing at the last field (least significant sort key). That's
3756  * the most likely to be different if we are dealing with sorted input.
3757  */
3758  for (int natt = numCols; --natt >= 0;)
3759  {
3760  int attno = keyColIdx[natt];
3761  Form_pg_attribute latt = TupleDescAttr(ldesc, attno - 1);
3762  Form_pg_attribute ratt = TupleDescAttr(rdesc, attno - 1);
3763  Oid foid = eqfunctions[natt];
3764  Oid collid = collations[natt];
3765  FmgrInfo *finfo;
3766  FunctionCallInfo fcinfo;
3767  AclResult aclresult;
3768 
3769  /* Check permission to call function */
3770  aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
3771  if (aclresult != ACLCHECK_OK)
3772  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
3773 
3775 
3776  /* Set up the primary fmgr lookup information */
3777  finfo = palloc0(sizeof(FmgrInfo));
3778  fcinfo = palloc0(SizeForFunctionCallInfo(2));
3779  fmgr_info(foid, finfo);
3780  fmgr_info_set_expr(NULL, finfo);
3781  InitFunctionCallInfoData(*fcinfo, finfo, 2,
3782  collid, NULL, NULL);
3783 
3784  /* left arg */
3785  scratch.opcode = EEOP_INNER_VAR;
3786  scratch.d.var.attnum = attno - 1;
3787  scratch.d.var.vartype = latt->atttypid;
3788  scratch.resvalue = &fcinfo->args[0].value;
3789  scratch.resnull = &fcinfo->args[0].isnull;
3790  ExprEvalPushStep(state, &scratch);
3791 
3792  /* right arg */
3793  scratch.opcode = EEOP_OUTER_VAR;
3794  scratch.d.var.attnum = attno - 1;
3795  scratch.d.var.vartype = ratt->atttypid;
3796  scratch.resvalue = &fcinfo->args[1].value;
3797  scratch.resnull = &fcinfo->args[1].isnull;
3798  ExprEvalPushStep(state, &scratch);
3799 
3800  /* evaluate distinctness */
3801  scratch.opcode = EEOP_NOT_DISTINCT;
3802  scratch.d.func.finfo = finfo;
3803  scratch.d.func.fcinfo_data = fcinfo;
3804  scratch.d.func.fn_addr = finfo->fn_addr;
3805  scratch.d.func.nargs = 2;
3806  scratch.resvalue = &state->resvalue;
3807  scratch.resnull = &state->resnull;
3808  ExprEvalPushStep(state, &scratch);
3809 
3810  /* then emit EEOP_QUAL to detect if result is false (or null) */
3811  scratch.opcode = EEOP_QUAL;
3812  scratch.d.qualexpr.jumpdone = -1;
3813  scratch.resvalue = &state->resvalue;
3814  scratch.resnull = &state->resnull;
3815  ExprEvalPushStep(state, &scratch);
3816  adjust_jumps = lappend_int(adjust_jumps,
3817  state->steps_len - 1);
3818  }
3819 
3820  /* adjust jump targets */
3821  foreach(lc, adjust_jumps)
3822  {
3823  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
3824 
3825  Assert(as->opcode == EEOP_QUAL);
3826  Assert(as->d.qualexpr.jumpdone == -1);
3827  as->d.qualexpr.jumpdone = state->steps_len;
3828  }
3829 
3830  scratch.resvalue = NULL;
3831  scratch.resnull = NULL;
3832  scratch.opcode = EEOP_DONE;
3833  ExprEvalPushStep(state, &scratch);
3834 
3835  ExecReadyExpr(state);
3836 
3837  return state;
3838 }
#define NIL
Definition: pg_list.h:65
Definition: fmgr.h:56
struct PlanState * parent
Definition: execnodes.h:108
Datum * resvalue
Definition: execExpr.h:273
struct ExprEvalStep::@49::@50 fetch
Oid GetUserId(void)
Definition: miscinit.c:478
PGFunction fn_addr
Definition: fmgr.h:58
struct ExprEvalStep * steps
Definition: execnodes.h:85
#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:72
union ExprEvalStep::@49 d
Expr * expr
Definition: execnodes.h:94
#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:59
#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:587
#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:104
#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:65
Definition: pg_list.h:50
Datum resvalue
Definition: execnodes.h:74

◆ 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 3856 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().

3863 {
3865  ExprEvalStep scratch = {0};
3866  int maxatt = list_length(param_exprs);
3867  List *adjust_jumps = NIL;
3868  ListCell *lc;
3869 
3870  state->expr = NULL;
3871  state->flags = EEO_FLAG_IS_QUAL;
3872  state->parent = parent;
3873 
3874  scratch.resvalue = &state->resvalue;
3875  scratch.resnull = &state->resnull;
3876 
3877  /* push deform steps */
3878  scratch.opcode = EEOP_INNER_FETCHSOME;
3879  scratch.d.fetch.last_var = maxatt;
3880  scratch.d.fetch.fixed = false;
3881  scratch.d.fetch.known_desc = desc;
3882  scratch.d.fetch.kind = lops;
3883  if (ExecComputeSlotInfo(state, &scratch))
3884  ExprEvalPushStep(state, &scratch);
3885 
3886  scratch.opcode = EEOP_OUTER_FETCHSOME;
3887  scratch.d.fetch.last_var = maxatt;
3888  scratch.d.fetch.fixed = false;
3889  scratch.d.fetch.known_desc = desc;
3890  scratch.d.fetch.kind = rops;
3891  if (ExecComputeSlotInfo(state, &scratch))
3892  ExprEvalPushStep(state, &scratch);
3893 
3894  for (int attno = 0; attno < maxatt; attno++)
3895  {
3896  Form_pg_attribute att = TupleDescAttr(desc, attno);
3897  Oid foid = eqfunctions[attno];
3898  Oid collid = collations[attno];
3899  FmgrInfo *finfo;
3900  FunctionCallInfo fcinfo;
3901  AclResult aclresult;
3902 
3903  /* Check permission to call function */
3904  aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
3905  if (aclresult != ACLCHECK_OK)
3906  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
3907 
3909 
3910  /* Set up the primary fmgr lookup information */
3911  finfo = palloc0(sizeof(FmgrInfo));
3912  fcinfo = palloc0(SizeForFunctionCallInfo(2));
3913  fmgr_info(foid, finfo);
3914  fmgr_info_set_expr(NULL, finfo);
3915  InitFunctionCallInfoData(*fcinfo, finfo, 2,
3916  collid, NULL, NULL);
3917 
3918  /* left arg */
3919  scratch.opcode = EEOP_INNER_VAR;
3920  scratch.d.var.attnum = attno;
3921  scratch.d.var.vartype = att->atttypid;
3922  scratch.resvalue = &fcinfo->args[0].value;
3923  scratch.resnull = &fcinfo->args[0].isnull;
3924  ExprEvalPushStep(state, &scratch);
3925 
3926  /* right arg */
3927  scratch.opcode = EEOP_OUTER_VAR;
3928  scratch.d.var.attnum = attno;
3929  scratch.d.var.vartype = att->atttypid;
3930  scratch.resvalue = &fcinfo->args[1].value;
3931  scratch.resnull = &fcinfo->args[1].isnull;
3932  ExprEvalPushStep(state, &scratch);
3933 
3934  /* evaluate distinctness */
3935  scratch.opcode = EEOP_NOT_DISTINCT;
3936  scratch.d.func.finfo = finfo;
3937  scratch.d.func.fcinfo_data = fcinfo;
3938  scratch.d.func.fn_addr = finfo->fn_addr;
3939  scratch.d.func.nargs = 2;
3940  scratch.resvalue = &state->resvalue;
3941  scratch.resnull = &state->resnull;
3942  ExprEvalPushStep(state, &scratch);
3943 
3944  /* then emit EEOP_QUAL to detect if result is false (or null) */
3945  scratch.opcode = EEOP_QUAL;
3946  scratch.d.qualexpr.jumpdone = -1;
3947  scratch.resvalue = &state->resvalue;
3948  scratch.resnull = &state->resnull;
3949  ExprEvalPushStep(state, &scratch);
3950  adjust_jumps = lappend_int(adjust_jumps,
3951  state->steps_len - 1);
3952  }
3953 
3954  /* adjust jump targets */
3955  foreach(lc, adjust_jumps)
3956  {
3957  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
3958 
3959  Assert(as->opcode == EEOP_QUAL);
3960  Assert(as->d.qualexpr.jumpdone == -1);
3961  as->d.qualexpr.jumpdone = state->steps_len;
3962  }
3963 
3964  scratch.resvalue = NULL;
3965  scratch.resnull = NULL;
3966  scratch.opcode = EEOP_DONE;
3967  ExprEvalPushStep(state, &scratch);
3968 
3969  ExecReadyExpr(state);
3970 
3971  return state;
3972 }
#define NIL
Definition: pg_list.h:65
Definition: fmgr.h:56
struct PlanState * parent
Definition: execnodes.h:108
Datum * resvalue
Definition: execExpr.h:273
struct ExprEvalStep::@49::@50 fetch
Oid GetUserId(void)
Definition: miscinit.c:478
PGFunction fn_addr
Definition: fmgr.h:58
struct ExprEvalStep * steps
Definition: execnodes.h:85
#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:72
union ExprEvalStep::@49 d
Expr * expr
Definition: execnodes.h:94
#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:59
#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:587
#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:104
#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:65
Definition: pg_list.h:50
Datum resvalue
Definition: execnodes.h:74

◆ 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 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
struct PlanState * parent
Definition: execnodes.h:108
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
ParamListInfo ext_params
Definition: execnodes.h:109
Definition: nodes.h:539
AttrNumber varattno
Definition: primnodes.h:191
TupleTableSlot * resultslot
Definition: execnodes.h:80
Definition: primnodes.h:186
bool resnull
Definition: execnodes.h:72
union ExprEvalStep::@49 d
Expr * expr
Definition: execnodes.h:94
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:1455
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
NodeTag type
Definition: execnodes.h:63
Index varno
Definition: primnodes.h:189
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:587
Definition: regguts.h:317
intptr_t opcode
Definition: execExpr.h:270
Expr * expr
Definition: primnodes.h:1454
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2144
ExprState pi_state
Definition: execnodes.h:333
struct ExprEvalStep::@49::@54 assign_tmp
ExprContext * pi_exprContext
Definition: execnodes.h:335
Datum resvalue
Definition: execnodes.h:74
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:108
#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:109
Definition: nodes.h:539
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:80
bool resjunk
Definition: primnodes.h:1461
#define ERROR
Definition: elog.h:46
bool resnull
Definition: execnodes.h:72
union ExprEvalStep::@49 d
Expr * expr
Definition: execnodes.h:94
#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:63
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:587
#define Assert(condition)
Definition: c.h:804
Definition: regguts.h:317
intptr_t opcode
Definition: execExpr.h:270
Expr * expr
Definition: primnodes.h:1454
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:333
struct ExprEvalStep::@49::@54 assign_tmp
ExprContext * pi_exprContext
Definition: execnodes.h:335
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
Datum resvalue
Definition: execnodes.h:74
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:59
#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:65

◆ 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:1042
struct PlanState * parent
Definition: execnodes.h:108
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:499
struct ExprEvalStep::@49::@50 fetch
bool inneropsset
Definition: execnodes.h:1050
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
ExprEvalOp
Definition: execExpr.h:64
bool inneropsfixed
Definition: execnodes.h:1046
union ExprEvalStep::@49 d
#define outerPlanState(node)
Definition: execnodes.h:1062
const TupleTableSlotOps * scanops
Definition: execnodes.h:1040
bool outeropsset
Definition: execnodes.h:1049
TupleDesc scandesc
Definition: execnodes.h:1015
bool scanopsfixed
Definition: execnodes.h:1044
#define Assert(condition)
Definition: c.h:804
intptr_t opcode
Definition: execExpr.h:270
bool outeropsfixed
Definition: execnodes.h:1045
bool scanopsset
Definition: execnodes.h:1048
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:490
#define innerPlanState(node)
Definition: execnodes.h:1061
const TupleTableSlotOps * outerops
Definition: execnodes.h:1041

◆ 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:590
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 3127 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().

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

◆ 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
#define NIL
Definition: pg_list.h:65
static void ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:3127
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:590
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:108
#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:796
List * args
Definition: primnodes.h:390
List * args
Definition: primnodes.h:503
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1824
Datum * resvalue
Definition: execExpr.h:273
Oid GetUserId(void)
Definition: miscinit.c:478
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:85
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
struct ExprEvalStep::@49::@57 boolexpr
bool * innermost_casenull
Definition: execnodes.h:112
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:993
ParamListInfo ext_params
Definition: execnodes.h:109
Expr * arg
Definition: primnodes.h:860
ParamKind paramkind
Definition: primnodes.h:267
struct ExprEvalStep::@49::@72 rowcompare_final
Definition: nodes.h:539
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:114
EState * state
Definition: execnodes.h:968
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:115
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:72
union ExprEvalStep::@49 d
Expr * expr
Definition: execnodes.h:94
#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:111
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:158
List * lappend(List *list, void *datum)
Definition: list.c:336
struct ExprEvalStep::@49::@84 grouping_func
Index varno
Definition: primnodes.h:189
Definition: nodes.h:157
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:870
NullTestType nulltesttype
Definition: primnodes.h:1266
struct ExprEvalStep::@49::@64 make_readonly
Plan * plan
Definition: execnodes.h:966
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:587
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:544
Oid element_typeid
Definition: primnodes.h:1036
struct ExprEvalStep::@49::@59 jump
struct ExprEvalStep::@49::@70 row
static Datum values[MAXATTR]
Definition: bootstrap.c:166
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:104
#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:594
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:857
struct ExprEvalStep::@49::@65 iocoerce
WindowFunc * wfunc
Definition: execnodes.h:794
List * aggs
Definition: execnodes.h:2277
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:74
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:1858
Definition: nodes.h:159
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:108
ParamListInfo ext_params
Definition: execnodes.h:109
Definition: nodes.h:539
bool resnull
Definition: execnodes.h:72
Expr * expr
Definition: execnodes.h:94
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:587
Definition: regguts.h:317
intptr_t opcode
Definition: execExpr.h:270
Datum resvalue
Definition: execnodes.h:74

◆ 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:590
struct PlanState * parent
Definition: execnodes.h:108
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1250
Oid GetUserId(void)
Definition: miscinit.c:478
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:539
int errcode(int sqlerrcode)
Definition: elog.c:698
EState * state
Definition: execnodes.h:968
#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:590
struct PlanState * parent
Definition: execnodes.h:108
Datum * resvalue
Definition: execExpr.h:273
struct ExprEvalStep * steps
Definition: execnodes.h:85
struct ExprEvalStep::@49::@58 qualexpr
bool * resnull
Definition: execExpr.h:274
ParamListInfo ext_params
Definition: execnodes.h:109
Definition: nodes.h:539
bool resnull
Definition: execnodes.h:72
union ExprEvalStep::@49 d
Expr * expr
Definition: execnodes.h:94
#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:59
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:587
#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:104
uint8 flags
Definition: execnodes.h:65
Definition: pg_list.h:50
Datum resvalue
Definition: execnodes.h:74

◆ 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 (!is