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

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

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

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

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

3847 {
3849  ExprEvalStep scratch = {0};
3850  int maxatt = list_length(param_exprs);
3851  List *adjust_jumps = NIL;
3852  ListCell *lc;
3853 
3854  state->expr = NULL;
3855  state->flags = EEO_FLAG_IS_QUAL;
3856  state->parent = parent;
3857 
3858  scratch.resvalue = &state->resvalue;
3859  scratch.resnull = &state->resnull;
3860 
3861  /* push deform steps */
3862  scratch.opcode = EEOP_INNER_FETCHSOME;
3863  scratch.d.fetch.last_var = maxatt;
3864  scratch.d.fetch.fixed = false;
3865  scratch.d.fetch.known_desc = desc;
3866  scratch.d.fetch.kind = lops;
3867  if (ExecComputeSlotInfo(state, &scratch))
3868  ExprEvalPushStep(state, &scratch);
3869 
3870  scratch.opcode = EEOP_OUTER_FETCHSOME;
3871  scratch.d.fetch.last_var = maxatt;
3872  scratch.d.fetch.fixed = false;
3873  scratch.d.fetch.known_desc = desc;
3874  scratch.d.fetch.kind = rops;
3875  if (ExecComputeSlotInfo(state, &scratch))
3876  ExprEvalPushStep(state, &scratch);
3877 
3878  for (int attno = 0; attno < maxatt; attno++)
3879  {
3880  Form_pg_attribute att = TupleDescAttr(desc, attno);
3881  Oid foid = eqfunctions[attno];
3882  Oid collid = collations[attno];
3883  FmgrInfo *finfo;
3884  FunctionCallInfo fcinfo;
3885  AclResult aclresult;
3886 
3887  /* Check permission to call function */
3888  aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
3889  if (aclresult != ACLCHECK_OK)
3890  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
3891 
3893 
3894  /* Set up the primary fmgr lookup information */
3895  finfo = palloc0(sizeof(FmgrInfo));
3896  fcinfo = palloc0(SizeForFunctionCallInfo(2));
3897  fmgr_info(foid, finfo);
3898  fmgr_info_set_expr(NULL, finfo);
3899  InitFunctionCallInfoData(*fcinfo, finfo, 2,
3900  collid, NULL, NULL);
3901 
3902  /* left arg */
3903  scratch.opcode = EEOP_INNER_VAR;
3904  scratch.d.var.attnum = attno;
3905  scratch.d.var.vartype = att->atttypid;
3906  scratch.resvalue = &fcinfo->args[0].value;
3907  scratch.resnull = &fcinfo->args[0].isnull;
3908  ExprEvalPushStep(state, &scratch);
3909 
3910  /* right arg */
3911  scratch.opcode = EEOP_OUTER_VAR;
3912  scratch.d.var.attnum = attno;
3913  scratch.d.var.vartype = att->atttypid;
3914  scratch.resvalue = &fcinfo->args[1].value;
3915  scratch.resnull = &fcinfo->args[1].isnull;
3916  ExprEvalPushStep(state, &scratch);
3917 
3918  /* evaluate distinctness */
3919  scratch.opcode = EEOP_NOT_DISTINCT;
3920  scratch.d.func.finfo = finfo;
3921  scratch.d.func.fcinfo_data = fcinfo;
3922  scratch.d.func.fn_addr = finfo->fn_addr;
3923  scratch.d.func.nargs = 2;
3924  scratch.resvalue = &state->resvalue;
3925  scratch.resnull = &state->resnull;
3926  ExprEvalPushStep(state, &scratch);
3927 
3928  /* then emit EEOP_QUAL to detect if result is false (or null) */
3929  scratch.opcode = EEOP_QUAL;
3930  scratch.d.qualexpr.jumpdone = -1;
3931  scratch.resvalue = &state->resvalue;
3932  scratch.resnull = &state->resnull;
3933  ExprEvalPushStep(state, &scratch);
3934  adjust_jumps = lappend_int(adjust_jumps,
3935  state->steps_len - 1);
3936  }
3937 
3938  /* adjust jump targets */
3939  foreach(lc, adjust_jumps)
3940  {
3941  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
3942 
3943  Assert(as->opcode == EEOP_QUAL);
3944  Assert(as->d.qualexpr.jumpdone == -1);
3945  as->d.qualexpr.jumpdone = state->steps_len;
3946  }
3947 
3948  scratch.resvalue = NULL;
3949  scratch.resnull = NULL;
3950  scratch.opcode = EEOP_DONE;
3951  ExprEvalPushStep(state, &scratch);
3952 
3953  ExecReadyExpr(state);
3954 
3955  return state;
3956 }
#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:3313
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:203
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:2676
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2429
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:4723
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, ExprState::tag, TupleDescAttr, 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.tag = 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 }
NodeTag tag
Definition: execnodes.h:63
#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:2560
#define lfirst_node(type, lc)
Definition: pg_list.h:172
AttrNumber resno
Definition: primnodes.h:1445
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:203
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:2429
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:1444
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, ExprState::tag, and TupleDescAttr.

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.tag = 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 }
NodeTag tag
Definition: execnodes.h:63
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:1451
#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:203
static void ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
Definition: execExpr.c:2578
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:2429
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:1444
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:2622
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 2676 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().

2677 {
2678  PlanState *parent = state->parent;
2679  TupleDesc desc = NULL;
2680  const TupleTableSlotOps *tts_ops = NULL;
2681  bool isfixed = false;
2682  ExprEvalOp opcode = op->opcode;
2683 
2684  Assert(opcode == EEOP_INNER_FETCHSOME ||
2685  opcode == EEOP_OUTER_FETCHSOME ||
2686  opcode == EEOP_SCAN_FETCHSOME);
2687 
2688  if (op->d.fetch.known_desc != NULL)
2689  {
2690  desc = op->d.fetch.known_desc;
2691  tts_ops = op->d.fetch.kind;
2692  isfixed = op->d.fetch.kind != NULL;
2693  }
2694  else if (!parent)
2695  {
2696  isfixed = false;
2697  }
2698  else if (opcode == EEOP_INNER_FETCHSOME)
2699  {
2700  PlanState *is = innerPlanState(parent);
2701 
2702  if (parent->inneropsset && !parent->inneropsfixed)
2703  {
2704  isfixed = false;
2705  }
2706  else if (parent->inneropsset && parent->innerops)
2707  {
2708  isfixed = true;
2709  tts_ops = parent->innerops;
2710  desc = ExecGetResultType(is);
2711  }
2712  else if (is)
2713  {
2714  tts_ops = ExecGetResultSlotOps(is, &isfixed);
2715  desc = ExecGetResultType(is);
2716  }
2717  }
2718  else if (opcode == EEOP_OUTER_FETCHSOME)
2719  {
2720  PlanState *os = outerPlanState(parent);
2721 
2722  if (parent->outeropsset && !parent->outeropsfixed)
2723  {
2724  isfixed = false;
2725  }
2726  else if (parent->outeropsset && parent->outerops)
2727  {
2728  isfixed = true;
2729  tts_ops = parent->outerops;
2730  desc = ExecGetResultType(os);
2731  }
2732  else if (os)
2733  {
2734  tts_ops = ExecGetResultSlotOps(os, &isfixed);
2735  desc = ExecGetResultType(os);
2736  }
2737  }
2738  else if (opcode == EEOP_SCAN_FETCHSOME)
2739  {
2740  desc = parent->scandesc;
2741 
2742  if (parent->scanops)
2743  tts_ops = parent->scanops;
2744 
2745  if (parent->scanopsset)
2746  isfixed = parent->scanopsfixed;
2747  }
2748 
2749  if (isfixed && desc != NULL && tts_ops != NULL)
2750  {
2751  op->d.fetch.fixed = true;
2752  op->d.fetch.kind = tts_ops;
2753  op->d.fetch.known_desc = desc;
2754  }
2755  else
2756  {
2757  op->d.fetch.fixed = false;
2758  op->d.fetch.kind = NULL;
2759  op->d.fetch.known_desc = NULL;
2760  }
2761 
2762  /* if the slot is known to always virtual we never need to deform */
2763  if (op->d.fetch.fixed && op->d.fetch.kind == &TTSOpsVirtual)
2764  return false;
2765 
2766  return true;
2767 }
const TupleTableSlotOps * innerops
Definition: execnodes.h:1041
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:1049
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
ExprEvalOp
Definition: execExpr.h:64
bool inneropsfixed
Definition: execnodes.h:1045
union ExprEvalStep::@49 d
#define outerPlanState(node)
Definition: execnodes.h:1061
const TupleTableSlotOps * scanops
Definition: execnodes.h:1039
bool outeropsset
Definition: execnodes.h:1048
TupleDesc scandesc
Definition: execnodes.h:1014
bool scanopsfixed
Definition: execnodes.h:1043
#define Assert(condition)
Definition: c.h:804
intptr_t opcode
Definition: execExpr.h:270
bool outeropsfixed
Definition: execnodes.h:1044
bool scanopsset
Definition: execnodes.h:1047
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:490
#define innerPlanState(node)
Definition: execnodes.h:1060
const TupleTableSlotOps * outerops
Definition: execnodes.h:1040

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

3113 {
3114  DomainConstraintRef *constraint_ref;
3115  ListCell *l;
3116 
3117  scratch->d.domaincheck.resulttype = ctest->resulttype;
3118  /* we'll allocate workspace only if needed */
3119  scratch->d.domaincheck.checkvalue = NULL;
3120  scratch->d.domaincheck.checknull = NULL;
3121 
3122  /*
3123  * Evaluate argument - it's fine to directly store it into resv/resnull,
3124  * if there's constraint failures there'll be errors, otherwise it's what
3125  * needs to be returned.
3126  */
3127  ExecInitExprRec(ctest->arg, state, resv, resnull);
3128 
3129  /*
3130  * Note: if the argument is of varlena type, it could be a R/W expanded
3131  * object. We want to return the R/W pointer as the final result, but we
3132  * have to pass a R/O pointer as the value to be tested by any functions
3133  * in check expressions. We don't bother to emit a MAKE_READONLY step
3134  * unless there's actually at least one check expression, though. Until
3135  * we've tested that, domainval/domainnull are NULL.
3136  */
3137 
3138  /*
3139  * Collect the constraints associated with the domain.
3140  *
3141  * Note: before PG v10 we'd recheck the set of constraints during each
3142  * evaluation of the expression. Now we bake them into the ExprState
3143  * during executor initialization. That means we don't need typcache.c to
3144  * provide compiled exprs.
3145  */
3146  constraint_ref = (DomainConstraintRef *)
3147  palloc(sizeof(DomainConstraintRef));
3149  constraint_ref,
3151  false);
3152 
3153  /*
3154  * Compile code to check each domain constraint. NOTNULL constraints can
3155  * just be applied on the resv/resnull value, but for CHECK constraints we
3156  * need more pushups.
3157  */
3158  foreach(l, constraint_ref->constraints)
3159  {
3161  Datum *domainval = NULL;
3162  bool *domainnull = NULL;
3163  Datum *save_innermost_domainval;
3164  bool *save_innermost_domainnull;
3165 
3166  scratch->d.domaincheck.constraintname = con->name;
3167 
3168  switch (con->constrainttype)
3169  {
3171  scratch->opcode = EEOP_DOMAIN_NOTNULL;
3172  ExprEvalPushStep(state, scratch);
3173  break;
3174  case DOM_CONSTRAINT_CHECK:
3175  /* Allocate workspace for CHECK output if we didn't yet */
3176  if (scratch->d.domaincheck.checkvalue == NULL)
3177  {
3178  scratch->d.domaincheck.checkvalue =
3179  (Datum *) palloc(sizeof(Datum));
3180  scratch->d.domaincheck.checknull =
3181  (bool *) palloc(sizeof(bool));
3182  }
3183 
3184  /*
3185  * If first time through, determine where CoerceToDomainValue
3186  * nodes should read from.
3187  */
3188  if (domainval == NULL)
3189  {
3190  /*
3191  * Since value might be read multiple times, force to R/O
3192  * - but only if it could be an expanded datum.
3193  */
3194  if (get_typlen(ctest->resulttype) == -1)
3195  {
3196  ExprEvalStep scratch2 = {0};
3197 
3198  /* Yes, so make output workspace for MAKE_READONLY */
3199  domainval = (Datum *) palloc(sizeof(Datum));
3200  domainnull = (bool *) palloc(sizeof(bool));
3201 
3202  /* Emit MAKE_READONLY */
3203  scratch2.opcode = EEOP_MAKE_READONLY;
3204  scratch2.resvalue = domainval;
3205  scratch2.resnull = domainnull;
3206  scratch2.d.make_readonly.value = resv;
3207  scratch2.d.make_readonly.isnull = resnull;
3208  ExprEvalPushStep(state, &scratch2);
3209  }
3210  else
3211  {
3212  /* No, so it's fine to read from resv/resnull */
3213  domainval = resv;
3214  domainnull = resnull;
3215  }
3216  }
3217 
3218  /*
3219  * Set up value to be returned by CoerceToDomainValue nodes.
3220  * We must save and restore innermost_domainval/null fields,
3221  * in case this node is itself within a check expression for
3222  * another domain.
3223  */
3224  save_innermost_domainval = state->innermost_domainval;
3225  save_innermost_domainnull = state->innermost_domainnull;
3226  state->innermost_domainval = domainval;
3227  state->innermost_domainnull = domainnull;
3228 
3229  /* evaluate check expression value */
3230  ExecInitExprRec(con->check_expr, state,
3231  scratch->d.domaincheck.checkvalue,
3232  scratch->d.domaincheck.checknull);
3233 
3234  state->innermost_domainval = save_innermost_domainval;
3235  state->innermost_domainnull = save_innermost_domainnull;
3236 
3237  /* now test result */
3238  scratch->opcode = EEOP_DOMAIN_CHECK;
3239  ExprEvalPushStep(state, scratch);
3240 
3241  break;
3242  default:
3243  elog(ERROR, "unrecognized constraint type: %d",
3244  (int) con->constrainttype);
3245  break;
3246  }
3247  }
3248 }
Datum * resvalue
Definition: execExpr.h:273
DomainConstraintType constrainttype
Definition: execnodes.h:929
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:2429
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:1304
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(), ExecInitProjectSet(), ExecInitPruningContext(), ExecInitResultCache(), 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:2560
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:2429
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, 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 
1209  Assert(list_length(opexpr->args) == 2);
1210  scalararg = (Expr *) linitial(opexpr->args);
1211  arrayarg = (Expr *) lsecond(opexpr->args);
1212 
1213  /* Check permission to call function */
1214  aclresult = pg_proc_aclcheck(opexpr->opfuncid,
1215  GetUserId(),
1216  ACL_EXECUTE);
1217  if (aclresult != ACLCHECK_OK)
1218  aclcheck_error(aclresult, OBJECT_FUNCTION,
1219  get_func_name(opexpr->opfuncid));
1221 
1222  if (OidIsValid(opexpr->hashfuncid))
1223  {
1224  aclresult = pg_proc_aclcheck(opexpr->hashfuncid,
1225  GetUserId(),
1226  ACL_EXECUTE);
1227  if (aclresult != ACLCHECK_OK)
1228  aclcheck_error(aclresult, OBJECT_FUNCTION,
1229  get_func_name(opexpr->hashfuncid));
1231  }
1232 
1233  /* Set up the primary fmgr lookup information */
1234  finfo = palloc0(sizeof(FmgrInfo));
1235  fcinfo = palloc0(SizeForFunctionCallInfo(2));
1236  fmgr_info(opexpr->opfuncid, finfo);
1237  fmgr_info_set_expr((Node *) node, finfo);
1238  InitFunctionCallInfoData(*fcinfo, finfo, 2,
1239  opexpr->inputcollid, NULL, NULL);
1240 
1241  /*
1242  * If hashfuncid is set, we create a EEOP_HASHED_SCALARARRAYOP
1243  * step instead of a EEOP_SCALARARRAYOP. This provides much
1244  * faster lookup performance than the normal linear search
1245  * when the number of items in the array is anything but very
1246  * small.
1247  */
1248  if (OidIsValid(opexpr->hashfuncid))
1249  {
1250  hash_finfo = palloc0(sizeof(FmgrInfo));
1251  hash_fcinfo = palloc0(SizeForFunctionCallInfo(1));
1252  fmgr_info(opexpr->hashfuncid, hash_finfo);
1253  fmgr_info_set_expr((Node *) node, hash_finfo);
1254  InitFunctionCallInfoData(*hash_fcinfo, hash_finfo,
1255  1, opexpr->inputcollid, NULL,
1256  NULL);
1257 
1258  scratch.d.hashedscalararrayop.hash_finfo = hash_finfo;
1259  scratch.d.hashedscalararrayop.hash_fcinfo_data = hash_fcinfo;
1260  scratch.d.hashedscalararrayop.hash_fn_addr = hash_finfo->fn_addr;
1261 
1262  /* Evaluate scalar directly into left function argument */
1263  ExecInitExprRec(scalararg, state,
1264  &fcinfo->args[0].value, &fcinfo->args[0].isnull);
1265 
1266  /*
1267  * Evaluate array argument into our return value. There's
1268  * no danger in that, because the return value is
1269  * guaranteed to be overwritten by
1270  * EEOP_HASHED_SCALARARRAYOP, and will not be passed to
1271  * any other expression.
1272  */
1273  ExecInitExprRec(arrayarg, state, resv, resnull);
1274 
1275  /* And perform the operation */
1277  scratch.d.hashedscalararrayop.finfo = finfo;
1278  scratch.d.hashedscalararrayop.fcinfo_data = fcinfo;
1279  scratch.d.hashedscalararrayop.fn_addr = finfo->fn_addr;
1280 
1281  scratch.d.hashedscalararrayop.hash_finfo = hash_finfo;
1282  scratch.d.hashedscalararrayop.hash_fcinfo_data = hash_fcinfo;
1283  scratch.d.hashedscalararrayop.hash_fn_addr = hash_finfo->fn_addr;
1284 
1285  ExprEvalPushStep(state, &scratch);
1286  }
1287  else
1288  {
1289  /* Evaluate scalar directly into left function argument */
1290  ExecInitExprRec(scalararg, state,
1291  &fcinfo->args[0].value,
1292  &fcinfo->args[0].isnull);
1293 
1294  /*
1295  * Evaluate array argument into our return value. There's
1296  * no danger in that, because the return value is
1297  * guaranteed to be overwritten by EEOP_SCALARARRAYOP, and
1298  * will not be passed to any other expression.
1299  */
1300  ExecInitExprRec(arrayarg, state, resv, resnull);
1301 
1302  /* And perform the operation */
1303  scratch.opcode = EEOP_SCALARARRAYOP;
1304  scratch.d.scalararrayop.element_type = InvalidOid;
1305  scratch.d.scalararrayop.useOr = opexpr->useOr;
1306  scratch.d.scalararrayop.finfo = finfo;
1307  scratch.d.scalararrayop.fcinfo_data = fcinfo;
1308  scratch.d.scalararrayop.fn_addr = finfo->fn_addr;
1309  ExprEvalPushStep(state, &scratch);
1310  }
1311  break;
1312  }
1313 
1314  case T_BoolExpr:
1315  {
1316  BoolExpr *boolexpr = (BoolExpr *) node;
1317  int nargs = list_length(boolexpr->args);
1318  List *adjust_jumps = NIL;
1319  int off;
1320  ListCell *lc;
1321 
1322  /* allocate scratch memory used by all steps of AND/OR */
1323  if (boolexpr->boolop != NOT_EXPR)
1324  scratch.d.boolexpr.anynull = (bool *) palloc(sizeof(bool));
1325 
1326  /*
1327  * For each argument evaluate the argument itself, then
1328  * perform the bool operation's appropriate handling.
1329  *
1330  * We can evaluate each argument into our result area, since
1331  * the short-circuiting logic means we only need to remember
1332  * previous NULL values.
1333  *
1334  * AND/OR is split into separate STEP_FIRST (one) / STEP (zero
1335  * or more) / STEP_LAST (one) steps, as each of those has to
1336  * perform different work. The FIRST/LAST split is valid
1337  * because AND/OR have at least two arguments.
1338  */
1339  off = 0;
1340  foreach(lc, boolexpr->args)
1341  {
1342  Expr *arg = (Expr *) lfirst(lc);
1343 
1344  /* Evaluate argument into our output variable */
1345  ExecInitExprRec(arg, state, resv, resnull);
1346 
1347  /* Perform the appropriate step type */
1348  switch (boolexpr->boolop)
1349  {
1350  case AND_EXPR:
1351  Assert(nargs >= 2);
1352 
1353  if (off == 0)
1354  scratch.opcode = EEOP_BOOL_AND_STEP_FIRST;
1355  else if (off + 1 == nargs)
1356  scratch.opcode = EEOP_BOOL_AND_STEP_LAST;
1357  else
1358  scratch.opcode = EEOP_BOOL_AND_STEP;
1359  break;
1360  case OR_EXPR:
1361  Assert(nargs >= 2);
1362 
1363  if (off == 0)
1364  scratch.opcode = EEOP_BOOL_OR_STEP_FIRST;
1365  else if (off + 1 == nargs)
1366  scratch.opcode = EEOP_BOOL_OR_STEP_LAST;
1367  else
1368  scratch.opcode = EEOP_BOOL_OR_STEP;
1369  break;
1370  case NOT_EXPR:
1371  Assert(nargs == 1);
1372 
1373  scratch.opcode = EEOP_BOOL_NOT_STEP;
1374  break;
1375  default:
1376  elog(ERROR, "unrecognized boolop: %d",
1377  (int) boolexpr->boolop);
1378  break;
1379  }
1380 
1381  scratch.d.boolexpr.jumpdone = -1;
1382  ExprEvalPushStep(state, &scratch);
1383  adjust_jumps = lappend_int(adjust_jumps,
1384  state->steps_len - 1);
1385  off++;
1386  }
1387 
1388  /* adjust jump targets */
1389  foreach(lc, adjust_jumps)
1390  {
1391  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
1392 
1393  Assert(as->d.boolexpr.jumpdone == -1);
1394  as->d.boolexpr.jumpdone = state->steps_len;
1395  }
1396 
1397  break;
1398  }
1399 
1400  case T_SubPlan:
1401  {
1402  SubPlan *subplan = (SubPlan *) node;
1403  SubPlanState *sstate;
1404 
1405  if (!state->parent)
1406  elog(ERROR, "SubPlan found with no parent plan");
1407 
1408  sstate = ExecInitSubPlan(subplan, state->parent);
1409 
1410  /* add SubPlanState nodes to state->parent->subPlan */
1411  state->parent->subPlan = lappend(state->parent->subPlan,
1412  sstate);
1413 
1414  scratch.opcode = EEOP_SUBPLAN;
1415  scratch.d.subplan.sstate = sstate;
1416 
1417  ExprEvalPushStep(state, &scratch);
1418  break;
1419  }
1420 
1421  case T_FieldSelect:
1422  {
1423  FieldSelect *fselect = (FieldSelect *) node;
1424 
1425  /* evaluate row/record argument into result area */
1426  ExecInitExprRec(fselect->arg, state, resv, resnull);
1427 
1428  /* and extract field */
1429  scratch.opcode = EEOP_FIELDSELECT;
1430  scratch.d.fieldselect.fieldnum = fselect->fieldnum;
1431  scratch.d.fieldselect.resulttype = fselect->resulttype;
1432  scratch.d.fieldselect.rowcache.cacheptr = NULL;
1433 
1434  ExprEvalPushStep(state, &scratch);
1435  break;
1436  }
1437 
1438  case T_FieldStore:
1439  {
1440  FieldStore *fstore = (FieldStore *) node;
1441  TupleDesc tupDesc;
1442  ExprEvalRowtypeCache *rowcachep;
1443  Datum *values;
1444  bool *nulls;
1445  int ncolumns;
1446  ListCell *l1,
1447  *l2;
1448 
1449  /* find out the number of columns in the composite type */
1450  tupDesc = lookup_rowtype_tupdesc(fstore->resulttype, -1);
1451  ncolumns = tupDesc->natts;
1452  DecrTupleDescRefCount(tupDesc);
1453 
1454  /* create workspace for column values */
1455  values = (Datum *) palloc(sizeof(Datum) * ncolumns);
1456  nulls = (bool *) palloc(sizeof(bool) * ncolumns);
1457 
1458  /* create shared composite-type-lookup cache struct */
1459  rowcachep = palloc(sizeof(ExprEvalRowtypeCache));
1460  rowcachep->cacheptr = NULL;
1461 
1462  /* emit code to evaluate the composite input value */
1463  ExecInitExprRec(fstore->arg, state, resv, resnull);
1464 
1465  /* next, deform the input tuple into our workspace */
1466  scratch.opcode = EEOP_FIELDSTORE_DEFORM;
1467  scratch.d.fieldstore.fstore = fstore;
1468  scratch.d.fieldstore.rowcache = rowcachep;
1469  scratch.d.fieldstore.values = values;
1470  scratch.d.fieldstore.nulls = nulls;
1471  scratch.d.fieldstore.ncolumns = ncolumns;
1472  ExprEvalPushStep(state, &scratch);
1473 
1474  /* evaluate new field values, store in workspace columns */
1475  forboth(l1, fstore->newvals, l2, fstore->fieldnums)
1476  {
1477  Expr *e = (Expr *) lfirst(l1);
1478  AttrNumber fieldnum = lfirst_int(l2);
1479  Datum *save_innermost_caseval;
1480  bool *save_innermost_casenull;
1481 
1482  if (fieldnum <= 0 || fieldnum > ncolumns)
1483  elog(ERROR, "field number %d is out of range in FieldStore",
1484  fieldnum);
1485 
1486  /*
1487  * Use the CaseTestExpr mechanism to pass down the old
1488  * value of the field being replaced; this is needed in
1489  * case the newval is itself a FieldStore or
1490  * SubscriptingRef that has to obtain and modify the old
1491  * value. It's safe to reuse the CASE mechanism because
1492  * there cannot be a CASE between here and where the value
1493  * would be needed, and a field assignment can't be within
1494  * a CASE either. (So saving and restoring
1495  * innermost_caseval is just paranoia, but let's do it
1496  * anyway.)
1497  *
1498  * Another non-obvious point is that it's safe to use the
1499  * field's values[]/nulls[] entries as both the caseval
1500  * source and the result address for this subexpression.
1501  * That's okay only because (1) both FieldStore and
1502  * SubscriptingRef evaluate their arg or refexpr inputs
1503  * first, and (2) any such CaseTestExpr is directly the
1504  * arg or refexpr input. So any read of the caseval will
1505  * occur before there's a chance to overwrite it. Also,
1506  * if multiple entries in the newvals/fieldnums lists
1507  * target the same field, they'll effectively be applied
1508  * left-to-right which is what we want.
1509  */
1510  save_innermost_caseval = state->innermost_caseval;
1511  save_innermost_casenull = state->innermost_casenull;
1512  state->innermost_caseval = &values[fieldnum - 1];
1513  state->innermost_casenull = &nulls[fieldnum - 1];
1514 
1515  ExecInitExprRec(e, state,
1516  &values[fieldnum - 1],
1517  &nulls[fieldnum - 1]);
1518 
1519  state->innermost_caseval = save_innermost_caseval;
1520  state->innermost_casenull = save_innermost_casenull;
1521  }
1522 
1523  /* finally, form result tuple */
1524  scratch.opcode = EEOP_FIELDSTORE_FORM;
1525  scratch.d.fieldstore.fstore = fstore;
1526  scratch.d.fieldstore.rowcache = rowcachep;
1527  scratch.d.fieldstore.values = values;
1528  scratch.d.fieldstore.nulls = nulls;
1529  scratch.d.fieldstore.ncolumns = ncolumns;
1530  ExprEvalPushStep(state, &scratch);
1531  break;
1532  }
1533 
1534  case T_RelabelType:
1535  {
1536  /* relabel doesn't need to do anything at runtime */
1537  RelabelType *relabel = (RelabelType *) node;
1538 
1539  ExecInitExprRec(relabel->arg, state, resv, resnull);
1540  break;
1541  }
1542 
1543  case T_CoerceViaIO:
1544  {
1545  CoerceViaIO *iocoerce = (CoerceViaIO *) node;
1546  Oid iofunc;
1547  bool typisvarlena;
1548  Oid typioparam;
1549  FunctionCallInfo fcinfo_in;
1550 
1551  /* evaluate argument into step's result area */
1552  ExecInitExprRec(iocoerce->arg, state, resv, resnull);
1553 
1554  /*
1555  * Prepare both output and input function calls, to be
1556  * evaluated inside a single evaluation step for speed - this
1557  * can be a very common operation.
1558  *
1559  * We don't check permissions here as a type's input/output
1560  * function are assumed to be executable by everyone.
1561  */
1562  scratch.opcode = EEOP_IOCOERCE;
1563 
1564  /* lookup the source type's output function */
1565  scratch.d.iocoerce.finfo_out = palloc0(sizeof(FmgrInfo));
1566  scratch.d.iocoerce.fcinfo_data_out = palloc0(SizeForFunctionCallInfo(1));
1567 
1568  getTypeOutputInfo(exprType((Node *) iocoerce->arg),
1569  &iofunc, &typisvarlena);
1570  fmgr_info(iofunc, scratch.d.iocoerce.finfo_out);
1571  fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_out);
1572  InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_out,
1573  scratch.d.iocoerce.finfo_out,
1574  1, InvalidOid, NULL, NULL);
1575 
1576  /* lookup the result type's input function */
1577  scratch.d.iocoerce.finfo_in = palloc0(sizeof(FmgrInfo));
1578  scratch.d.iocoerce.fcinfo_data_in = palloc0(SizeForFunctionCallInfo(3));
1579 
1580  getTypeInputInfo(iocoerce->resulttype,
1581  &iofunc, &typioparam);
1582  fmgr_info(iofunc, scratch.d.iocoerce.finfo_in);
1583  fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_in);
1584  InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_in,
1585  scratch.d.iocoerce.finfo_in,
1586  3, InvalidOid, NULL, NULL);
1587 
1588  /*
1589  * We can preload the second and third arguments for the input
1590  * function, since they're constants.
1591  */
1592  fcinfo_in = scratch.d.iocoerce.fcinfo_data_in;
1593  fcinfo_in->args[1].value = ObjectIdGetDatum(typioparam);
1594  fcinfo_in->args[1].isnull = false;
1595  fcinfo_in->args[2].value = Int32GetDatum(-1);
1596  fcinfo_in->args[2].isnull = false;
1597 
1598  ExprEvalPushStep(state, &scratch);
1599  break;
1600  }
1601 
1602  case T_ArrayCoerceExpr:
1603  {
1604  ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
1605  Oid resultelemtype;
1606  ExprState *elemstate;
1607 
1608  /* evaluate argument into step's result area */
1609  ExecInitExprRec(acoerce->arg, state, resv, resnull);
1610 
1611  resultelemtype = get_element_type(acoerce->resulttype);
1612  if (!OidIsValid(resultelemtype))
1613  ereport(ERROR,
1614  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1615  errmsg("target type is not an array")));
1616 
1617  /*
1618  * Construct a sub-expression for the per-element expression;
1619  * but don't ready it until after we check it for triviality.
1620  * We assume it hasn't any Var references, but does have a
1621  * CaseTestExpr representing the source array element values.
1622  */
1623  elemstate = makeNode(ExprState);
1624  elemstate->expr = acoerce->elemexpr;
1625  elemstate->parent = state->parent;
1626  elemstate->ext_params = state->ext_params;
1627 
1628  elemstate->innermost_caseval = (Datum *) palloc(sizeof(Datum));
1629  elemstate->innermost_casenull = (bool *) palloc(sizeof(bool));
1630 
1631  ExecInitExprRec(acoerce->elemexpr, elemstate,
1632  &elemstate->resvalue, &elemstate->resnull);
1633 
1634  if (elemstate->steps_len == 1 &&
1635  elemstate->steps[0].opcode == EEOP_CASE_TESTVAL)
1636  {
1637  /* Trivial, so we need no per-element work at runtime */
1638  elemstate = NULL;
1639  }
1640  else
1641  {
1642  /* Not trivial, so append a DONE step */
1643  scratch.opcode = EEOP_DONE;
1644  ExprEvalPushStep(elemstate, &scratch);
1645  /* and ready the subexpression */
1646  ExecReadyExpr(elemstate);
1647  }
1648 
1649  scratch.opcode = EEOP_ARRAYCOERCE;
1650  scratch.d.arraycoerce.elemexprstate = elemstate;
1651  scratch.d.arraycoerce.resultelemtype = resultelemtype;
1652 
1653  if (elemstate)
1654  {
1655  /* Set up workspace for array_map */
1656  scratch.d.arraycoerce.amstate =
1657  (ArrayMapState *) palloc0(sizeof(ArrayMapState));
1658  }
1659  else
1660  {
1661  /* Don't need workspace if there's no subexpression */
1662  scratch.d.arraycoerce.amstate = NULL;
1663  }
1664 
1665  ExprEvalPushStep(state, &scratch);
1666  break;
1667  }
1668 
1669  case T_ConvertRowtypeExpr:
1670  {
1672  ExprEvalRowtypeCache *rowcachep;
1673 
1674  /* cache structs must be out-of-line for space reasons */
1675  rowcachep = palloc(2 * sizeof(ExprEvalRowtypeCache));
1676  rowcachep[0].cacheptr = NULL;
1677  rowcachep[1].cacheptr = NULL;
1678 
1679  /* evaluate argument into step's result area */
1680  ExecInitExprRec(convert->arg, state, resv, resnull);
1681 
1682  /* and push conversion step */
1683  scratch.opcode = EEOP_CONVERT_ROWTYPE;
1684  scratch.d.convert_rowtype.inputtype =
1685  exprType((Node *) convert->arg);
1686  scratch.d.convert_rowtype.outputtype = convert->resulttype;
1687  scratch.d.convert_rowtype.incache = &rowcachep[0];
1688  scratch.d.convert_rowtype.outcache = &rowcachep[1];
1689  scratch.d.convert_rowtype.map = NULL;
1690 
1691  ExprEvalPushStep(state, &scratch);
1692  break;
1693  }
1694 
1695  /* note that CaseWhen expressions are handled within this block */
1696  case T_CaseExpr:
1697  {
1698  CaseExpr *caseExpr = (CaseExpr *) node;
1699  List *adjust_jumps = NIL;
1700  Datum *caseval = NULL;
1701  bool *casenull = NULL;
1702  ListCell *lc;
1703 
1704  /*
1705  * If there's a test expression, we have to evaluate it and
1706  * save the value where the CaseTestExpr placeholders can find
1707  * it.
1708  */
1709  if (caseExpr->arg != NULL)
1710  {
1711  /* Evaluate testexpr into caseval/casenull workspace */
1712  caseval = palloc(sizeof(Datum));
1713  casenull = palloc(sizeof(bool));
1714 
1715  ExecInitExprRec(caseExpr->arg, state,
1716  caseval, casenull);
1717 
1718  /*
1719  * Since value might be read multiple times, force to R/O
1720  * - but only if it could be an expanded datum.
1721  */
1722  if (get_typlen(exprType((Node *) caseExpr->arg)) == -1)
1723  {
1724  /* change caseval in-place */
1725  scratch.opcode = EEOP_MAKE_READONLY;
1726  scratch.resvalue = caseval;
1727  scratch.resnull = casenull;
1728  scratch.d.make_readonly.value = caseval;
1729  scratch.d.make_readonly.isnull = casenull;
1730  ExprEvalPushStep(state, &scratch);
1731  /* restore normal settings of scratch fields */
1732  scratch.resvalue = resv;
1733  scratch.resnull = resnull;
1734  }
1735  }
1736 
1737  /*
1738  * Prepare to evaluate each of the WHEN clauses in turn; as
1739  * soon as one is true we return the value of the
1740  * corresponding THEN clause. If none are true then we return
1741  * the value of the ELSE clause, or NULL if there is none.
1742  */
1743  foreach(lc, caseExpr->args)
1744  {
1745  CaseWhen *when = (CaseWhen *) lfirst(lc);
1746  Datum *save_innermost_caseval;
1747  bool *save_innermost_casenull;
1748  int whenstep;
1749 
1750  /*
1751  * Make testexpr result available to CaseTestExpr nodes
1752  * within the condition. We must save and restore prior
1753  * setting of innermost_caseval fields, in case this node
1754  * is itself within a larger CASE.
1755  *
1756  * If there's no test expression, we don't actually need
1757  * to save and restore these fields; but it's less code to
1758  * just do so unconditionally.
1759  */
1760  save_innermost_caseval = state->innermost_caseval;
1761  save_innermost_casenull = state->innermost_casenull;
1762  state->innermost_caseval = caseval;
1763  state->innermost_casenull = casenull;
1764 
1765  /* evaluate condition into CASE's result variables */
1766  ExecInitExprRec(when->expr, state, resv, resnull);
1767 
1768  state->innermost_caseval = save_innermost_caseval;
1769  state->innermost_casenull = save_innermost_casenull;
1770 
1771  /* If WHEN result isn't true, jump to next CASE arm */
1772  scratch.opcode = EEOP_JUMP_IF_NOT_TRUE;
1773  scratch.d.jump.jumpdone = -1; /* computed later */
1774  ExprEvalPushStep(state, &scratch);
1775  whenstep = state->steps_len - 1;
1776 
1777  /*
1778  * If WHEN result is true, evaluate THEN result, storing
1779  * it into the CASE's result variables.
1780  */
1781  ExecInitExprRec(when->result, state, resv, resnull);
1782 
1783  /* Emit JUMP step to jump to end of CASE's code */
1784  scratch.opcode = EEOP_JUMP;
1785  scratch.d.jump.jumpdone = -1; /* computed later */
1786  ExprEvalPushStep(state, &scratch);
1787 
1788  /*
1789  * Don't know address for that jump yet, compute once the
1790  * whole CASE expression is built.
1791  */
1792  adjust_jumps = lappend_int(adjust_jumps,
1793  state->steps_len - 1);
1794 
1795  /*
1796  * But we can set WHEN test's jump target now, to make it
1797  * jump to the next WHEN subexpression or the ELSE.
1798  */
1799  state->steps[whenstep].d.jump.jumpdone = state->steps_len;
1800  }
1801 
1802  /* transformCaseExpr always adds a default */
1803  Assert(caseExpr->defresult);
1804 
1805  /* evaluate ELSE expr into CASE's result variables */
1806  ExecInitExprRec(caseExpr->defresult, state,
1807  resv, resnull);
1808 
1809  /* adjust jump targets */
1810  foreach(lc, adjust_jumps)
1811  {
1812  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
1813 
1814  Assert(as->opcode == EEOP_JUMP);
1815  Assert(as->d.jump.jumpdone == -1);
1816  as->d.jump.jumpdone = state->steps_len;
1817  }
1818 
1819  break;
1820  }
1821 
1822  case T_CaseTestExpr:
1823  {
1824  /*
1825  * Read from location identified by innermost_caseval. Note
1826  * that innermost_caseval could be NULL, if this node isn't
1827  * actually within a CaseExpr, ArrayCoerceExpr, etc structure.
1828  * That can happen because some parts of the system abuse
1829  * CaseTestExpr to cause a read of a value externally supplied
1830  * in econtext->caseValue_datum. We'll take care of that
1831  * scenario at runtime.
1832  */
1833  scratch.opcode = EEOP_CASE_TESTVAL;
1834  scratch.d.casetest.value = state->innermost_caseval;
1835  scratch.d.casetest.isnull = state->innermost_casenull;
1836 
1837  ExprEvalPushStep(state, &scratch);
1838  break;
1839  }
1840 
1841  case T_ArrayExpr:
1842  {
1843  ArrayExpr *arrayexpr = (ArrayExpr *) node;
1844  int nelems = list_length(arrayexpr->elements);
1845  ListCell *lc;
1846  int elemoff;
1847 
1848  /*
1849  * Evaluate by computing each element, and then forming the
1850  * array. Elements are computed into scratch arrays
1851  * associated with the ARRAYEXPR step.
1852  */
1853  scratch.opcode = EEOP_ARRAYEXPR;
1854  scratch.d.arrayexpr.elemvalues =
1855  (Datum *) palloc(sizeof(Datum) * nelems);
1856  scratch.d.arrayexpr.elemnulls =
1857  (bool *) palloc(sizeof(bool) * nelems);
1858  scratch.d.arrayexpr.nelems = nelems;
1859 
1860  /* fill remaining fields of step */
1861  scratch.d.arrayexpr.multidims = arrayexpr->multidims;
1862  scratch.d.arrayexpr.elemtype = arrayexpr->element_typeid;
1863 
1864  /* do one-time catalog lookup for type info */
1866  &scratch.d.arrayexpr.elemlength,
1867  &scratch.d.arrayexpr.elembyval,
1868  &scratch.d.arrayexpr.elemalign);
1869 
1870  /* prepare to evaluate all arguments */
1871  elemoff = 0;
1872  foreach(lc, arrayexpr->elements)
1873  {
1874  Expr *e = (Expr *) lfirst(lc);
1875 
1876  ExecInitExprRec(e, state,
1877  &scratch.d.arrayexpr.elemvalues[elemoff],
1878  &scratch.d.arrayexpr.elemnulls[elemoff]);
1879  elemoff++;
1880  }
1881 
1882  /* and then collect all into an array */
1883  ExprEvalPushStep(state, &scratch);
1884  break;
1885  }
1886 
1887  case T_RowExpr:
1888  {
1889  RowExpr *rowexpr = (RowExpr *) node;
1890  int nelems = list_length(rowexpr->args);
1891  TupleDesc tupdesc;
1892  int i;
1893  ListCell *l;
1894 
1895  /* Build tupdesc to describe result tuples */
1896  if (rowexpr->row_typeid == RECORDOID)
1897  {
1898  /* generic record, use types of given expressions */
1899  tupdesc = ExecTypeFromExprList(rowexpr->args);
1900  }
1901  else
1902  {
1903  /* it's been cast to a named type, use that */
1904  tupdesc = lookup_rowtype_tupdesc_copy(rowexpr->row_typeid, -1);
1905  }
1906  /* In either case, adopt RowExpr's column aliases */
1907  ExecTypeSetColNames(tupdesc, rowexpr->colnames);
1908  /* Bless the tupdesc in case it's now of type RECORD */
1909  BlessTupleDesc(tupdesc);
1910 
1911  /*
1912  * In the named-type case, the tupdesc could have more columns
1913  * than are in the args list, since the type might have had
1914  * columns added since the ROW() was parsed. We want those
1915  * extra columns to go to nulls, so we make sure that the
1916  * workspace arrays are large enough and then initialize any
1917  * extra columns to read as NULLs.
1918  */
1919  Assert(nelems <= tupdesc->natts);
1920  nelems = Max(nelems, tupdesc->natts);
1921 
1922  /*
1923  * Evaluate by first building datums for each field, and then
1924  * a final step forming the composite datum.
1925  */
1926  scratch.opcode = EEOP_ROW;
1927  scratch.d.row.tupdesc = tupdesc;
1928 
1929  /* space for the individual field datums */
1930  scratch.d.row.elemvalues =
1931  (Datum *) palloc(sizeof(Datum) * nelems);
1932  scratch.d.row.elemnulls =
1933  (bool *) palloc(sizeof(bool) * nelems);
1934  /* as explained above, make sure any extra columns are null */
1935  memset(scratch.d.row.elemnulls, true, sizeof(bool) * nelems);
1936 
1937  /* Set up evaluation, skipping any deleted columns */
1938  i = 0;
1939  foreach(l, rowexpr->args)
1940  {
1941  Form_pg_attribute att = TupleDescAttr(tupdesc, i);
1942  Expr *e = (Expr *) lfirst(l);
1943 
1944  if (!att->attisdropped)
1945  {
1946  /*
1947  * Guard against ALTER COLUMN TYPE on rowtype since
1948  * the RowExpr was created. XXX should we check
1949  * typmod too? Not sure we can be sure it'll be the
1950  * same.
1951  */
1952  if (exprType((Node *) e) != att->atttypid)
1953  ereport(ERROR,
1954  (errcode(ERRCODE_DATATYPE_MISMATCH),
1955  errmsg("ROW() column has type %s instead of type %s",
1956  format_type_be(exprType((Node *) e)),
1957  format_type_be(att->atttypid))));
1958  }
1959  else
1960  {
1961  /*
1962  * Ignore original expression and insert a NULL. We
1963  * don't really care what type of NULL it is, so
1964  * always make an int4 NULL.
1965  */
1966  e = (Expr *) makeNullConst(INT4OID, -1, InvalidOid);
1967  }
1968 
1969  /* Evaluate column expr into appropriate workspace slot */
1970  ExecInitExprRec(e, state,
1971  &scratch.d.row.elemvalues[i],
1972  &scratch.d.row.elemnulls[i]);
1973  i++;
1974  }
1975 
1976  /* And finally build the row value */
1977  ExprEvalPushStep(state, &scratch);
1978  break;
1979  }
1980 
1981  case T_RowCompareExpr:
1982  {
1983  RowCompareExpr *rcexpr = (RowCompareExpr *) node;
1984  int nopers = list_length(rcexpr->opnos);
1985  List *adjust_jumps = NIL;
1986  ListCell *l_left_expr,
1987  *l_right_expr,
1988  *l_opno,
1989  *l_opfamily,
1990  *l_inputcollid;
1991  ListCell *lc;
1992 
1993  /*
1994  * Iterate over each field, prepare comparisons. To handle
1995  * NULL results, prepare jumps to after the expression. If a
1996  * comparison yields a != 0 result, jump to the final step.
1997  */
1998  Assert(list_length(rcexpr->largs) == nopers);
1999  Assert(list_length(rcexpr->rargs) == nopers);
2000  Assert(list_length(rcexpr->opfamilies) == nopers);
2001  Assert(list_length(rcexpr->inputcollids) == nopers);
2002 
2003  forfive(l_left_expr, rcexpr->largs,
2004  l_right_expr, rcexpr->rargs,
2005  l_opno, rcexpr->opnos,
2006  l_opfamily, rcexpr->opfamilies,
2007  l_inputcollid, rcexpr->inputcollids)
2008  {
2009  Expr *left_expr = (Expr *) lfirst(l_left_expr);
2010  Expr *right_expr = (Expr *) lfirst(l_right_expr);
2011  Oid opno = lfirst_oid(l_opno);
2012  Oid opfamily = lfirst_oid(l_opfamily);
2013  Oid inputcollid = lfirst_oid(l_inputcollid);
2014  int strategy;
2015  Oid lefttype;
2016  Oid righttype;
2017  Oid proc;
2018  FmgrInfo *finfo;
2019  FunctionCallInfo fcinfo;
2020 
2021  get_op_opfamily_properties(opno, opfamily, false,
2022  &strategy,
2023  &lefttype,
2024  &righttype);
2025  proc = get_opfamily_proc(opfamily,
2026  lefttype,
2027  righttype,
2028  BTORDER_PROC);
2029  if (!OidIsValid(proc))
2030  elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
2031  BTORDER_PROC, lefttype, righttype, opfamily);
2032 
2033  /* Set up the primary fmgr lookup information */
2034  finfo = palloc0(sizeof(FmgrInfo));
2035  fcinfo = palloc0(SizeForFunctionCallInfo(2));
2036  fmgr_info(proc, finfo);
2037  fmgr_info_set_expr((Node *) node, finfo);
2038  InitFunctionCallInfoData(*fcinfo, finfo, 2,
2039  inputcollid, NULL, NULL);
2040 
2041  /*
2042  * If we enforced permissions checks on index support
2043  * functions, we'd need to make a check here. But the
2044  * index support machinery doesn't do that, and thus
2045  * neither does this code.
2046  */
2047 
2048  /* evaluate left and right args directly into fcinfo */
2049  ExecInitExprRec(left_expr, state,
2050  &fcinfo->args[0].value, &fcinfo->args[0].isnull);
2051  ExecInitExprRec(right_expr, state,
2052  &fcinfo->args[1].value, &fcinfo->args[1].isnull);
2053 
2054  scratch.opcode = EEOP_ROWCOMPARE_STEP;
2055  scratch.d.rowcompare_step.finfo = finfo;
2056  scratch.d.rowcompare_step.fcinfo_data = fcinfo;
2057  scratch.d.rowcompare_step.fn_addr = finfo->fn_addr;
2058  /* jump targets filled below */
2059  scratch.d.rowcompare_step.jumpnull = -1;
2060  scratch.d.rowcompare_step.jumpdone = -1;
2061 
2062  ExprEvalPushStep(state, &scratch);
2063  adjust_jumps = lappend_int(adjust_jumps,
2064  state->steps_len - 1);
2065  }
2066 
2067  /*
2068  * We could have a zero-column rowtype, in which case the rows
2069  * necessarily compare equal.
2070  */
2071  if (nopers == 0)
2072  {
2073  scratch.opcode = EEOP_CONST;
2074  scratch.d.constval.value = Int32GetDatum(0);
2075  scratch.d.constval.isnull = false;
2076  ExprEvalPushStep(state, &scratch);
2077  }
2078 
2079  /* Finally, examine the last comparison result */
2080  scratch.opcode = EEOP_ROWCOMPARE_FINAL;
2081  scratch.d.rowcompare_final.rctype = rcexpr->rctype;
2082  ExprEvalPushStep(state, &scratch);
2083 
2084  /* adjust jump targets */
2085  foreach(lc, adjust_jumps)
2086  {
2087  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
2088 
2090  Assert(as->d.rowcompare_step.jumpdone == -1);
2091  Assert(as->d.rowcompare_step.jumpnull == -1);
2092 
2093  /* jump to comparison evaluation */
2094  as->d.rowcompare_step.jumpdone = state->steps_len - 1;
2095  /* jump to the following expression */
2096  as->d.rowcompare_step.jumpnull = state->steps_len;
2097  }
2098 
2099  break;
2100  }
2101 
2102  case T_CoalesceExpr:
2103  {
2104  CoalesceExpr *coalesce = (CoalesceExpr *) node;
2105  List *adjust_jumps = NIL;
2106  ListCell *lc;
2107 
2108  /* We assume there's at least one arg */
2109  Assert(coalesce->args != NIL);
2110 
2111  /*
2112  * Prepare evaluation of all coalesced arguments, after each
2113  * one push a step that short-circuits if not null.
2114  */
2115  foreach(lc, coalesce->args)
2116  {
2117  Expr *e = (Expr *) lfirst(lc);
2118 
2119  /* evaluate argument, directly into result datum */
2120  ExecInitExprRec(e, state, resv, resnull);
2121 
2122  /* if it's not null, skip to end of COALESCE expr */
2123  scratch.opcode = EEOP_JUMP_IF_NOT_NULL;
2124  scratch.d.jump.jumpdone = -1; /* adjust later */
2125  ExprEvalPushStep(state, &scratch);
2126 
2127  adjust_jumps = lappend_int(adjust_jumps,
2128  state->steps_len - 1);
2129  }
2130 
2131  /*
2132  * No need to add a constant NULL return - we only can get to
2133  * the end of the expression if a NULL already is being
2134  * returned.
2135  */
2136 
2137  /* adjust jump targets */
2138  foreach(lc, adjust_jumps)
2139  {
2140  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
2141 
2143  Assert(as->d.jump.jumpdone == -1);
2144  as->d.jump.jumpdone = state->steps_len;
2145  }
2146 
2147  break;
2148  }
2149 
2150  case T_MinMaxExpr:
2151  {
2152  MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
2153  int nelems = list_length(minmaxexpr->args);
2154  TypeCacheEntry *typentry;
2155  FmgrInfo *finfo;
2156  FunctionCallInfo fcinfo;
2157  ListCell *lc;
2158  int off;
2159 
2160  /* Look up the btree comparison function for the datatype */
2161  typentry = lookup_type_cache(minmaxexpr->minmaxtype,
2163  if (!OidIsValid(typentry->cmp_proc))
2164  ereport(ERROR,
2165  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2166  errmsg("could not identify a comparison function for type %s",
2167  format_type_be(minmaxexpr->minmaxtype))));
2168 
2169  /*
2170  * If we enforced permissions checks on index support
2171  * functions, we'd need to make a check here. But the index
2172  * support machinery doesn't do that, and thus neither does
2173  * this code.
2174  */
2175 
2176  /* Perform function lookup */
2177  finfo = palloc0(sizeof(FmgrInfo));
2178  fcinfo = palloc0(SizeForFunctionCallInfo(2));
2179  fmgr_info(typentry->cmp_proc, finfo);
2180  fmgr_info_set_expr((Node *) node, finfo);
2181  InitFunctionCallInfoData(*fcinfo, finfo, 2,
2182  minmaxexpr->inputcollid, NULL, NULL);
2183 
2184  scratch.opcode = EEOP_MINMAX;
2185  /* allocate space to store arguments */
2186  scratch.d.minmax.values =
2187  (Datum *) palloc(sizeof(Datum) * nelems);
2188  scratch.d.minmax.nulls =
2189  (bool *) palloc(sizeof(bool) * nelems);
2190  scratch.d.minmax.nelems = nelems;
2191 
2192  scratch.d.minmax.op = minmaxexpr->op;
2193  scratch.d.minmax.finfo = finfo;
2194  scratch.d.minmax.fcinfo_data = fcinfo;
2195 
2196  /* evaluate expressions into minmax->values/nulls */
2197  off = 0;
2198  foreach(lc, minmaxexpr->args)
2199  {
2200  Expr *e = (Expr *) lfirst(lc);
2201 
2202  ExecInitExprRec(e, state,
2203  &scratch.d.minmax.values[off],
2204  &scratch.d.minmax.nulls[off]);
2205  off++;
2206  }
2207 
2208  /* and push the final comparison */
2209  ExprEvalPushStep(state, &scratch);
2210  break;
2211  }
2212 
2213  case T_SQLValueFunction:
2214  {
2215  SQLValueFunction *svf = (SQLValueFunction *) node;
2216 
2217  scratch.opcode = EEOP_SQLVALUEFUNCTION;
2218  scratch.d.sqlvaluefunction.svf = svf;
2219 
2220  ExprEvalPushStep(state, &scratch);
2221  break;
2222  }
2223 
2224  case T_XmlExpr:
2225  {
2226  XmlExpr *xexpr = (XmlExpr *) node;
2227  int nnamed = list_length(xexpr->named_args);
2228  int nargs = list_length(xexpr->args);
2229  int off;
2230  ListCell *arg;
2231 
2232  scratch.opcode = EEOP_XMLEXPR;
2233  scratch.d.xmlexpr.xexpr = xexpr;
2234 
2235  /* allocate space for storing all the arguments */
2236  if (nnamed)
2237  {
2238  scratch.d.xmlexpr.named_argvalue =
2239  (Datum *) palloc(sizeof(Datum) * nnamed);
2240  scratch.d.xmlexpr.named_argnull =
2241  (bool *) palloc(sizeof(bool) * nnamed);
2242  }
2243  else
2244  {
2245  scratch.d.xmlexpr.named_argvalue = NULL;
2246  scratch.d.xmlexpr.named_argnull = NULL;
2247  }
2248 
2249  if (nargs)
2250  {
2251  scratch.d.xmlexpr.argvalue =
2252  (Datum *) palloc(sizeof(Datum) * nargs);
2253  scratch.d.xmlexpr.argnull =
2254  (bool *) palloc(sizeof(bool) * nargs);
2255  }
2256  else
2257  {
2258  scratch.d.xmlexpr.argvalue = NULL;
2259  scratch.d.xmlexpr.argnull = NULL;
2260  }
2261 
2262  /* prepare argument execution */
2263  off = 0;
2264  foreach(arg, xexpr->named_args)
2265  {
2266  Expr *e = (Expr *) lfirst(arg);
2267 
2268  ExecInitExprRec(e, state,
2269  &scratch.d.xmlexpr.named_argvalue[off],
2270  &scratch.d.xmlexpr.named_argnull[off]);
2271  off++;
2272  }
2273 
2274  off = 0;
2275  foreach(arg, xexpr->args)
2276  {
2277  Expr *e = (Expr *) lfirst(arg);
2278 
2279  ExecInitExprRec(e, state,
2280  &scratch.d.xmlexpr.argvalue[off],
2281  &scratch.d.xmlexpr.argnull[off]);
2282  off++;
2283  }
2284 
2285  /* and evaluate the actual XML expression */
2286  ExprEvalPushStep(state, &scratch);
2287  break;
2288  }
2289 
2290  case T_NullTest:
2291  {
2292  NullTest *ntest = (NullTest *) node;
2293 
2294  if (ntest->nulltesttype == IS_NULL)
2295  {
2296  if (ntest->argisrow)
2297  scratch.opcode = EEOP_NULLTEST_ROWISNULL;
2298  else
2299  scratch.opcode = EEOP_NULLTEST_ISNULL;
2300  }
2301  else if (ntest->nulltesttype == IS_NOT_NULL)
2302  {
2303  if (ntest->argisrow)
2305  else
2306  scratch.opcode = EEOP_NULLTEST_ISNOTNULL;
2307  }
2308  else
2309  {
2310  elog(ERROR, "unrecognized nulltesttype: %d",
2311  (int) ntest->nulltesttype);
2312  }
2313  /* initialize cache in case it's a row test */
2314  scratch.d.nulltest_row.rowcache.cacheptr = NULL;
2315 
2316  /* first evaluate argument into result variable */
2317  ExecInitExprRec(ntest->arg, state,
2318  resv, resnull);
2319 
2320  /* then push the test of that argument */
2321  ExprEvalPushStep(state, &scratch);
2322  break;
2323  }
2324 
2325  case T_BooleanTest:
2326  {
2327  BooleanTest *btest = (BooleanTest *) node;
2328 
2329  /*
2330  * Evaluate argument, directly into result datum. That's ok,
2331  * because resv/resnull is definitely not used anywhere else,
2332  * and will get overwritten by the below EEOP_BOOLTEST_IS_*
2333  * step.
2334  */
2335  ExecInitExprRec(btest->arg, state, resv, resnull);
2336 
2337  switch (btest->booltesttype)
2338  {
2339  case IS_TRUE:
2340  scratch.opcode = EEOP_BOOLTEST_IS_TRUE;
2341  break;
2342  case IS_NOT_TRUE:
2344  break;
2345  case IS_FALSE:
2346  scratch.opcode = EEOP_BOOLTEST_IS_FALSE;
2347  break;
2348  case IS_NOT_FALSE:
2350  break;
2351  case IS_UNKNOWN:
2352  /* Same as scalar IS NULL test */
2353  scratch.opcode = EEOP_NULLTEST_ISNULL;
2354  break;
2355  case IS_NOT_UNKNOWN:
2356  /* Same as scalar IS NOT NULL test */
2357  scratch.opcode = EEOP_NULLTEST_ISNOTNULL;
2358  break;
2359  default:
2360  elog(ERROR, "unrecognized booltesttype: %d",
2361  (int) btest->booltesttype);
2362  }
2363 
2364  ExprEvalPushStep(state, &scratch);
2365  break;
2366  }
2367 
2368  case T_CoerceToDomain:
2369  {
2370  CoerceToDomain *ctest = (CoerceToDomain *) node;
2371 
2372  ExecInitCoerceToDomain(&scratch, ctest, state,
2373  resv, resnull);
2374  break;
2375  }
2376 
2377  case T_CoerceToDomainValue:
2378  {
2379  /*
2380  * Read from location identified by innermost_domainval. Note
2381  * that innermost_domainval could be NULL, if we're compiling
2382  * a standalone domain check rather than one embedded in a
2383  * larger expression. In that case we must read from
2384  * econtext->domainValue_datum. We'll take care of that
2385  * scenario at runtime.
2386  */
2387  scratch.opcode = EEOP_DOMAIN_TESTVAL;
2388  /* we share instruction union variant with case testval */
2389  scratch.d.casetest.value = state->innermost_domainval;
2390  scratch.d.casetest.isnull = state->innermost_domainnull;
2391 
2392  ExprEvalPushStep(state, &scratch);
2393  break;
2394  }
2395 
2396  case T_CurrentOfExpr:
2397  {
2398  scratch.opcode = EEOP_CURRENTOFEXPR;
2399  ExprEvalPushStep(state, &scratch);
2400  break;
2401  }
2402 
2403  case T_NextValueExpr:
2404  {
2405  NextValueExpr *nve = (NextValueExpr *) node;
2406 
2407  scratch.opcode = EEOP_NEXTVALUEEXPR;
2408  scratch.d.nextvalueexpr.seqid = nve->seqid;
2409  scratch.d.nextvalueexpr.seqtypid = nve->typeId;
2410 
2411  ExprEvalPushStep(state, &scratch);
2412  break;
2413  }
2414 
2415  default:
2416  elog(ERROR, "unrecognized node type: %d",
2417  (int) nodeTag(node));
2418  break;
2419  }
2420 }
Datum constvalue
Definition: primnodes.h:219
Oid minmaxtype
Definition: primnodes.h:1138
struct ExprEvalStep::@49::@86 subplan
bool multidims
Definition: primnodes.h:1028
#define NIL
Definition: pg_list.h:65
static void ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:3111
Definition: fmgr.h:56
List * args
Definition: primnodes.h:1142
struct ExprEvalStep::@49::@80 scalararrayop
List * args
Definition: primnodes.h:1058
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
static void ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, ExprState *state)
Definition: execExpr.c:2774
#define BTORDER_PROC
Definition: nbtree.h:700
Expr * arg
Definition: primnodes.h:827
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:795
List * args
Definition: primnodes.h:390
List * args
Definition: primnodes.h:503
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1826
Datum * resvalue
Definition: execExpr.h:273
Oid GetUserId(void)
Definition: miscinit.c:478
Oid resulttype
Definition: primnodes.h:800
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:871
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
RowCompareType rctype
Definition: primnodes.h:1106
List * opfamilies
Definition: primnodes.h:1108
bool * resnull
Definition: execExpr.h:274
List * subPlan
Definition: execnodes.h:992
ParamListInfo ext_params
Definition: execnodes.h:109
Expr * arg
Definition: primnodes.h:850
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:798
struct ExprEvalStep::@49::@83 aggref
struct ExprEvalStep::@49::@67 nextvalueexpr
Datum * innermost_domainval
Definition: execnodes.h:114
EState * state
Definition: execnodes.h:967
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:2847
ParamCompileHook paramCompile
Definition: params.h:114
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3313
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:1074
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:1122
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:615
Expr * arg
Definition: primnodes.h:1255
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:3459
Expr * arg
Definition: primnodes.h:1278
#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:203
Oid resulttype
Definition: primnodes.h:830
Expr * arg
Definition: primnodes.h:870
List * elements
Definition: primnodes.h:1027
Expr * elemexpr
Definition: primnodes.h:895
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:828
#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:969
void * palloc0(Size size)
Definition: mcxt.c:1093
AclResult
Definition: acl.h:177
struct ExprEvalStep::@49::@75 fieldstore
BoolTestType booltesttype
Definition: primnodes.h:1279
uintptr_t Datum
Definition: postgres.h:411
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2429
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:1256
struct ExprEvalStep::@49::@64 make_readonly
Plan * plan
Definition: execnodes.h:965
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:338
#define InvalidOid
Definition: postgres_ext.h:36
List * named_args
Definition: primnodes.h:1219
#define ereport(elevel,...)
Definition: elog.h:157
#define INNER_VAR
Definition: primnodes.h:175
List * args
Definition: primnodes.h:1221
#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:1059
static int list_length(const List *l)
Definition: pg_list.h:149
Oid inputcollid
Definition: primnodes.h:1140
Oid inputcollid
Definition: primnodes.h:547
static void ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, Oid inputcollid, ExprState *state)
Definition: execExpr.c:2455
struct ExprEvalStep::@49::@66 sqlvaluefunction
List * args
Definition: primnodes.h:616
#define InvalidAttrNumber
Definition: attnum.h:23
#define nodeTag(nodeptr)
Definition: nodes.h:544
Oid element_typeid
Definition: primnodes.h:1026
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:829
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:4723
#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:593
bool argisrow
Definition: primnodes.h:1257
MinMaxOp op
Definition: primnodes.h:1141
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:123
Expr * arg
Definition: primnodes.h:968
Definition: plannodes.h:857
struct ExprEvalStep::@49::@65 iocoerce
WindowFunc * wfunc
Definition: execnodes.h:793
List * aggs
Definition: execnodes.h:2275
Expr * result
Definition: primnodes.h:981
List * args
Definition: primnodes.h:548
List * inputcollids
Definition: primnodes.h:1109
Expr * defresult
Definition: primnodes.h:970
Expr * expr
Definition: primnodes.h:980
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:1860
Definition: nodes.h:159
AttrNumber fieldnum
Definition: primnodes.h:799

◆ ExecInitExprSlots()

static void ExecInitExprSlots ( ExprState state,
Node node 
)
static

Definition at line 2560 of file execExpr.c.

References ExecPushExprSlots(), and get_last_attnums_walker().

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

2561 {
2562  LastAttnumInfo info = {0, 0, 0};
2563 
2564  /*
2565  * Figure out which attributes we're going to need.
2566  */
2567  get_last_attnums_walker(node, &info);
2568 
2569  ExecPushExprSlots(state, &info);
2570 }
static void ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
Definition: execExpr.c:2578
static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info)
Definition: execExpr.c:2622

◆ 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:2560
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:2429
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 2455 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().

2457 {
2458  int nargs = list_length(args);
2459  AclResult aclresult;
2460  FmgrInfo *flinfo;
2461  FunctionCallInfo fcinfo;
2462  int argno;
2463  ListCell *lc;
2464 
2465  /* Check permission to call function */
2466  aclresult = pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE);
2467  if (aclresult != ACLCHECK_OK)
2468  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(funcid));
2469  InvokeFunctionExecuteHook(funcid);
2470 
2471  /*
2472  * Safety check on nargs. Under normal circumstances this should never
2473  * fail, as parser should check sooner. But possibly it might fail if
2474  * server has been compiled with FUNC_MAX_ARGS smaller than some functions
2475  * declared in pg_proc?
2476  */
2477  if (nargs > FUNC_MAX_ARGS)
2478  ereport(ERROR,
2479  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2480  errmsg_plural("cannot pass more than %d argument to a function",
2481  "cannot pass more than %d arguments to a function",
2482  FUNC_MAX_ARGS,
2483  FUNC_MAX_ARGS)));
2484 
2485  /* Allocate function lookup data and parameter workspace for this call */
2486  scratch->d.func.finfo = palloc0(sizeof(FmgrInfo));
2487  scratch->d.func.fcinfo_data = palloc0(SizeForFunctionCallInfo(nargs));
2488  flinfo = scratch->d.func.finfo;
2489  fcinfo = scratch->d.func.fcinfo_data;
2490 
2491  /* Set up the primary fmgr lookup information */
2492  fmgr_info(funcid, flinfo);
2493  fmgr_info_set_expr((Node *) node, flinfo);
2494 
2495  /* Initialize function call parameter structure too */
2496  InitFunctionCallInfoData(*fcinfo, flinfo,
2497  nargs, inputcollid, NULL, NULL);
2498 
2499  /* Keep extra copies of this info to save an indirection at runtime */
2500  scratch->d.func.fn_addr = flinfo->fn_addr;
2501  scratch->d.func.nargs = nargs;
2502 
2503  /* We only support non-set functions here */
2504  if (flinfo->fn_retset)
2505  ereport(ERROR,
2506  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2507  errmsg("set-valued function called in context that cannot accept a set"),
2508  state->parent ?
2510  exprLocation((Node *) node)) : 0));
2511 
2512  /* Build code to evaluate arguments directly into the fcinfo struct */
2513  argno = 0;
2514  foreach(lc, args)
2515  {
2516  Expr *arg = (Expr *) lfirst(lc);
2517 
2518  if (IsA(arg, Const))
2519  {
2520  /*
2521  * Don't evaluate const arguments every round; especially
2522  * interesting for constants in comparisons.
2523  */
2524  Const *con = (Const *) arg;
2525 
2526  fcinfo->args[argno].value = con->constvalue;
2527  fcinfo->args[argno].isnull = con->constisnull;
2528  }
2529  else
2530  {
2531  ExecInitExprRec(arg, state,
2532  &fcinfo->args[argno].value,
2533  &fcinfo->args[argno].isnull);
2534  }
2535  argno++;
2536  }
2537 
2538  /* Insert appropriate opcode depending on strictness and stats level */
2539  if (pgstat_track_functions <= flinfo->fn_stats)
2540  {
2541  if (flinfo->fn_strict && nargs > 0)
2542  scratch->opcode = EEOP_FUNCEXPR_STRICT;
2543  else
2544  scratch->opcode = EEOP_FUNCEXPR;
2545  }
2546  else
2547  {
2548  if (flinfo->fn_strict && nargs > 0)
2550  else
2551  scratch->opcode = EEOP_FUNCEXPR_FUSAGE;
2552  }
2553 }
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:967
#define FUNC_MAX_ARGS
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3313
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:4723
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:2560
#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:2429
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 2847 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().

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