PostgreSQL Source Code  git master
execExpr.c File Reference
#include "postgres.h"
#include "access/nbtree.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_proc.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 3263 of file execExpr.c.

3265 {
3267  PlanState *parent = &aggstate->ss.ps;
3268  ExprEvalStep scratch = {0};
3269  bool isCombine = DO_AGGSPLIT_COMBINE(aggstate->aggsplit);
3270  LastAttnumInfo deform = {0, 0, 0};
3271 
3272  state->expr = (Expr *) aggstate;
3273  state->parent = parent;
3274 
3275  scratch.resvalue = &state->resvalue;
3276  scratch.resnull = &state->resnull;
3277 
3278  /*
3279  * First figure out which slots, and how many columns from each, we're
3280  * going to need.
3281  */
3282  for (int transno = 0; transno < aggstate->numtrans; transno++)
3283  {
3284  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3285 
3287  &deform);
3288  get_last_attnums_walker((Node *) pertrans->aggref->args,
3289  &deform);
3291  &deform);
3293  &deform);
3295  &deform);
3296  }
3297  ExecPushExprSlots(state, &deform);
3298 
3299  /*
3300  * Emit instructions for each transition value / grouping set combination.
3301  */
3302  for (int transno = 0; transno < aggstate->numtrans; transno++)
3303  {
3304  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3305  FunctionCallInfo trans_fcinfo = pertrans->transfn_fcinfo;
3306  List *adjust_bailout = NIL;
3307  NullableDatum *strictargs = NULL;
3308  bool *strictnulls = NULL;
3309  int argno;
3310  ListCell *bail;
3311 
3312  /*
3313  * If filter present, emit. Do so before evaluating the input, to
3314  * avoid potentially unneeded computations, or even worse, unintended
3315  * side-effects. When combining, all the necessary filtering has
3316  * already been done.
3317  */
3318  if (pertrans->aggref->aggfilter && !isCombine)
3319  {
3320  /* evaluate filter expression */
3321  ExecInitExprRec(pertrans->aggref->aggfilter, state,
3322  &state->resvalue, &state->resnull);
3323  /* and jump out if false */
3324  scratch.opcode = EEOP_JUMP_IF_NOT_TRUE;
3325  scratch.d.jump.jumpdone = -1; /* adjust later */
3326  ExprEvalPushStep(state, &scratch);
3327  adjust_bailout = lappend_int(adjust_bailout,
3328  state->steps_len - 1);
3329  }
3330 
3331  /*
3332  * Evaluate arguments to aggregate/combine function.
3333  */
3334  argno = 0;
3335  if (isCombine)
3336  {
3337  /*
3338  * Combining two aggregate transition values. Instead of directly
3339  * coming from a tuple the input is a, potentially deserialized,
3340  * transition value.
3341  */
3342  TargetEntry *source_tle;
3343 
3344  Assert(pertrans->numSortCols == 0);
3345  Assert(list_length(pertrans->aggref->args) == 1);
3346 
3347  strictargs = trans_fcinfo->args + 1;
3348  source_tle = (TargetEntry *) linitial(pertrans->aggref->args);
3349 
3350  /*
3351  * deserialfn_oid will be set if we must deserialize the input
3352  * state before calling the combine function.
3353  */
3354  if (!OidIsValid(pertrans->deserialfn_oid))
3355  {
3356  /*
3357  * Start from 1, since the 0th arg will be the transition
3358  * value
3359  */
3360  ExecInitExprRec(source_tle->expr, state,
3361  &trans_fcinfo->args[argno + 1].value,
3362  &trans_fcinfo->args[argno + 1].isnull);
3363  }
3364  else
3365  {
3366  FunctionCallInfo ds_fcinfo = pertrans->deserialfn_fcinfo;
3367 
3368  /* evaluate argument */
3369  ExecInitExprRec(source_tle->expr, state,
3370  &ds_fcinfo->args[0].value,
3371  &ds_fcinfo->args[0].isnull);
3372 
3373  /* Dummy second argument for type-safety reasons */
3374  ds_fcinfo->args[1].value = PointerGetDatum(NULL);
3375  ds_fcinfo->args[1].isnull = false;
3376 
3377  /*
3378  * Don't call a strict deserialization function with NULL
3379  * input
3380  */
3381  if (pertrans->deserialfn.fn_strict)
3383  else
3384  scratch.opcode = EEOP_AGG_DESERIALIZE;
3385 
3386  scratch.d.agg_deserialize.fcinfo_data = ds_fcinfo;
3387  scratch.d.agg_deserialize.jumpnull = -1; /* adjust later */
3388  scratch.resvalue = &trans_fcinfo->args[argno + 1].value;
3389  scratch.resnull = &trans_fcinfo->args[argno + 1].isnull;
3390 
3391  ExprEvalPushStep(state, &scratch);
3392  /* don't add an adjustment unless the function is strict */
3393  if (pertrans->deserialfn.fn_strict)
3394  adjust_bailout = lappend_int(adjust_bailout,
3395  state->steps_len - 1);
3396 
3397  /* restore normal settings of scratch fields */
3398  scratch.resvalue = &state->resvalue;
3399  scratch.resnull = &state->resnull;
3400  }
3401  argno++;
3402 
3403  Assert(pertrans->numInputs == argno);
3404  }
3405  else if (!pertrans->aggsortrequired)
3406  {
3407  ListCell *arg;
3408 
3409  /*
3410  * Normal transition function without ORDER BY / DISTINCT or with
3411  * ORDER BY / DISTINCT but the planner has given us pre-sorted
3412  * input.
3413  */
3414  strictargs = trans_fcinfo->args + 1;
3415 
3416  foreach(arg, pertrans->aggref->args)
3417  {
3418  TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3419 
3420  /*
3421  * Don't initialize args for any ORDER BY clause that might
3422  * exist in a presorted aggregate.
3423  */
3424  if (argno == pertrans->numTransInputs)
3425  break;
3426 
3427  /*
3428  * Start from 1, since the 0th arg will be the transition
3429  * value
3430  */
3431  ExecInitExprRec(source_tle->expr, state,
3432  &trans_fcinfo->args[argno + 1].value,
3433  &trans_fcinfo->args[argno + 1].isnull);
3434  argno++;
3435  }
3436  Assert(pertrans->numTransInputs == argno);
3437  }
3438  else if (pertrans->numInputs == 1)
3439  {
3440  /*
3441  * Non-presorted DISTINCT and/or ORDER BY case, with a single
3442  * column sorted on.
3443  */
3444  TargetEntry *source_tle =
3445  (TargetEntry *) linitial(pertrans->aggref->args);
3446 
3447  Assert(list_length(pertrans->aggref->args) == 1);
3448 
3449  ExecInitExprRec(source_tle->expr, state,
3450  &state->resvalue,
3451  &state->resnull);
3452  strictnulls = &state->resnull;
3453  argno++;
3454 
3455  Assert(pertrans->numInputs == argno);
3456  }
3457  else
3458  {
3459  /*
3460  * Non-presorted DISTINCT and/or ORDER BY case, with multiple
3461  * columns sorted on.
3462  */
3463  Datum *values = pertrans->sortslot->tts_values;
3464  bool *nulls = pertrans->sortslot->tts_isnull;
3465  ListCell *arg;
3466 
3467  strictnulls = nulls;
3468 
3469  foreach(arg, pertrans->aggref->args)
3470  {
3471  TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3472 
3473  ExecInitExprRec(source_tle->expr, state,
3474  &values[argno], &nulls[argno]);
3475  argno++;
3476  }
3477  Assert(pertrans->numInputs == argno);
3478  }
3479 
3480  /*
3481  * For a strict transfn, nothing happens when there's a NULL input; we
3482  * just keep the prior transValue. This is true for both plain and
3483  * sorted/distinct aggregates.
3484  */
3485  if (trans_fcinfo->flinfo->fn_strict && pertrans->numTransInputs > 0)
3486  {
3487  if (strictnulls)
3489  else
3491  scratch.d.agg_strict_input_check.nulls = strictnulls;
3492  scratch.d.agg_strict_input_check.args = strictargs;
3493  scratch.d.agg_strict_input_check.jumpnull = -1; /* adjust later */
3494  scratch.d.agg_strict_input_check.nargs = pertrans->numTransInputs;
3495  ExprEvalPushStep(state, &scratch);
3496  adjust_bailout = lappend_int(adjust_bailout,
3497  state->steps_len - 1);
3498  }
3499 
3500  /* Handle DISTINCT aggregates which have pre-sorted input */
3501  if (pertrans->numDistinctCols > 0 && !pertrans->aggsortrequired)
3502  {
3503  if (pertrans->numDistinctCols > 1)
3505  else
3507 
3508  scratch.d.agg_presorted_distinctcheck.pertrans = pertrans;
3509  scratch.d.agg_presorted_distinctcheck.jumpdistinct = -1; /* adjust later */
3510  ExprEvalPushStep(state, &scratch);
3511  adjust_bailout = lappend_int(adjust_bailout,
3512  state->steps_len - 1);
3513  }
3514 
3515  /*
3516  * Call transition function (once for each concurrently evaluated
3517  * grouping set). Do so for both sort and hash based computations, as
3518  * applicable.
3519  */
3520  if (doSort)
3521  {
3522  int processGroupingSets = Max(phase->numsets, 1);
3523  int setoff = 0;
3524 
3525  for (int setno = 0; setno < processGroupingSets; setno++)
3526  {
3527  ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3528  pertrans, transno, setno, setoff, false,
3529  nullcheck);
3530  setoff++;
3531  }
3532  }
3533 
3534  if (doHash)
3535  {
3536  int numHashes = aggstate->num_hashes;
3537  int setoff;
3538 
3539  /* in MIXED mode, there'll be preceding transition values */
3540  if (aggstate->aggstrategy != AGG_HASHED)
3541  setoff = aggstate->maxsets;
3542  else
3543  setoff = 0;
3544 
3545  for (int setno = 0; setno < numHashes; setno++)
3546  {
3547  ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3548  pertrans, transno, setno, setoff, true,
3549  nullcheck);
3550  setoff++;
3551  }
3552  }
3553 
3554  /* adjust early bail out jump target(s) */
3555  foreach(bail, adjust_bailout)
3556  {
3557  ExprEvalStep *as = &state->steps[lfirst_int(bail)];
3558 
3559  if (as->opcode == EEOP_JUMP_IF_NOT_TRUE)
3560  {
3561  Assert(as->d.jump.jumpdone == -1);
3562  as->d.jump.jumpdone = state->steps_len;
3563  }
3564  else if (as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_ARGS ||
3566  {
3567  Assert(as->d.agg_strict_input_check.jumpnull == -1);
3568  as->d.agg_strict_input_check.jumpnull = state->steps_len;
3569  }
3570  else if (as->opcode == EEOP_AGG_STRICT_DESERIALIZE)
3571  {
3572  Assert(as->d.agg_deserialize.jumpnull == -1);
3573  as->d.agg_deserialize.jumpnull = state->steps_len;
3574  }
3575  else if (as->opcode == EEOP_AGG_PRESORTED_DISTINCT_SINGLE ||
3577  {
3578  Assert(as->d.agg_presorted_distinctcheck.jumpdistinct == -1);
3579  as->d.agg_presorted_distinctcheck.jumpdistinct = state->steps_len;
3580  }
3581  else
3582  Assert(false);
3583  }
3584  }
3585 
3586  scratch.resvalue = NULL;
3587  scratch.resnull = NULL;
3588  scratch.opcode = EEOP_DONE;
3589  ExprEvalPushStep(state, &scratch);
3590 
3592 
3593  return state;
3594 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define Max(x, y)
Definition: c.h:931
#define OidIsValid(objectId)
Definition: c.h:711
static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info)
Definition: execExpr.c:2611
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:901
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:3602
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2418
static void ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
Definition: execExpr.c:2567
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:884
@ EEOP_AGG_STRICT_DESERIALIZE
Definition: execExpr.h:243
@ EEOP_DONE
Definition: execExpr.h:67
@ EEOP_AGG_PRESORTED_DISTINCT_MULTI
Definition: execExpr.h:255
@ EEOP_AGG_STRICT_INPUT_CHECK_NULLS
Definition: execExpr.h:246
@ EEOP_AGG_STRICT_INPUT_CHECK_ARGS
Definition: execExpr.h:245
@ EEOP_AGG_DESERIALIZE
Definition: execExpr.h:244
@ EEOP_JUMP_IF_NOT_TRUE
Definition: execExpr.h:141
@ EEOP_AGG_PRESORTED_DISTINCT_SINGLE
Definition: execExpr.h:254
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend_int(List *list, int datum)
Definition: list.c:356
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:382
@ AGG_HASHED
Definition: nodes.h:353
#define makeNode(_type_)
Definition: nodes.h:165
void * arg
#define lfirst(lc)
Definition: pg_list.h:170
static int list_length(const List *l)
Definition: pg_list.h:150
#define NIL
Definition: pg_list.h:66
#define lfirst_int(lc)
Definition: pg_list.h:171
#define linitial(l)
Definition: pg_list.h:176
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:670
uintptr_t Datum
Definition: postgres.h:412
TupleTableSlot * sortslot
Definition: nodeAgg.h:141
Aggref * aggref
Definition: nodeAgg.h:44
FmgrInfo deserialfn
Definition: nodeAgg.h:92
FunctionCallInfo deserialfn_fcinfo
Definition: nodeAgg.h:175
FunctionCallInfo transfn_fcinfo
Definition: nodeAgg.h:170
ScanState ss
Definition: execnodes.h:2358
AggStatePerTrans pertrans
Definition: execnodes.h:2368
AggStrategy aggstrategy
Definition: execnodes.h:2362
int numtrans
Definition: execnodes.h:2361
AggSplit aggsplit
Definition: execnodes.h:2363
int num_hashes
Definition: execnodes.h:2399
int maxsets
Definition: execnodes.h:2388
List * aggdistinct
Definition: primnodes.h:403
List * aggdirectargs
Definition: primnodes.h:394
List * args
Definition: primnodes.h:397
Expr * aggfilter
Definition: primnodes.h:406
List * aggorder
Definition: primnodes.h:400
struct ExprEvalStep::@50::@87 agg_deserialize
intptr_t opcode
Definition: execExpr.h:271
struct ExprEvalStep::@50::@88 agg_strict_input_check
Datum * resvalue
Definition: execExpr.h:274
struct ExprEvalStep::@50::@60 jump
union ExprEvalStep::@50 d
bool * resnull
Definition: execExpr.h:275
struct ExprEvalStep::@50::@90 agg_presorted_distinctcheck
bool fn_strict
Definition: fmgr.h:61
FmgrInfo * flinfo
Definition: fmgr.h:87
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
Definition: pg_list.h:52
Definition: nodes.h:118
Datum value
Definition: postgres.h:423
PlanState ps
Definition: execnodes.h:1454
Expr * expr
Definition: primnodes.h:1555
bool * tts_isnull
Definition: tuptable.h:128
Datum * tts_values
Definition: tuptable.h:126
Definition: regguts.h:318

References ExprEvalStep::agg_deserialize, AGG_HASHED, ExprEvalStep::agg_presorted_distinctcheck, ExprEvalStep::agg_strict_input_check, Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggorder, AggStatePerTransData::aggref, AggStatePerTransData::aggsortrequired, 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_PRESORTED_DISTINCT_MULTI, EEOP_AGG_PRESORTED_DISTINCT_SINGLE, 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(), 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::numDistinctCols, AggStatePerTransData::numInputs, AggStatePerPhaseData::numsets, AggStatePerTransData::numSortCols, AggState::numtrans, AggStatePerTransData::numTransInputs, OidIsValid, ExprEvalStep::opcode, AggState::pertrans, PointerGetDatum(), ScanState::ps, ExprEvalStep::resnull, ExprEvalStep::resvalue, AggStatePerTransData::sortslot, AggState::ss, AggStatePerTransData::transfn_fcinfo, TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, NullableDatum::value, and values.

Referenced by ExecInitAgg(), and hashagg_recompile_expressions().

◆ 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 3602 of file execExpr.c.

3607 {
3608  ExprContext *aggcontext;
3609  int adjust_jumpnull = -1;
3610 
3611  if (ishash)
3612  aggcontext = aggstate->hashcontext;
3613  else
3614  aggcontext = aggstate->aggcontexts[setno];
3615 
3616  /* add check for NULL pointer? */
3617  if (nullcheck)
3618  {
3620  scratch->d.agg_plain_pergroup_nullcheck.setoff = setoff;
3621  /* adjust later */
3622  scratch->d.agg_plain_pergroup_nullcheck.jumpnull = -1;
3623  ExprEvalPushStep(state, scratch);
3624  adjust_jumpnull = state->steps_len - 1;
3625  }
3626 
3627  /*
3628  * Determine appropriate transition implementation.
3629  *
3630  * For non-ordered aggregates and ORDER BY / DISTINCT aggregates with
3631  * presorted input:
3632  *
3633  * If the initial value for the transition state doesn't exist in the
3634  * pg_aggregate table then we will let the first non-NULL value returned
3635  * from the outer procNode become the initial value. (This is useful for
3636  * aggregates like max() and min().) The noTransValue flag signals that we
3637  * need to do so. If true, generate a
3638  * EEOP_AGG_INIT_STRICT_PLAIN_TRANS{,_BYVAL} step. This step also needs to
3639  * do the work described next:
3640  *
3641  * If the function is strict, but does have an initial value, choose
3642  * EEOP_AGG_STRICT_PLAIN_TRANS{,_BYVAL}, which skips the transition
3643  * function if the transition value has become NULL (because a previous
3644  * transition function returned NULL). This step also needs to do the work
3645  * described next:
3646  *
3647  * Otherwise we call EEOP_AGG_PLAIN_TRANS{,_BYVAL}, which does not have to
3648  * perform either of the above checks.
3649  *
3650  * Having steps with overlapping responsibilities is not nice, but
3651  * aggregations are very performance sensitive, making this worthwhile.
3652  *
3653  * For ordered aggregates:
3654  *
3655  * Only need to choose between the faster path for a single ordered
3656  * column, and the one between multiple columns. Checking strictness etc
3657  * is done when finalizing the aggregate. See
3658  * process_ordered_aggregate_{single, multi} and
3659  * advance_transition_function.
3660  */
3661  if (!pertrans->aggsortrequired)
3662  {
3663  if (pertrans->transtypeByVal)
3664  {
3665  if (fcinfo->flinfo->fn_strict &&
3666  pertrans->initValueIsNull)
3668  else if (fcinfo->flinfo->fn_strict)
3670  else
3672  }
3673  else
3674  {
3675  if (fcinfo->flinfo->fn_strict &&
3676  pertrans->initValueIsNull)
3678  else if (fcinfo->flinfo->fn_strict)
3680  else
3682  }
3683  }
3684  else if (pertrans->numInputs == 1)
3686  else
3688 
3689  scratch->d.agg_trans.pertrans = pertrans;
3690  scratch->d.agg_trans.setno = setno;
3691  scratch->d.agg_trans.setoff = setoff;
3692  scratch->d.agg_trans.transno = transno;
3693  scratch->d.agg_trans.aggcontext = aggcontext;
3694  ExprEvalPushStep(state, scratch);
3695 
3696  /* fix up jumpnull */
3697  if (adjust_jumpnull != -1)
3698  {
3699  ExprEvalStep *as = &state->steps[adjust_jumpnull];
3700 
3702  Assert(as->d.agg_plain_pergroup_nullcheck.jumpnull == -1);
3703  as->d.agg_plain_pergroup_nullcheck.jumpnull = state->steps_len;
3704  }
3705 }
@ EEOP_AGG_PLAIN_PERGROUP_NULLCHECK
Definition: execExpr.h:247
@ EEOP_AGG_PLAIN_TRANS_BYREF
Definition: execExpr.h:253
@ EEOP_AGG_PLAIN_TRANS_BYVAL
Definition: execExpr.h:250
@ EEOP_AGG_ORDERED_TRANS_DATUM
Definition: execExpr.h:256
@ EEOP_AGG_PLAIN_TRANS_STRICT_BYREF
Definition: execExpr.h:252
@ EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL
Definition: execExpr.h:248
@ EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL
Definition: execExpr.h:249
@ EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF
Definition: execExpr.h:251
@ EEOP_AGG_ORDERED_TRANS_TUPLE
Definition: execExpr.h:257
ExprContext * hashcontext
Definition: execnodes.h:2369
ExprContext ** aggcontexts
Definition: execnodes.h:2370
struct ExprEvalStep::@50::@91 agg_trans
struct ExprEvalStep::@50::@89 agg_plain_pergroup_nullcheck

References ExprEvalStep::agg_plain_pergroup_nullcheck, ExprEvalStep::agg_trans, AggState::aggcontexts, AggStatePerTransData::aggsortrequired, 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, ExprEvalStep::opcode, and AggStatePerTransData::transtypeByVal.

Referenced by ExecBuildAggTrans().

◆ 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 3719 of file execExpr.c.

3726 {
3728  ExprEvalStep scratch = {0};
3729  int maxatt = -1;
3730  List *adjust_jumps = NIL;
3731  ListCell *lc;
3732 
3733  /*
3734  * When no columns are actually compared, the result's always true. See
3735  * special case in ExecQual().
3736  */
3737  if (numCols == 0)
3738  return NULL;
3739 
3740  state->expr = NULL;
3741  state->flags = EEO_FLAG_IS_QUAL;
3742  state->parent = parent;
3743 
3744  scratch.resvalue = &state->resvalue;
3745  scratch.resnull = &state->resnull;
3746 
3747  /* compute max needed attribute */
3748  for (int natt = 0; natt < numCols; natt++)
3749  {
3750  int attno = keyColIdx[natt];
3751 
3752  if (attno > maxatt)
3753  maxatt = attno;
3754  }
3755  Assert(maxatt >= 0);
3756 
3757  /* push deform steps */
3758  scratch.opcode = EEOP_INNER_FETCHSOME;
3759  scratch.d.fetch.last_var = maxatt;
3760  scratch.d.fetch.fixed = false;
3761  scratch.d.fetch.known_desc = ldesc;
3762  scratch.d.fetch.kind = lops;
3763  if (ExecComputeSlotInfo(state, &scratch))
3764  ExprEvalPushStep(state, &scratch);
3765 
3766  scratch.opcode = EEOP_OUTER_FETCHSOME;
3767  scratch.d.fetch.last_var = maxatt;
3768  scratch.d.fetch.fixed = false;
3769  scratch.d.fetch.known_desc = rdesc;
3770  scratch.d.fetch.kind = rops;
3771  if (ExecComputeSlotInfo(state, &scratch))
3772  ExprEvalPushStep(state, &scratch);
3773 
3774  /*
3775  * Start comparing at the last field (least significant sort key). That's
3776  * the most likely to be different if we are dealing with sorted input.
3777  */
3778  for (int natt = numCols; --natt >= 0;)
3779  {
3780  int attno = keyColIdx[natt];
3781  Form_pg_attribute latt = TupleDescAttr(ldesc, attno - 1);
3782  Form_pg_attribute ratt = TupleDescAttr(rdesc, attno - 1);
3783  Oid foid = eqfunctions[natt];
3784  Oid collid = collations[natt];
3785  FmgrInfo *finfo;
3786  FunctionCallInfo fcinfo;
3787  AclResult aclresult;
3788 
3789  /* Check permission to call function */
3790  aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE);
3791  if (aclresult != ACLCHECK_OK)
3792  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
3793 
3795 
3796  /* Set up the primary fmgr lookup information */
3797  finfo = palloc0(sizeof(FmgrInfo));
3798  fcinfo = palloc0(SizeForFunctionCallInfo(2));
3799  fmgr_info(foid, finfo);
3800  fmgr_info_set_expr(NULL, finfo);
3801  InitFunctionCallInfoData(*fcinfo, finfo, 2,
3802  collid, NULL, NULL);
3803 
3804  /* left arg */
3805  scratch.opcode = EEOP_INNER_VAR;
3806  scratch.d.var.attnum = attno - 1;
3807  scratch.d.var.vartype = latt->atttypid;
3808  scratch.resvalue = &fcinfo->args[0].value;
3809  scratch.resnull = &fcinfo->args[0].isnull;
3810  ExprEvalPushStep(state, &scratch);
3811 
3812  /* right arg */
3813  scratch.opcode = EEOP_OUTER_VAR;
3814  scratch.d.var.attnum = attno - 1;
3815  scratch.d.var.vartype = ratt->atttypid;
3816  scratch.resvalue = &fcinfo->args[1].value;
3817  scratch.resnull = &fcinfo->args[1].isnull;
3818  ExprEvalPushStep(state, &scratch);
3819 
3820  /* evaluate distinctness */
3821  scratch.opcode = EEOP_NOT_DISTINCT;
3822  scratch.d.func.finfo = finfo;
3823  scratch.d.func.fcinfo_data = fcinfo;
3824  scratch.d.func.fn_addr = finfo->fn_addr;
3825  scratch.d.func.nargs = 2;
3826  scratch.resvalue = &state->resvalue;
3827  scratch.resnull = &state->resnull;
3828  ExprEvalPushStep(state, &scratch);
3829 
3830  /* then emit EEOP_QUAL to detect if result is false (or null) */
3831  scratch.opcode = EEOP_QUAL;
3832  scratch.d.qualexpr.jumpdone = -1;
3833  scratch.resvalue = &state->resvalue;
3834  scratch.resnull = &state->resnull;
3835  ExprEvalPushStep(state, &scratch);
3836  adjust_jumps = lappend_int(adjust_jumps,
3837  state->steps_len - 1);
3838  }
3839 
3840  /* adjust jump targets */
3841  foreach(lc, adjust_jumps)
3842  {
3843  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
3844 
3845  Assert(as->opcode == EEOP_QUAL);
3846  Assert(as->d.qualexpr.jumpdone == -1);
3847  as->d.qualexpr.jumpdone = state->steps_len;
3848  }
3849 
3850  scratch.resvalue = NULL;
3851  scratch.resnull = NULL;
3852  scratch.opcode = EEOP_DONE;
3853  ExprEvalPushStep(state, &scratch);
3854 
3856 
3857  return state;
3858 }
AclResult
Definition: acl.h:183
@ ACLCHECK_OK
Definition: acl.h:184
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3485
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:4598
static bool ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op)
Definition: execExpr.c:2665
@ EEOP_NOT_DISTINCT
Definition: execExpr.h:171
@ EEOP_INNER_VAR
Definition: execExpr.h:75
@ EEOP_QUAL
Definition: execExpr.h:133
@ EEOP_INNER_FETCHSOME
Definition: execExpr.h:70
@ EEOP_OUTER_FETCHSOME
Definition: execExpr.h:71
@ EEOP_OUTER_VAR
Definition: execExpr.h:76
#define EEO_FLAG_IS_QUAL
Definition: execnodes.h:75
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1590
void * palloc0(Size size)
Definition: mcxt.c:1230
Oid GetUserId(void)
Definition: miscinit.c:497
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:213
@ OBJECT_FUNCTION
Definition: parsenodes.h:1881
#define ACL_EXECUTE
Definition: parsenodes.h:90
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
unsigned int Oid
Definition: postgres_ext.h:31
struct ExprEvalStep::@50::@51 fetch
struct ExprEvalStep::@50::@52 var
struct ExprEvalStep::@50::@59 qualexpr
struct ExprEvalStep::@50::@57 func
Definition: fmgr.h:57
PGFunction fn_addr
Definition: fmgr.h:58
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

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(), ExprEvalPushStep(), ExprEvalStep::fetch, 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_aclcheck(), OBJECT_FUNCTION, ExprEvalStep::opcode, palloc0(), ExprEvalStep::qualexpr, ExprEvalStep::resnull, ExprEvalStep::resvalue, SizeForFunctionCallInfo, TupleDescAttr, NullableDatum::value, and ExprEvalStep::var.

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

◆ 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 3876 of file execExpr.c.

3883 {
3885  ExprEvalStep scratch = {0};
3886  int maxatt = list_length(param_exprs);
3887  List *adjust_jumps = NIL;
3888  ListCell *lc;
3889 
3890  state->expr = NULL;
3891  state->flags = EEO_FLAG_IS_QUAL;
3892  state->parent = parent;
3893 
3894  scratch.resvalue = &state->resvalue;
3895  scratch.resnull = &state->resnull;
3896 
3897  /* push deform steps */
3898  scratch.opcode = EEOP_INNER_FETCHSOME;
3899  scratch.d.fetch.last_var = maxatt;
3900  scratch.d.fetch.fixed = false;
3901  scratch.d.fetch.known_desc = desc;
3902  scratch.d.fetch.kind = lops;
3903  if (ExecComputeSlotInfo(state, &scratch))
3904  ExprEvalPushStep(state, &scratch);
3905 
3906  scratch.opcode = EEOP_OUTER_FETCHSOME;
3907  scratch.d.fetch.last_var = maxatt;
3908  scratch.d.fetch.fixed = false;
3909  scratch.d.fetch.known_desc = desc;
3910  scratch.d.fetch.kind = rops;
3911  if (ExecComputeSlotInfo(state, &scratch))
3912  ExprEvalPushStep(state, &scratch);
3913 
3914  for (int attno = 0; attno < maxatt; attno++)
3915  {
3916  Form_pg_attribute att = TupleDescAttr(desc, attno);
3917  Oid foid = eqfunctions[attno];
3918  Oid collid = collations[attno];
3919  FmgrInfo *finfo;
3920  FunctionCallInfo fcinfo;
3921  AclResult aclresult;
3922 
3923  /* Check permission to call function */
3924  aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE);
3925  if (aclresult != ACLCHECK_OK)
3926  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
3927 
3929 
3930  /* Set up the primary fmgr lookup information */
3931  finfo = palloc0(sizeof(FmgrInfo));
3932  fcinfo = palloc0(SizeForFunctionCallInfo(2));
3933  fmgr_info(foid, finfo);
3934  fmgr_info_set_expr(NULL, finfo);
3935  InitFunctionCallInfoData(*fcinfo, finfo, 2,
3936  collid, NULL, NULL);
3937 
3938  /* left arg */
3939  scratch.opcode = EEOP_INNER_VAR;
3940  scratch.d.var.attnum = attno;
3941  scratch.d.var.vartype = att->atttypid;
3942  scratch.resvalue = &fcinfo->args[0].value;
3943  scratch.resnull = &fcinfo->args[0].isnull;
3944  ExprEvalPushStep(state, &scratch);
3945 
3946  /* right arg */
3947  scratch.opcode = EEOP_OUTER_VAR;
3948  scratch.d.var.attnum = attno;
3949  scratch.d.var.vartype = att->atttypid;
3950  scratch.resvalue = &fcinfo->args[1].value;
3951  scratch.resnull = &fcinfo->args[1].isnull;
3952  ExprEvalPushStep(state, &scratch);
3953 
3954  /* evaluate distinctness */
3955  scratch.opcode = EEOP_NOT_DISTINCT;
3956  scratch.d.func.finfo = finfo;
3957  scratch.d.func.fcinfo_data = fcinfo;
3958  scratch.d.func.fn_addr = finfo->fn_addr;
3959  scratch.d.func.nargs = 2;
3960  scratch.resvalue = &state->resvalue;
3961  scratch.resnull = &state->resnull;
3962  ExprEvalPushStep(state, &scratch);
3963 
3964  /* then emit EEOP_QUAL to detect if result is false (or null) */
3965  scratch.opcode = EEOP_QUAL;
3966  scratch.d.qualexpr.jumpdone = -1;
3967  scratch.resvalue = &state->resvalue;
3968  scratch.resnull = &state->resnull;
3969  ExprEvalPushStep(state, &scratch);
3970  adjust_jumps = lappend_int(adjust_jumps,
3971  state->steps_len - 1);
3972  }
3973 
3974  /* adjust jump targets */
3975  foreach(lc, adjust_jumps)
3976  {
3977  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
3978 
3979  Assert(as->opcode == EEOP_QUAL);
3980  Assert(as->d.qualexpr.jumpdone == -1);
3981  as->d.qualexpr.jumpdone = state->steps_len;
3982  }
3983 
3984  scratch.resvalue = NULL;
3985  scratch.resnull = NULL;
3986  scratch.opcode = EEOP_DONE;
3987  ExprEvalPushStep(state, &scratch);
3988 
3990 
3991  return state;
3992 }

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(), ExprEvalPushStep(), ExprEvalStep::fetch, 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_aclcheck(), OBJECT_FUNCTION, ExprEvalStep::opcode, palloc0(), ExprEvalStep::qualexpr, ExprEvalStep::resnull, ExprEvalStep::resvalue, SizeForFunctionCallInfo, TupleDescAttr, NullableDatum::value, and ExprEvalStep::var.

Referenced by ExecInitMemoize().

◆ ExecBuildProjectionInfo()

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

Definition at line 354 of file execExpr.c.

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

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(), TargetEntry::expr, ExprEvalPushStep(), exprType(), get_typlen(), if(), INNER_VAR, IsA, lfirst_node, makeNode, ExprEvalStep::opcode, OUTER_VAR, ProjectionInfo::pi_exprContext, ProjectionInfo::pi_state, TargetEntry::resno, TupleDescAttr, and ExprState::type.

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

◆ ExecBuildUpdateProjection()

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

Definition at line 514 of file execExpr.c.

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

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(), TargetEntry::expr, ExprEvalPushStep(), exprType(), 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, ProjectionInfo::pi_exprContext, ProjectionInfo::pi_state, TargetEntry::resjunk, ExprEvalStep::resnull, ExprEvalStep::resvalue, TupleDescAttr, and ExprState::type.

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

◆ ExecCheck()

bool ExecCheck ( ExprState state,
ExprContext econtext 
)

Definition at line 854 of file execExpr.c.

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

References Assert(), DatumGetBool(), EEO_FLAG_IS_QUAL, and ExecEvalExprSwitchContext().

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

◆ ExecComputeSlotInfo()

static bool ExecComputeSlotInfo ( ExprState state,
ExprEvalStep op 
)
static

Definition at line 2665 of file execExpr.c.

2666 {
2667  PlanState *parent = state->parent;
2668  TupleDesc desc = NULL;
2669  const TupleTableSlotOps *tts_ops = NULL;
2670  bool isfixed = false;
2671  ExprEvalOp opcode = op->opcode;
2672 
2673  Assert(opcode == EEOP_INNER_FETCHSOME ||
2674  opcode == EEOP_OUTER_FETCHSOME ||
2675  opcode == EEOP_SCAN_FETCHSOME);
2676 
2677  if (op->d.fetch.known_desc != NULL)
2678  {
2679  desc = op->d.fetch.known_desc;
2680  tts_ops = op->d.fetch.kind;
2681  isfixed = op->d.fetch.kind != NULL;
2682  }
2683  else if (!parent)
2684  {
2685  isfixed = false;
2686  }
2687  else if (opcode == EEOP_INNER_FETCHSOME)
2688  {
2689  PlanState *is = innerPlanState(parent);
2690 
2691  if (parent->inneropsset && !parent->inneropsfixed)
2692  {
2693  isfixed = false;
2694  }
2695  else if (parent->inneropsset && parent->innerops)
2696  {
2697  isfixed = true;
2698  tts_ops = parent->innerops;
2699  desc = ExecGetResultType(is);
2700  }
2701  else if (is)
2702  {
2703  tts_ops = ExecGetResultSlotOps(is, &isfixed);
2704  desc = ExecGetResultType(is);
2705  }
2706  }
2707  else if (opcode == EEOP_OUTER_FETCHSOME)
2708  {
2709  PlanState *os = outerPlanState(parent);
2710 
2711  if (parent->outeropsset && !parent->outeropsfixed)
2712  {
2713  isfixed = false;
2714  }
2715  else if (parent->outeropsset && parent->outerops)
2716  {
2717  isfixed = true;
2718  tts_ops = parent->outerops;
2719  desc = ExecGetResultType(os);
2720  }
2721  else if (os)
2722  {
2723  tts_ops = ExecGetResultSlotOps(os, &isfixed);
2724  desc = ExecGetResultType(os);
2725  }
2726  }
2727  else if (opcode == EEOP_SCAN_FETCHSOME)
2728  {
2729  desc = parent->scandesc;
2730 
2731  if (parent->scanops)
2732  tts_ops = parent->scanops;
2733 
2734  if (parent->scanopsset)
2735  isfixed = parent->scanopsfixed;
2736  }
2737 
2738  if (isfixed && desc != NULL && tts_ops != NULL)
2739  {
2740  op->d.fetch.fixed = true;
2741  op->d.fetch.kind = tts_ops;
2742  op->d.fetch.known_desc = desc;
2743  }
2744  else
2745  {
2746  op->d.fetch.fixed = false;
2747  op->d.fetch.kind = NULL;
2748  op->d.fetch.known_desc = NULL;
2749  }
2750 
2751  /* if the slot is known to always virtual we never need to deform */
2752  if (op->d.fetch.fixed && op->d.fetch.kind == &TTSOpsVirtual)
2753  return false;
2754 
2755  return true;
2756 }
ExprEvalOp
Definition: execExpr.h:65
@ EEOP_SCAN_FETCHSOME
Definition: execExpr.h:72
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:492
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:501
#define outerPlanState(node)
Definition: execnodes.h:1125
#define innerPlanState(node)
Definition: execnodes.h:1124
bool inneropsset
Definition: execnodes.h:1113
bool outeropsset
Definition: execnodes.h:1112
const TupleTableSlotOps * outerops
Definition: execnodes.h:1104
const TupleTableSlotOps * innerops
Definition: execnodes.h:1105
const TupleTableSlotOps * scanops
Definition: execnodes.h:1103
bool outeropsfixed
Definition: execnodes.h:1108
bool scanopsset
Definition: execnodes.h:1111
TupleDesc scandesc
Definition: execnodes.h:1078
bool scanopsfixed
Definition: execnodes.h:1107
bool inneropsfixed
Definition: execnodes.h:1109

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, PlanState::scandesc, PlanState::scanops, PlanState::scanopsfixed, PlanState::scanopsset, and TTSOpsVirtual.

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

◆ ExecInitCheck()

ExprState* ExecInitCheck ( List qual,
PlanState parent 
)

Definition at line 299 of file execExpr.c.

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

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

Referenced by ExecPrepareCheck().

◆ ExecInitCoerceToDomain()

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

Definition at line 3109 of file execExpr.c.

3111 {
3112  DomainConstraintRef *constraint_ref;
3113  Datum *domainval = NULL;
3114  bool *domainnull = NULL;
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 *save_innermost_domainval;
3162  bool *save_innermost_domainnull;
3163 
3164  scratch->d.domaincheck.constraintname = con->name;
3165 
3166  switch (con->constrainttype)
3167  {
3169  scratch->opcode = EEOP_DOMAIN_NOTNULL;
3170  ExprEvalPushStep(state, scratch);
3171  break;
3172  case DOM_CONSTRAINT_CHECK:
3173  /* Allocate workspace for CHECK output if we didn't yet */
3174  if (scratch->d.domaincheck.checkvalue == NULL)
3175  {
3176  scratch->d.domaincheck.checkvalue =
3177  (Datum *) palloc(sizeof(Datum));
3178  scratch->d.domaincheck.checknull =
3179  (bool *) palloc(sizeof(bool));
3180  }
3181 
3182  /*
3183  * If first time through, determine where CoerceToDomainValue
3184  * nodes should read from.
3185  */
3186  if (domainval == NULL)
3187  {
3188  /*
3189  * Since value might be read multiple times, force to R/O
3190  * - but only if it could be an expanded datum.
3191  */
3192  if (get_typlen(ctest->resulttype) == -1)
3193  {
3194  ExprEvalStep scratch2 = {0};
3195 
3196  /* Yes, so make output workspace for MAKE_READONLY */
3197  domainval = (Datum *) palloc(sizeof(Datum));
3198  domainnull = (bool *) palloc(sizeof(bool));
3199 
3200  /* Emit MAKE_READONLY */
3201  scratch2.opcode = EEOP_MAKE_READONLY;
3202  scratch2.resvalue = domainval;
3203  scratch2.resnull = domainnull;
3204  scratch2.d.make_readonly.value = resv;
3205  scratch2.d.make_readonly.isnull = resnull;
3206  ExprEvalPushStep(state, &scratch2);
3207  }
3208  else
3209  {
3210  /* No, so it's fine to read from resv/resnull */
3211  domainval = resv;
3212  domainnull = resnull;
3213  }
3214  }
3215 
3216  /*
3217  * Set up value to be returned by CoerceToDomainValue nodes.
3218  * We must save and restore innermost_domainval/null fields,
3219  * in case this node is itself within a check expression for
3220  * another domain.
3221  */
3222  save_innermost_domainval = state->innermost_domainval;
3223  save_innermost_domainnull = state->innermost_domainnull;
3224  state->innermost_domainval = domainval;
3225  state->innermost_domainnull = domainnull;
3226 
3227  /* evaluate check expression value */
3229  scratch->d.domaincheck.checkvalue,
3230  scratch->d.domaincheck.checknull);
3231 
3232  state->innermost_domainval = save_innermost_domainval;
3233  state->innermost_domainnull = save_innermost_domainnull;
3234 
3235  /* now test result */
3236  scratch->opcode = EEOP_DOMAIN_CHECK;
3237  ExprEvalPushStep(state, scratch);
3238 
3239  break;
3240  default:
3241  elog(ERROR, "unrecognized constraint type: %d",
3242  (int) con->constrainttype);
3243  break;
3244  }
3245  }
3246 }
@ EEOP_DOMAIN_CHECK
Definition: execExpr.h:230
@ EEOP_DOMAIN_NOTNULL
Definition: execExpr.h:227
@ EEOP_MAKE_READONLY
Definition: execExpr.h:166
@ DOM_CONSTRAINT_CHECK
Definition: execnodes.h:985
@ DOM_CONSTRAINT_NOTNULL
Definition: execnodes.h:984
MemoryContext CurrentMemoryContext
Definition: mcxt.c:124
void * palloc(Size size)
Definition: mcxt.c:1199
DomainConstraintType constrainttype
Definition: execnodes.h:991
struct ExprEvalStep::@50::@65 make_readonly
struct ExprEvalStep::@50::@78 domaincheck
void InitDomainConstraintRef(Oid type_id, DomainConstraintRef *ref, MemoryContext refctx, bool need_exprstate)
Definition: typcache.c:1305

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(), lfirst, ExprEvalStep::make_readonly, DomainConstraintState::name, ExprEvalStep::opcode, palloc(), ExprEvalStep::resnull, CoerceToDomain::resulttype, and ExprEvalStep::resvalue.

Referenced by ExecInitExprRec().

◆ ExecInitExpr()

ExprState* ExecInitExpr ( Expr node,
PlanState parent 
)

Definition at line 124 of file execExpr.c.

125 {
126  ExprState *state;
127  ExprEvalStep scratch = {0};
128 
129  /* Special case: NULL expression produces a NULL ExprState pointer */
130  if (node == NULL)
131  return NULL;
132 
133  /* Initialize ExprState with empty step list */
135  state->expr = node;
136  state->parent = parent;
137  state->ext_params = NULL;
138 
139  /* Insert EEOP_*_FETCHSOME steps as needed */
140  ExecInitExprSlots(state, (Node *) node);
141 
142  /* Compile the expression proper */
143  ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
144 
145  /* Finally, append a DONE step */
146  scratch.opcode = EEOP_DONE;
147  ExprEvalPushStep(state, &scratch);
148 
150 
151  return state;
152 }

References EEOP_DONE, ExecInitExprRec(), ExecInitExprSlots(), ExecReadyExpr(), ExprEvalPushStep(), makeNode, and ExprEvalStep::opcode.

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

◆ ExecInitExprList()

List* ExecInitExprList ( List nodes,
PlanState parent 
)

Definition at line 319 of file execExpr.c.

320 {
321  List *result = NIL;
322  ListCell *lc;
323 
324  foreach(lc, nodes)
325  {
326  Expr *e = lfirst(lc);
327 
328  result = lappend(result, ExecInitExpr(e, parent));
329  }
330 
331  return result;
332 }
List * lappend(List *list, void *datum)
Definition: list.c:338
e
Definition: preproc-init.c:82

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

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

◆ ExecInitExprRec()

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

Definition at line 901 of file execExpr.c.

903 {
904  ExprEvalStep scratch = {0};
905 
906  /* Guard against stack overflow due to overly complex expressions */
908 
909  /* Step's output location is always what the caller gave us */
910  Assert(resv != NULL && resnull != NULL);
911  scratch.resvalue = resv;
912  scratch.resnull = resnull;
913 
914  /* cases should be ordered as they are in enum NodeTag */
915  switch (nodeTag(node))
916  {
917  case T_Var:
918  {
919  Var *variable = (Var *) node;
920 
921  if (variable->varattno == InvalidAttrNumber)
922  {
923  /* whole-row Var */
924  ExecInitWholeRowVar(&scratch, variable, state);
925  }
926  else if (variable->varattno <= 0)
927  {
928  /* system column */
929  scratch.d.var.attnum = variable->varattno;
930  scratch.d.var.vartype = variable->vartype;
931  switch (variable->varno)
932  {
933  case INNER_VAR:
934  scratch.opcode = EEOP_INNER_SYSVAR;
935  break;
936  case OUTER_VAR:
937  scratch.opcode = EEOP_OUTER_SYSVAR;
938  break;
939 
940  /* INDEX_VAR is handled by default case */
941 
942  default:
943  scratch.opcode = EEOP_SCAN_SYSVAR;
944  break;
945  }
946  }
947  else
948  {
949  /* regular user column */
950  scratch.d.var.attnum = variable->varattno - 1;
951  scratch.d.var.vartype = variable->vartype;
952  switch (variable->varno)
953  {
954  case INNER_VAR:
955  scratch.opcode = EEOP_INNER_VAR;
956  break;
957  case OUTER_VAR:
958  scratch.opcode = EEOP_OUTER_VAR;
959  break;
960 
961  /* INDEX_VAR is handled by default case */
962 
963  default:
964  scratch.opcode = EEOP_SCAN_VAR;
965  break;
966  }
967  }
968 
969  ExprEvalPushStep(state, &scratch);
970  break;
971  }
972 
973  case T_Const:
974  {
975  Const *con = (Const *) node;
976 
977  scratch.opcode = EEOP_CONST;
978  scratch.d.constval.value = con->constvalue;
979  scratch.d.constval.isnull = con->constisnull;
980 
981  ExprEvalPushStep(state, &scratch);
982  break;
983  }
984 
985  case T_Param:
986  {
987  Param *param = (Param *) node;
988  ParamListInfo params;
989 
990  switch (param->paramkind)
991  {
992  case PARAM_EXEC:
993  scratch.opcode = EEOP_PARAM_EXEC;
994  scratch.d.param.paramid = param->paramid;
995  scratch.d.param.paramtype = param->paramtype;
996  ExprEvalPushStep(state, &scratch);
997  break;
998  case PARAM_EXTERN:
999 
1000  /*
1001  * If we have a relevant ParamCompileHook, use it;
1002  * otherwise compile a standard EEOP_PARAM_EXTERN
1003  * step. ext_params, if supplied, takes precedence
1004  * over info from the parent node's EState (if any).
1005  */
1006  if (state->ext_params)
1007  params = state->ext_params;
1008  else if (state->parent &&
1009  state->parent->state)
1010  params = state->parent->state->es_param_list_info;
1011  else
1012  params = NULL;
1013  if (params && params->paramCompile)
1014  {
1015  params->paramCompile(params, param, state,
1016  resv, resnull);
1017  }
1018  else
1019  {
1020  scratch.opcode = EEOP_PARAM_EXTERN;
1021  scratch.d.param.paramid = param->paramid;
1022  scratch.d.param.paramtype = param->paramtype;
1023  ExprEvalPushStep(state, &scratch);
1024  }
1025  break;
1026  default:
1027  elog(ERROR, "unrecognized paramkind: %d",
1028  (int) param->paramkind);
1029  break;
1030  }
1031  break;
1032  }
1033 
1034  case T_Aggref:
1035  {
1036  Aggref *aggref = (Aggref *) node;
1037 
1038  scratch.opcode = EEOP_AGGREF;
1039  scratch.d.aggref.aggno = aggref->aggno;
1040 
1041  if (state->parent && IsA(state->parent, AggState))
1042  {
1043  AggState *aggstate = (AggState *) state->parent;
1044 
1045  aggstate->aggs = lappend(aggstate->aggs, aggref);
1046  }
1047  else
1048  {
1049  /* planner messed up */
1050  elog(ERROR, "Aggref found in non-Agg plan node");
1051  }
1052 
1053  ExprEvalPushStep(state, &scratch);
1054  break;
1055  }
1056 
1057  case T_GroupingFunc:
1058  {
1059  GroupingFunc *grp_node = (GroupingFunc *) node;
1060  Agg *agg;
1061 
1062  if (!state->parent || !IsA(state->parent, AggState) ||
1063  !IsA(state->parent->plan, Agg))
1064  elog(ERROR, "GroupingFunc found in non-Agg plan node");
1065 
1066  scratch.opcode = EEOP_GROUPING_FUNC;
1067 
1068  agg = (Agg *) (state->parent->plan);
1069 
1070  if (agg->groupingSets)
1071  scratch.d.grouping_func.clauses = grp_node->cols;
1072  else
1073  scratch.d.grouping_func.clauses = NIL;
1074 
1075  ExprEvalPushStep(state, &scratch);
1076  break;
1077  }
1078 
1079  case T_WindowFunc:
1080  {
1081  WindowFunc *wfunc = (WindowFunc *) node;
1083 
1084  wfstate->wfunc = wfunc;
1085 
1086  if (state->parent && IsA(state->parent, WindowAggState))
1087  {
1088  WindowAggState *winstate = (WindowAggState *) state->parent;
1089  int nfuncs;
1090 
1091  winstate->funcs = lappend(winstate->funcs, wfstate);
1092  nfuncs = ++winstate->numfuncs;
1093  if (wfunc->winagg)
1094  winstate->numaggs++;
1095 
1096  /* for now initialize agg using old style expressions */
1097  wfstate->args = ExecInitExprList(wfunc->args,
1098  state->parent);
1099  wfstate->aggfilter = ExecInitExpr(wfunc->aggfilter,
1100  state->parent);
1101 
1102  /*
1103  * Complain if the windowfunc's arguments contain any
1104  * windowfuncs; nested window functions are semantically
1105  * nonsensical. (This should have been caught earlier,
1106  * but we defend against it here anyway.)
1107  */
1108  if (nfuncs != winstate->numfuncs)
1109  ereport(ERROR,
1110  (errcode(ERRCODE_WINDOWING_ERROR),
1111  errmsg("window function calls cannot be nested")));
1112  }
1113  else
1114  {
1115  /* planner messed up */
1116  elog(ERROR, "WindowFunc found in non-WindowAgg plan node");
1117  }
1118 
1119  scratch.opcode = EEOP_WINDOW_FUNC;
1120  scratch.d.window_func.wfstate = wfstate;
1121  ExprEvalPushStep(state, &scratch);
1122  break;
1123  }
1124 
1125  case T_SubscriptingRef:
1126  {
1127  SubscriptingRef *sbsref = (SubscriptingRef *) node;
1128 
1129  ExecInitSubscriptingRef(&scratch, sbsref, state, resv, resnull);
1130  break;
1131  }
1132 
1133  case T_FuncExpr:
1134  {
1135  FuncExpr *func = (FuncExpr *) node;
1136 
1137  ExecInitFunc(&scratch, node,
1138  func->args, func->funcid, func->inputcollid,
1139  state);
1140  ExprEvalPushStep(state, &scratch);
1141  break;
1142  }
1143 
1144  case T_OpExpr:
1145  {
1146  OpExpr *op = (OpExpr *) node;
1147 
1148  ExecInitFunc(&scratch, node,
1149  op->args, op->opfuncid, op->inputcollid,
1150  state);
1151  ExprEvalPushStep(state, &scratch);
1152  break;
1153  }
1154 
1155  case T_DistinctExpr:
1156  {
1157  DistinctExpr *op = (DistinctExpr *) node;
1158 
1159  ExecInitFunc(&scratch, node,
1160  op->args, op->opfuncid, op->inputcollid,
1161  state);
1162 
1163  /*
1164  * Change opcode of call instruction to EEOP_DISTINCT.
1165  *
1166  * XXX: historically we've not called the function usage
1167  * pgstat infrastructure - that seems inconsistent given that
1168  * we do so for normal function *and* operator evaluation. If
1169  * we decided to do that here, we'd probably want separate
1170  * opcodes for FUSAGE or not.
1171  */
1172  scratch.opcode = EEOP_DISTINCT;
1173  ExprEvalPushStep(state, &scratch);
1174  break;
1175  }
1176 
1177  case T_NullIfExpr:
1178  {
1179  NullIfExpr *op = (NullIfExpr *) node;
1180 
1181  ExecInitFunc(&scratch, node,
1182  op->args, op->opfuncid, op->inputcollid,
1183  state);
1184 
1185  /*
1186  * Change opcode of call instruction to EEOP_NULLIF.
1187  *
1188  * XXX: historically we've not called the function usage
1189  * pgstat infrastructure - that seems inconsistent given that
1190  * we do so for normal function *and* operator evaluation. If
1191  * we decided to do that here, we'd probably want separate
1192  * opcodes for FUSAGE or not.
1193  */
1194  scratch.opcode = EEOP_NULLIF;
1195  ExprEvalPushStep(state, &scratch);
1196  break;
1197  }
1198 
1199  case T_ScalarArrayOpExpr:
1200  {
1201  ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
1202  Expr *scalararg;
1203  Expr *arrayarg;
1204  FmgrInfo *finfo;
1205  FunctionCallInfo fcinfo;
1206  AclResult aclresult;
1207  Oid cmpfuncid;
1208 
1209  /*
1210  * Select the correct comparison function. When we do hashed
1211  * NOT IN clauses, the opfuncid will be the inequality
1212  * comparison function and negfuncid will be set to equality.
1213  * We need to use the equality function for hash probes.
1214  */
1215  if (OidIsValid(opexpr->negfuncid))
1216  {
1217  Assert(OidIsValid(opexpr->hashfuncid));
1218  cmpfuncid = opexpr->negfuncid;
1219  }
1220  else
1221  cmpfuncid = opexpr->opfuncid;
1222 
1223  Assert(list_length(opexpr->args) == 2);
1224  scalararg = (Expr *) linitial(opexpr->args);
1225  arrayarg = (Expr *) lsecond(opexpr->args);
1226 
1227  /* Check permission to call function */
1228  aclresult = object_aclcheck(ProcedureRelationId, cmpfuncid,
1229  GetUserId(),
1230  ACL_EXECUTE);
1231  if (aclresult != ACLCHECK_OK)
1232  aclcheck_error(aclresult, OBJECT_FUNCTION,
1233  get_func_name(cmpfuncid));
1234  InvokeFunctionExecuteHook(cmpfuncid);
1235 
1236  if (OidIsValid(opexpr->hashfuncid))
1237  {
1238  aclresult = object_aclcheck(ProcedureRelationId, opexpr->hashfuncid,
1239  GetUserId(),
1240  ACL_EXECUTE);
1241  if (aclresult != ACLCHECK_OK)
1242  aclcheck_error(aclresult, OBJECT_FUNCTION,
1243  get_func_name(opexpr->hashfuncid));
1244  InvokeFunctionExecuteHook(opexpr->hashfuncid);
1245  }
1246 
1247  /* Set up the primary fmgr lookup information */
1248  finfo = palloc0(sizeof(FmgrInfo));
1249  fcinfo = palloc0(SizeForFunctionCallInfo(2));
1250  fmgr_info(cmpfuncid, finfo);
1251  fmgr_info_set_expr((Node *) node, finfo);
1252  InitFunctionCallInfoData(*fcinfo, finfo, 2,
1253  opexpr->inputcollid, NULL, NULL);
1254 
1255  /*
1256  * If hashfuncid is set, we create a EEOP_HASHED_SCALARARRAYOP
1257  * step instead of a EEOP_SCALARARRAYOP. This provides much
1258  * faster lookup performance than the normal linear search
1259  * when the number of items in the array is anything but very
1260  * small.
1261  */
1262  if (OidIsValid(opexpr->hashfuncid))
1263  {
1264  /* Evaluate scalar directly into left function argument */
1265  ExecInitExprRec(scalararg, state,
1266  &fcinfo->args[0].value, &fcinfo->args[0].isnull);
1267 
1268  /*
1269  * Evaluate array argument into our return value. There's
1270  * no danger in that, because the return value is
1271  * guaranteed to be overwritten by
1272  * EEOP_HASHED_SCALARARRAYOP, and will not be passed to
1273  * any other expression.
1274  */
1275  ExecInitExprRec(arrayarg, state, resv, resnull);
1276 
1277  /* And perform the operation */
1279  scratch.d.hashedscalararrayop.inclause = opexpr->useOr;
1280  scratch.d.hashedscalararrayop.finfo = finfo;
1281  scratch.d.hashedscalararrayop.fcinfo_data = fcinfo;
1282  scratch.d.hashedscalararrayop.saop = opexpr;
1283 
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  ReleaseTupleDesc(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 
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 
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  /* ... but adopt RowExpr's column aliases */
1901  ExecTypeSetColNames(tupdesc, rowexpr->colnames);
1902  /* Bless the tupdesc so it can be looked up later */
1903  BlessTupleDesc(tupdesc);
1904  }
1905  else
1906  {
1907  /* it's been cast to a named type, use that */
1908  tupdesc = lookup_rowtype_tupdesc_copy(rowexpr->row_typeid, -1);
1909  }
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 */
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 
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_XmlExpr:
2214  {
2215  XmlExpr *xexpr = (XmlExpr *) node;
2216  int nnamed = list_length(xexpr->named_args);
2217  int nargs = list_length(xexpr->args);
2218  int off;
2219  ListCell *arg;
2220 
2221  scratch.opcode = EEOP_XMLEXPR;
2222  scratch.d.xmlexpr.xexpr = xexpr;
2223 
2224  /* allocate space for storing all the arguments */
2225  if (nnamed)
2226  {
2227  scratch.d.xmlexpr.named_argvalue =
2228  (Datum *) palloc(sizeof(Datum) * nnamed);
2229  scratch.d.xmlexpr.named_argnull =
2230  (bool *) palloc(sizeof(bool) * nnamed);
2231  }
2232  else
2233  {
2234  scratch.d.xmlexpr.named_argvalue = NULL;
2235  scratch.d.xmlexpr.named_argnull = NULL;
2236  }
2237 
2238  if (nargs)
2239  {
2240  scratch.d.xmlexpr.argvalue =
2241  (Datum *) palloc(sizeof(Datum) * nargs);
2242  scratch.d.xmlexpr.argnull =
2243  (bool *) palloc(sizeof(bool) * nargs);
2244  }
2245  else
2246  {
2247  scratch.d.xmlexpr.argvalue = NULL;
2248  scratch.d.xmlexpr.argnull = NULL;
2249  }
2250 
2251  /* prepare argument execution */
2252  off = 0;
2253  foreach(arg, xexpr->named_args)
2254  {
2255  Expr *e = (Expr *) lfirst(arg);
2256 
2258  &scratch.d.xmlexpr.named_argvalue[off],
2259  &scratch.d.xmlexpr.named_argnull[off]);
2260  off++;
2261  }
2262 
2263  off = 0;
2264  foreach(arg, xexpr->args)
2265  {
2266  Expr *e = (Expr *) lfirst(arg);
2267 
2269  &scratch.d.xmlexpr.argvalue[off],
2270  &scratch.d.xmlexpr.argnull[off]);
2271  off++;
2272  }
2273 
2274  /* and evaluate the actual XML expression */
2275  ExprEvalPushStep(state, &scratch);
2276  break;
2277  }
2278 
2279  case T_NullTest:
2280  {
2281  NullTest *ntest = (NullTest *) node;
2282 
2283  if (ntest->nulltesttype == IS_NULL)
2284  {
2285  if (ntest->argisrow)
2286  scratch.opcode = EEOP_NULLTEST_ROWISNULL;
2287  else
2288  scratch.opcode = EEOP_NULLTEST_ISNULL;
2289  }
2290  else if (ntest->nulltesttype == IS_NOT_NULL)
2291  {
2292  if (ntest->argisrow)
2294  else
2295  scratch.opcode = EEOP_NULLTEST_ISNOTNULL;
2296  }
2297  else
2298  {
2299  elog(ERROR, "unrecognized nulltesttype: %d",
2300  (int) ntest->nulltesttype);
2301  }
2302  /* initialize cache in case it's a row test */
2303  scratch.d.nulltest_row.rowcache.cacheptr = NULL;
2304 
2305  /* first evaluate argument into result variable */
2306  ExecInitExprRec(ntest->arg, state,
2307  resv, resnull);
2308 
2309  /* then push the test of that argument */
2310  ExprEvalPushStep(state, &scratch);
2311  break;
2312  }
2313 
2314  case T_BooleanTest:
2315  {
2316  BooleanTest *btest = (BooleanTest *) node;
2317 
2318  /*
2319  * Evaluate argument, directly into result datum. That's ok,
2320  * because resv/resnull is definitely not used anywhere else,
2321  * and will get overwritten by the below EEOP_BOOLTEST_IS_*
2322  * step.
2323  */
2324  ExecInitExprRec(btest->arg, state, resv, resnull);
2325 
2326  switch (btest->booltesttype)
2327  {
2328  case IS_TRUE:
2329  scratch.opcode = EEOP_BOOLTEST_IS_TRUE;
2330  break;
2331  case IS_NOT_TRUE:
2333  break;
2334  case IS_FALSE:
2335  scratch.opcode = EEOP_BOOLTEST_IS_FALSE;
2336  break;
2337  case IS_NOT_FALSE:
2339  break;
2340  case IS_UNKNOWN:
2341  /* Same as scalar IS NULL test */
2342  scratch.opcode = EEOP_NULLTEST_ISNULL;
2343  break;
2344  case IS_NOT_UNKNOWN:
2345  /* Same as scalar IS NOT NULL test */
2346  scratch.opcode = EEOP_NULLTEST_ISNOTNULL;
2347  break;
2348  default:
2349  elog(ERROR, "unrecognized booltesttype: %d",
2350  (int) btest->booltesttype);
2351  }
2352 
2353  ExprEvalPushStep(state, &scratch);
2354  break;
2355  }
2356 
2357  case T_CoerceToDomain:
2358  {
2359  CoerceToDomain *ctest = (CoerceToDomain *) node;
2360 
2361  ExecInitCoerceToDomain(&scratch, ctest, state,
2362  resv, resnull);
2363  break;
2364  }
2365 
2366  case T_CoerceToDomainValue:
2367  {
2368  /*
2369  * Read from location identified by innermost_domainval. Note
2370  * that innermost_domainval could be NULL, if we're compiling
2371  * a standalone domain check rather than one embedded in a
2372  * larger expression. In that case we must read from
2373  * econtext->domainValue_datum. We'll take care of that
2374  * scenario at runtime.
2375  */
2376  scratch.opcode = EEOP_DOMAIN_TESTVAL;
2377  /* we share instruction union variant with case testval */
2378  scratch.d.casetest.value = state->innermost_domainval;
2379  scratch.d.casetest.isnull = state->innermost_domainnull;
2380 
2381  ExprEvalPushStep(state, &scratch);
2382  break;
2383  }
2384 
2385  case T_CurrentOfExpr:
2386  {
2387  scratch.opcode = EEOP_CURRENTOFEXPR;
2388  ExprEvalPushStep(state, &scratch);
2389  break;
2390  }
2391 
2392  case T_NextValueExpr:
2393  {
2394  NextValueExpr *nve = (NextValueExpr *) node;
2395 
2396  scratch.opcode = EEOP_NEXTVALUEEXPR;
2397  scratch.d.nextvalueexpr.seqid = nve->seqid;
2398  scratch.d.nextvalueexpr.seqtypid = nve->typeId;
2399 
2400  ExprEvalPushStep(state, &scratch);
2401  break;
2402  }
2403 
2404  default:
2405  elog(ERROR, "unrecognized node type: %d",
2406  (int) nodeTag(node));
2407  break;
2408  }
2409 }
#define InvalidAttrNumber
Definition: attnum.h:23
static void ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:3109
static void ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, ExprState *state)
Definition: execExpr.c:2763
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:319
static void ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:2836
static void ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, Oid inputcollid, ExprState *state)
Definition: execExpr.c:2444
@ EEOP_SUBPLAN
Definition: execExpr.h:240
@ EEOP_CONVERT_ROWTYPE
Definition: execExpr.h:233
@ EEOP_ARRAYEXPR
Definition: execExpr.h:175
@ EEOP_DOMAIN_TESTVAL
Definition: execExpr.h:224
@ EEOP_PARAM_EXTERN
Definition: execExpr.h:159
@ EEOP_BOOL_AND_STEP
Definition: execExpr.h:121
@ EEOP_AGGREF
Definition: execExpr.h:237
@ EEOP_ROWCOMPARE_FINAL
Definition: execExpr.h:186
@ EEOP_IOCOERCE
Definition: execExpr.h:169
@ EEOP_GROUPING_FUNC
Definition: execExpr.h:238
@ EEOP_BOOLTEST_IS_NOT_FALSE
Definition: execExpr.h:155
@ EEOP_NEXTVALUEEXPR
Definition: execExpr.h:174
@ EEOP_SCAN_VAR
Definition: execExpr.h:77
@ EEOP_BOOL_NOT_STEP
Definition: execExpr.h:130
@ EEOP_SCAN_SYSVAR
Definition: execExpr.h:82
@ EEOP_SCALARARRAYOP
Definition: execExpr.h:234
@ EEOP_WINDOW_FUNC
Definition: execExpr.h:239
@ EEOP_NULLTEST_ROWISNOTNULL
Definition: execExpr.h:149
@ EEOP_ROW
Definition: execExpr.h:177
@ EEOP_FIELDSTORE_FORM
Definition: execExpr.h:205
@ EEOP_NULLIF
Definition: execExpr.h:172
@ EEOP_CURRENTOFEXPR
Definition: execExpr.h:173
@ EEOP_INNER_SYSVAR
Definition: execExpr.h:80
@ EEOP_BOOL_OR_STEP_LAST
Definition: execExpr.h:127
@ EEOP_BOOL_OR_STEP_FIRST
Definition: execExpr.h:125
@ EEOP_XMLEXPR
Definition: execExpr.h:236
@ EEOP_OUTER_SYSVAR
Definition: execExpr.h:81
@ EEOP_BOOL_OR_STEP
Definition: execExpr.h:126
@ EEOP_NULLTEST_ROWISNULL
Definition: execExpr.h:148
@ EEOP_BOOLTEST_IS_TRUE
Definition: execExpr.h:152
@ EEOP_NULLTEST_ISNOTNULL
Definition: execExpr.h:145
@ EEOP_ROWCOMPARE_STEP
Definition: execExpr.h:183
@ EEOP_DISTINCT
Definition: execExpr.h:170
@ EEOP_BOOL_AND_STEP_FIRST
Definition: execExpr.h:120
@ EEOP_JUMP
Definition: execExpr.h:136
@ EEOP_BOOL_AND_STEP_LAST
Definition: execExpr.h:122
@ EEOP_JUMP_IF_NOT_NULL
Definition: execExpr.h:140
@ EEOP_FIELDSTORE_DEFORM
Definition: execExpr.h:198
@ EEOP_BOOLTEST_IS_FALSE
Definition: execExpr.h:154
@ EEOP_BOOLTEST_IS_NOT_TRUE
Definition: execExpr.h:153
@ EEOP_PARAM_EXEC
Definition: execExpr.h:158
@ EEOP_NULLTEST_ISNULL
Definition: execExpr.h:144
@ EEOP_MINMAX
Definition: execExpr.h:189
@ EEOP_ARRAYCOERCE
Definition: execExpr.h:176
@ EEOP_FIELDSELECT
Definition: execExpr.h:192
@ EEOP_CASE_TESTVAL
Definition: execExpr.h:163
@ EEOP_HASHED_SCALARARRAYOP
Definition: execExpr.h:235
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2071
void ExecTypeSetColNames(TupleDesc typeInfo, List *namesList)
Definition: execTuples.c:2030
TupleDesc ExecTypeFromExprList(List *exprList)
Definition: execTuples.c:1997
int i
Definition: isn.c:73
void get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op, int *strategy, Oid *lefttype, Oid *righttype)
Definition: lsyscache.c:135
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2717
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2865
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2229
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:795
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2832
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:337
#define BTORDER_PROC
Definition: nbtree.h:701
SubPlanState * ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
Definition: nodeSubplan.c:804
#define nodeTag(nodeptr)
Definition: nodes.h:122
#define lsecond(l)
Definition: pg_list.h:181
#define forfive(cell1, list1, cell2, list2, cell3, list3, cell4, list4, cell5, list5)
Definition: pg_list.h:535
#define lfirst_oid(lc)
Definition: pg_list.h:172
void check_stack_depth(void)
Definition: postgres.c:3440
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:600
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:560
#define InvalidOid
Definition: postgres_ext.h:36
@ IS_NOT_TRUE
Definition: primnodes.h:1382
@ IS_NOT_FALSE
Definition: primnodes.h:1382
@ IS_NOT_UNKNOWN
Definition: primnodes.h:1382
@ IS_TRUE
Definition: primnodes.h:1382
@ IS_UNKNOWN
Definition: primnodes.h:1382
@ IS_FALSE
Definition: primnodes.h:1382
@ AND_EXPR
Definition: primnodes.h:758
@ OR_EXPR
Definition: primnodes.h:758
@ NOT_EXPR
Definition: primnodes.h:758
@ PARAM_EXTERN
Definition: primnodes.h:302
@ PARAM_EXEC
Definition: primnodes.h:303
@ IS_NULL
Definition: primnodes.h:1359
@ IS_NOT_NULL
Definition: primnodes.h:1359
List * aggs
Definition: execnodes.h:2359
Definition: plannodes.h:993
List * groupingSets
Definition: plannodes.h:1024
int aggno
Definition: primnodes.h:430
bool multidims
Definition: primnodes.h:1179
List * elements
Definition: primnodes.h:1178
Oid element_typeid
Definition: primnodes.h:1177
BoolExprType boolop
Definition: primnodes.h:766
List * args
Definition: primnodes.h:767
BoolTestType booltesttype
Definition: primnodes.h:1389
Expr * arg
Definition: primnodes.h:1388
Expr * arg
Definition: primnodes.h:1119
Expr * defresult
Definition: primnodes.h:1121
List * args
Definition: primnodes.h:1120
List * args
Definition: primnodes.h:1271
Expr * arg
Definition: primnodes.h:1021
Oid resulttype
Definition: primnodes.h:1022
Datum constvalue
Definition: primnodes.h:263
bool constisnull
Definition: primnodes.h:264
struct ExprEvalStep::@50::@84 grouping_func
struct ExprEvalStep::@50::@70 row
struct ExprEvalStep::@50::@73 minmax
struct ExprEvalStep::@50::@58 boolexpr
struct ExprEvalStep::@50::@71 rowcompare_step
struct ExprEvalStep::@50::@72 rowcompare_final
struct ExprEvalStep::@50::@61 nulltest_row
struct ExprEvalStep::@50::@80 scalararrayop
struct ExprEvalStep::@50::@83 aggref
struct ExprEvalStep::@50::@69 arraycoerce
struct ExprEvalStep::@50::@67 nextvalueexpr
struct ExprEvalStep::@50::@75 fieldstore
struct ExprEvalStep::@50::@74 fieldselect
struct ExprEvalStep::@50::@82 xmlexpr
struct ExprEvalStep::@50::@68 arrayexpr
struct ExprEvalStep::@50::@62 param
struct ExprEvalStep::@50::@66 iocoerce
struct ExprEvalStep::@50::@81 hashedscalararrayop
struct ExprEvalStep::@50::@85 window_func
struct ExprEvalStep::@50::@86 subplan
struct ExprEvalStep::@50::@79 convert_rowtype
struct ExprEvalStep::@50::@64 casetest
Expr * expr
Definition: execnodes.h:110
Datum resvalue
Definition: execnodes.h:90
struct ExprEvalStep * steps
Definition: execnodes.h:101
bool resnull
Definition: execnodes.h:88
ParamListInfo ext_params
Definition: execnodes.h:125
struct PlanState * parent
Definition: execnodes.h:124
bool * innermost_casenull
Definition: execnodes.h:128
Datum * innermost_caseval
Definition: execnodes.h:127
int steps_len
Definition: execnodes.h:120
AttrNumber fieldnum
Definition: primnodes.h:950
Oid resulttype
Definition: primnodes.h:951
Expr * arg
Definition: primnodes.h:949
List * newvals
Definition: primnodes.h:979
Expr * arg
Definition: primnodes.h:978
Oid resulttype
Definition: primnodes.h:981
List * fieldnums
Definition: primnodes.h:980
Oid funcid
Definition: primnodes.h:598
List * args
Definition: primnodes.h:606
Oid inputcollid
Definition: primnodes.h:605
Oid inputcollid
Definition: primnodes.h:1289
List * args
Definition: primnodes.h:1291
MinMaxOp op
Definition: primnodes.h:1290
Oid minmaxtype
Definition: primnodes.h:1287
NullTestType nulltesttype
Definition: primnodes.h:1366
bool argisrow
Definition: primnodes.h:1367
Expr * arg
Definition: primnodes.h:1365
List * args
Definition: primnodes.h:666
Oid inputcollid
Definition: primnodes.h:663
ParamCompileHook paramCompile
Definition: params.h:114
int paramid
Definition: primnodes.h:312
Oid paramtype
Definition: primnodes.h:313
ParamKind paramkind
Definition: primnodes.h:311
Expr * arg
Definition: primnodes.h:1001
RowCompareType rctype
Definition: primnodes.h:1255
List * opfamilies
Definition: primnodes.h:1257
List * inputcollids
Definition: primnodes.h:1258
Oid row_typeid
Definition: primnodes.h:1208
List * args
Definition: primnodes.h:1207
List * colnames
Definition: primnodes.h:1223
WindowFunc * wfunc
Definition: execnodes.h:855
ExprState * aggfilter
Definition: execnodes.h:857
bool winagg
Definition: primnodes.h:497
List * args
Definition: primnodes.h:493
Expr * aggfilter
Definition: primnodes.h:494
List * args
Definition: primnodes.h:1331
List * named_args
Definition: primnodes.h:1329
Definition: type.h:88
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:122
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1824
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:339
TupleDesc lookup_rowtype_tupdesc_copy(Oid type_id, int32 typmod)
Definition: typcache.c:1858
#define TYPECACHE_CMP_PROC
Definition: typcache.h:139
static void convert(const int32 val, char *const buf)
Definition: zic.c:1992

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, WindowFuncExprState::aggfilter, WindowFunc::aggfilter, Aggref::aggno, ExprEvalStep::aggref, AggState::aggs, AND_EXPR, arg, FieldSelect::arg, FieldStore::arg, RelabelType::arg, CoerceViaIO::arg, ArrayCoerceExpr::arg, CaseExpr::arg, NullTest::arg, BooleanTest::arg, NullTest::argisrow, FunctionCallInfoBaseData::args, WindowFuncExprState::args, WindowFunc::args, FuncExpr::args, OpExpr::args, ScalarArrayOpExpr::args, BoolExpr::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, Const::constisnull, ExprEvalStep::constval, Const::constvalue, convert(), ExprEvalStep::convert_rowtype, ExprEvalStep::d, 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_SUBPLAN, EEOP_WINDOW_FUNC, EEOP_XMLEXPR, ArrayExpr::element_typeid, ArrayExpr::elements, ArrayCoerceExpr::elemexpr, elog(), ereport, errcode(), errmsg(), ERROR, ExecInitCoerceToDomain(), ExecInitExpr(), ExecInitExprList(), ExecInitFunc(), ExecInitSubPlan(), ExecInitSubscriptingRef(), ExecInitWholeRowVar(), ExecReadyExpr(), ExecTypeFromExprList(), ExecTypeSetColNames(), ExprState::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, i, InitFunctionCallInfoData, INNER_VAR, ExprState::innermost_casenull, ExprState::innermost_caseval, 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_aclcheck(), OBJECT_FUNCTION, ObjectIdGetDatum(), OidIsValid, MinMaxExpr::op, ExprEvalStep::opcode, RowCompareExpr::opfamilies, RowCompareExpr::opnos, OR_EXPR, OUTER_VAR, palloc(), palloc0(), ExprEvalStep::param, PARAM_EXEC, PARAM_EXTERN, ParamListInfoData::paramCompile, Param::paramid, Param::paramkind, Param::paramtype, ExprState::parent, RowCompareExpr::rargs, RowCompareExpr::rctype, ReleaseTupleDesc, ExprEvalStep::resnull, ExprState::resnull, FieldSelect::resulttype, FieldStore::resulttype, CoerceViaIO::resulttype, ArrayCoerceExpr::resulttype, ExprEvalStep::resvalue, ExprState::resvalue, ExprEvalStep::row, RowExpr::row_typeid, ExprEvalStep::rowcompare_final, ExprEvalStep::rowcompare_step, ExprEvalStep::scalararrayop, NextValueExpr::seqid, SizeForFunctionCallInfo, ExprState::steps, ExprState::steps_len, ExprEvalStep::subplan, TupleDescAttr, TYPECACHE_CMP_PROC, NextValueExpr::typeId, ScalarArrayOpExpr::useOr, NullableDatum::value, values, ExprEvalStep::var, WindowFuncExprState::wfunc, WindowFunc::winagg, ExprEvalStep::window_func, and ExprEvalStep::xmlexpr.

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

◆ ExecInitExprSlots()

static void ExecInitExprSlots ( ExprState state,
Node node 
)
static

Definition at line 2549 of file execExpr.c.

2550 {
2551  LastAttnumInfo info = {0, 0, 0};
2552 
2553  /*
2554  * Figure out which attributes we're going to need.
2555  */
2556  get_last_attnums_walker(node, &info);
2557 
2558  ExecPushExprSlots(state, &info);
2559 }

References ExecPushExprSlots(), and get_last_attnums_walker().

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

◆ ExecInitExprWithParams()

ExprState* ExecInitExprWithParams ( Expr node,
ParamListInfo  ext_params 
)

Definition at line 161 of file execExpr.c.

162 {
163  ExprState *state;
164  ExprEvalStep scratch = {0};
165 
166  /* Special case: NULL expression produces a NULL ExprState pointer */
167  if (node == NULL)
168  return NULL;
169 
170  /* Initialize ExprState with empty step list */
172  state->expr = node;
173  state->parent = NULL;
174  state->ext_params = ext_params;
175 
176  /* Insert EEOP_*_FETCHSOME steps as needed */
177  ExecInitExprSlots(state, (Node *) node);
178 
179  /* Compile the expression proper */
180  ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
181 
182  /* Finally, append a DONE step */
183  scratch.opcode = EEOP_DONE;
184  ExprEvalPushStep(state, &scratch);
185 
187 
188  return state;
189 }

References EEOP_DONE, ExecInitExprRec(), ExecInitExprSlots(), ExecReadyExpr(), ExprEvalPushStep(), makeNode, and ExprEvalStep::opcode.

Referenced by exec_eval_simple_expr(), and InitPartitionPruneContext().

◆ ExecInitFunc()

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

Definition at line 2444 of file execExpr.c.

2446 {
2447  int nargs = list_length(args);
2448  AclResult aclresult;
2449  FmgrInfo *flinfo;
2450  FunctionCallInfo fcinfo;
2451  int argno;
2452  ListCell *lc;
2453 
2454  /* Check permission to call function */
2455  aclresult = object_aclcheck(ProcedureRelationId, funcid, GetUserId(), ACL_EXECUTE);
2456  if (aclresult != ACLCHECK_OK)
2457  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(funcid));
2458  InvokeFunctionExecuteHook(funcid);
2459 
2460  /*
2461  * Safety check on nargs. Under normal circumstances this should never
2462  * fail, as parser should check sooner. But possibly it might fail if
2463  * server has been compiled with FUNC_MAX_ARGS smaller than some functions
2464  * declared in pg_proc?
2465  */
2466  if (nargs > FUNC_MAX_ARGS)
2467  ereport(ERROR,
2468  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2469  errmsg_plural("cannot pass more than %d argument to a function",
2470  "cannot pass more than %d arguments to a function",
2471  FUNC_MAX_ARGS,
2472  FUNC_MAX_ARGS)));
2473 
2474  /* Allocate function lookup data and parameter workspace for this call */
2475  scratch->d.func.finfo = palloc0(sizeof(FmgrInfo));
2476  scratch->d.func.fcinfo_data = palloc0(SizeForFunctionCallInfo(nargs));
2477  flinfo = scratch->d.func.finfo;
2478  fcinfo = scratch->d.func.fcinfo_data;
2479 
2480  /* Set up the primary fmgr lookup information */
2481  fmgr_info(funcid, flinfo);
2482  fmgr_info_set_expr((Node *) node, flinfo);
2483 
2484  /* Initialize function call parameter structure too */
2485  InitFunctionCallInfoData(*fcinfo, flinfo,
2486  nargs, inputcollid, NULL, NULL);
2487 
2488  /* Keep extra copies of this info to save an indirection at runtime */
2489  scratch->d.func.fn_addr = flinfo->fn_addr;
2490  scratch->d.func.nargs = nargs;
2491 
2492  /* We only support non-set functions here */
2493  if (flinfo->fn_retset)
2494  ereport(ERROR,
2495  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2496  errmsg("set-valued function called in context that cannot accept a set"),
2497  state->parent ?
2498  executor_errposition(state->parent->state,
2499  exprLocation((Node *) node)) : 0));
2500 
2501  /* Build code to evaluate arguments directly into the fcinfo struct */
2502  argno = 0;
2503  foreach(lc, args)
2504  {
2505  Expr *arg = (Expr *) lfirst(lc);
2506 
2507  if (IsA(arg, Const))
2508  {
2509  /*
2510  * Don't evaluate const arguments every round; especially
2511  * interesting for constants in comparisons.
2512  */
2513  Const *con = (Const *) arg;
2514 
2515  fcinfo->args[argno].value = con->constvalue;
2516  fcinfo->args[argno].isnull = con->constisnull;
2517  }
2518  else
2519  {
2521  &fcinfo->args[argno].value,
2522  &fcinfo->args[argno].isnull);
2523  }
2524  argno++;
2525  }
2526 
2527  /* Insert appropriate opcode depending on strictness and stats level */
2528  if (pgstat_track_functions <= flinfo->fn_stats)
2529  {
2530  if (flinfo->fn_strict && nargs > 0)
2531  scratch->opcode = EEOP_FUNCEXPR_STRICT;
2532  else
2533  scratch->opcode = EEOP_FUNCEXPR;
2534  }
2535  else
2536  {
2537  if (flinfo->fn_strict && nargs > 0)
2539  else
2540  scratch->opcode = EEOP_FUNCEXPR_FUSAGE;
2541  }
2542 }
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1016
@ EEOP_FUNCEXPR_STRICT_FUSAGE
Definition: execExpr.h:112
@ EEOP_FUNCEXPR_STRICT
Definition: execExpr.h:110
@ EEOP_FUNCEXPR
Definition: execExpr.h:109
@ EEOP_FUNCEXPR_FUSAGE
Definition: execExpr.h:111
int executor_errposition(EState *estate, int location)
Definition: execUtils.c:900
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1243
#define FUNC_MAX_ARGS
bool fn_retset
Definition: fmgr.h:62

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, arg, generate_unaccent_rules::args, 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_aclcheck(), OBJECT_FUNCTION, ExprEvalStep::opcode, palloc0(), SizeForFunctionCallInfo, and NullableDatum::value.

Referenced by ExecInitExprRec().

◆ ExecInitQual()

ExprState* ExecInitQual ( List qual,
PlanState parent 
)

Definition at line 210 of file execExpr.c.

211 {
212  ExprState *state;
213  ExprEvalStep scratch = {0};
214  List *adjust_jumps = NIL;
215  ListCell *lc;
216 
217  /* short-circuit (here and in ExecQual) for empty restriction list */
218  if (qual == NIL)
219  return NULL;
220 
221  Assert(IsA(qual, List));
222 
224  state->expr = (Expr *) qual;
225  state->parent = parent;
226  state->ext_params = NULL;
227 
228  /* mark expression as to be used with ExecQual() */
229  state->flags = EEO_FLAG_IS_QUAL;
230 
231  /* Insert EEOP_*_FETCHSOME steps as needed */
232  ExecInitExprSlots(state, (Node *) qual);
233 
234  /*
235  * ExecQual() needs to return false for an expression returning NULL. That
236  * allows us to short-circuit the evaluation the first time a NULL is
237  * encountered. As qual evaluation is a hot-path this warrants using a
238  * special opcode for qual evaluation that's simpler than BOOL_AND (which
239  * has more complex NULL handling).
240  */
241  scratch.opcode = EEOP_QUAL;
242 
243  /*
244  * We can use ExprState's resvalue/resnull as target for each qual expr.
245  */
246  scratch.resvalue = &state->resvalue;
247  scratch.resnull = &state->resnull;
248 
249  foreach(lc, qual)
250  {
251  Expr *node = (Expr *) lfirst(lc);
252 
253  /* first evaluate expression */
254  ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
255 
256  /* then emit EEOP_QUAL to detect if it's false (or null) */
257  scratch.d.qualexpr.jumpdone = -1;
258  ExprEvalPushStep(state, &scratch);
259  adjust_jumps = lappend_int(adjust_jumps,
260  state->steps_len - 1);
261  }
262 
263  /* adjust jump targets */
264  foreach(lc, adjust_jumps)
265  {
266  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
267 
268  Assert(as->opcode == EEOP_QUAL);
269  Assert(as->d.qualexpr.jumpdone == -1);
270  as->d.qualexpr.jumpdone = state->steps_len;
271  }
272 
273  /*
274  * At the end, we don't need to do anything more. The last qual expr must
275  * have yielded TRUE, and since its result is stored in the desired output
276  * location, we're done.
277  */
278  scratch.opcode = EEOP_DONE;
279  ExprEvalPushStep(state, &scratch);
280 
282 
283  return state;
284 }

References Assert(), ExprEvalStep::d, EEO_FLAG_IS_QUAL, EEOP_DONE, EEOP_QUAL, ExecInitExprRec(), ExecInitExprSlots(), ExecReadyExpr(), ExprEvalPushStep(), IsA, lappend_int(), lfirst, lfirst_int, makeNode, NIL, ExprEvalStep::opcode, ExprEvalStep::qualexpr, ExprEvalStep::resnull, and ExprEvalStep::resvalue.

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

◆ ExecInitSubscriptingRef()

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

Definition at line 2836 of file execExpr.c.

2838 {
2839  bool isAssignment = (sbsref->refassgnexpr != NULL);
2840  int nupper = list_length(sbsref->refupperindexpr);
2841  int nlower = list_length(sbsref->reflowerindexpr);
2842  const SubscriptRoutines *sbsroutines;
2843  SubscriptingRefState *sbsrefstate;
2844  SubscriptExecSteps methods;
2845  char *ptr;
2846  List *adjust_jumps = NIL;
2847  ListCell *lc;
2848  int i;
2849 
2850  /* Look up the subscripting support methods */
2851  sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype, NULL);
2852  if (!sbsroutines)
2853  ereport(ERROR,
2854  (errcode(ERRCODE_DATATYPE_MISMATCH),
2855  errmsg("cannot subscript type %s because it does not support subscripting",
2856  format_type_be(sbsref->refcontainertype)),
2857  state->parent ?
2858  executor_errposition(state->parent->state,
2859  exprLocation((Node *) sbsref)) : 0));
2860 
2861  /* Allocate sbsrefstate, with enough space for per-subscript arrays too */
2862  sbsrefstate = palloc0(MAXALIGN(sizeof(SubscriptingRefState)) +
2863  (nupper + nlower) * (sizeof(Datum) +
2864  2 * sizeof(bool)));
2865 
2866  /* Fill constant fields of SubscriptingRefState */
2867  sbsrefstate->isassignment = isAssignment;
2868  sbsrefstate->numupper = nupper;
2869  sbsrefstate->numlower = nlower;
2870  /* Set up per-subscript arrays */
2871  ptr = ((char *) sbsrefstate) + MAXALIGN(sizeof(SubscriptingRefState));
2872  sbsrefstate->upperindex = (Datum *) ptr;
2873  ptr += nupper * sizeof(Datum);
2874  sbsrefstate->lowerindex = (Datum *) ptr;
2875  ptr += nlower * sizeof(Datum);
2876  sbsrefstate->upperprovided = (bool *) ptr;
2877  ptr += nupper * sizeof(bool);
2878  sbsrefstate->lowerprovided = (bool *) ptr;
2879  ptr += nlower * sizeof(bool);
2880  sbsrefstate->upperindexnull = (bool *) ptr;
2881  ptr += nupper * sizeof(bool);
2882  sbsrefstate->lowerindexnull = (bool *) ptr;
2883  /* ptr += nlower * sizeof(bool); */
2884 
2885  /*
2886  * Let the container-type-specific code have a chance. It must fill the
2887  * "methods" struct with function pointers for us to possibly use in
2888  * execution steps below; and it can optionally set up some data pointed
2889  * to by the workspace field.
2890  */
2891  memset(&methods, 0, sizeof(methods));
2892  sbsroutines->exec_setup(sbsref, sbsrefstate, &methods);
2893 
2894  /*
2895  * Evaluate array input. It's safe to do so into resv/resnull, because we
2896  * won't use that as target for any of the other subexpressions, and it'll
2897  * be overwritten by the final EEOP_SBSREF_FETCH/ASSIGN step, which is
2898  * pushed last.
2899  */
2900  ExecInitExprRec(sbsref->refexpr, state, resv, resnull);
2901 
2902  /*
2903  * If refexpr yields NULL, and the operation should be strict, then result
2904  * is NULL. We can implement this with just JUMP_IF_NULL, since we
2905  * evaluated the array into the desired target location.
2906  */
2907  if (!isAssignment && sbsroutines->fetch_strict)
2908  {
2909  scratch->opcode = EEOP_JUMP_IF_NULL;
2910  scratch->d.jump.jumpdone = -1; /* adjust later */
2911  ExprEvalPushStep(state, scratch);
2912  adjust_jumps = lappend_int(adjust_jumps,
2913  state->steps_len - 1);
2914  }
2915 
2916  /* Evaluate upper subscripts */
2917  i = 0;
2918  foreach(lc, sbsref->refupperindexpr)
2919  {
2920  Expr *e = (Expr *) lfirst(lc);
2921 
2922  /* When slicing, individual subscript bounds can be omitted */
2923  if (!e)
2924  {
2925  sbsrefstate->upperprovided[i] = false;
2926  sbsrefstate->upperindexnull[i] = true;
2927  }
2928  else
2929  {
2930  sbsrefstate->upperprovided[i] = true;
2931  /* Each subscript is evaluated into appropriate array entry */
2933  &sbsrefstate->upperindex[i],
2934  &sbsrefstate->upperindexnull[i]);
2935  }
2936  i++;
2937  }
2938 
2939  /* Evaluate lower subscripts similarly */
2940  i = 0;
2941  foreach(lc, sbsref->reflowerindexpr)
2942  {
2943  Expr *e = (Expr *) lfirst(lc);
2944 
2945  /* When slicing, individual subscript bounds can be omitted */
2946  if (!e)
2947  {
2948  sbsrefstate->lowerprovided[i] = false;
2949  sbsrefstate->lowerindexnull[i] = true;
2950  }
2951  else
2952  {
2953  sbsrefstate->lowerprovided[i] = true;
2954  /* Each subscript is evaluated into appropriate array entry */
2956  &sbsrefstate->lowerindex[i],
2957  &sbsrefstate->lowerindexnull[i]);
2958  }
2959  i++;
2960  }
2961 
2962  /* SBSREF_SUBSCRIPTS checks and converts all the subscripts at once */
2963  if (methods.sbs_check_subscripts)
2964  {
2965  scratch->opcode = EEOP_SBSREF_SUBSCRIPTS;
2966  scratch->d.sbsref_subscript.subscriptfunc = methods.sbs_check_subscripts;
2967  scratch->d.sbsref_subscript.state = sbsrefstate;
2968  scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */
2969  ExprEvalPushStep(state, scratch);
2970  adjust_jumps = lappend_int(adjust_jumps,
2971  state->steps_len - 1);
2972  }
2973 
2974  if (isAssignment)
2975  {
2976  Datum *save_innermost_caseval;
2977  bool *save_innermost_casenull;
2978 
2979  /* Check for unimplemented methods */
2980  if (!methods.sbs_assign)
2981  ereport(ERROR,
2982  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2983  errmsg("type %s does not support subscripted assignment",
2984  format_type_be(sbsref->refcontainertype))));
2985 
2986  /*
2987  * We might have a nested-assignment situation, in which the
2988  * refassgnexpr is itself a FieldStore or SubscriptingRef that needs
2989  * to obtain and modify the previous value of the array element or
2990  * slice being replaced. If so, we have to extract that value from
2991  * the array and pass it down via the CaseTestExpr mechanism. It's
2992  * safe to reuse the CASE mechanism because there cannot be a CASE
2993  * between here and where the value would be needed, and an array
2994  * assignment can't be within a CASE either. (So saving and restoring
2995  * innermost_caseval is just paranoia, but let's do it anyway.)
2996  *
2997  * Since fetching the old element might be a nontrivial expense, do it
2998  * only if the argument actually needs it.
2999  */
3001  {
3002  if (!methods.sbs_fetch_old)
3003  ereport(ERROR,
3004  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3005  errmsg("type %s does not support subscripted assignment",
3006  format_type_be(sbsref->refcontainertype))));
3007  scratch->opcode = EEOP_SBSREF_OLD;
3008  scratch->d.sbsref.subscriptfunc = methods.sbs_fetch_old;
3009  scratch->d.sbsref.state = sbsrefstate;
3010  ExprEvalPushStep(state, scratch);
3011  }
3012 
3013  /* SBSREF_OLD puts extracted value into prevvalue/prevnull */
3014  save_innermost_caseval = state->innermost_caseval;
3015  save_innermost_casenull = state->innermost_casenull;
3016  state->innermost_caseval = &sbsrefstate->prevvalue;
3017  state->innermost_casenull = &sbsrefstate->prevnull;
3018 
3019  /* evaluate replacement value into replacevalue/replacenull */
3021  &sbsrefstate->replacevalue, &sbsrefstate->replacenull);
3022 
3023  state->innermost_caseval = save_innermost_caseval;
3024  state->innermost_casenull = save_innermost_casenull;
3025 
3026  /* and perform the assignment */
3027  scratch->opcode = EEOP_SBSREF_ASSIGN;
3028  scratch->d.sbsref.subscriptfunc = methods.sbs_assign;
3029  scratch->d.sbsref.state = sbsrefstate;
3030  ExprEvalPushStep(state, scratch);
3031  }
3032  else
3033  {
3034  /* array fetch is much simpler */
3035  scratch->opcode = EEOP_SBSREF_FETCH;
3036  scratch->d.sbsref.subscriptfunc = methods.sbs_fetch;
3037  scratch->d.sbsref.state = sbsrefstate;
3038  ExprEvalPushStep(state, scratch);
3039  }
3040 
3041  /* adjust jump targets */
3042  foreach(lc, adjust_jumps)
3043  {
3044  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
3045 
3046  if (as->opcode == EEOP_SBSREF_SUBSCRIPTS)
3047  {
3048  Assert(as->d.sbsref_subscript.jumpdone == -1);
3049  as->d.sbsref_subscript.jumpdone = state->steps_len;
3050  }
3051  else
3052  {
3054  Assert(as->d.jump.jumpdone == -1);
3055  as->d.jump.jumpdone = state->steps_len;
3056  }
3057  }
3058 }
#define MAXALIGN(LEN)
Definition: c.h:747
unsigned char bool
Definition: c.h:392
static bool isAssignmentIndirectionExpr(Expr *expr)
Definition: execExpr.c:3078
@ EEOP_SBSREF_SUBSCRIPTS
Definition: execExpr.h:208
@ EEOP_SBSREF_FETCH
Definition: execExpr.h:221
@ EEOP_SBSREF_ASSIGN
Definition: execExpr.h:218
@ EEOP_SBSREF_OLD
Definition: execExpr.h:215
@ EEOP_JUMP_IF_NULL
Definition: execExpr.h:139
const struct SubscriptRoutines * getSubscriptingRoutines(Oid typid, Oid *typelemp)
Definition: lsyscache.c:3088
struct ExprEvalStep::@50::@76 sbsref_subscript
struct ExprEvalStep::@50::@77 sbsref
ExecEvalSubroutine sbs_fetch_old
Definition: execExpr.h:710
ExecEvalBoolSubroutine sbs_check_subscripts
Definition: execExpr.h:707
ExecEvalSubroutine sbs_assign
Definition: execExpr.h:709
ExecEvalSubroutine sbs_fetch
Definition: execExpr.h:708
SubscriptExecSetup exec_setup
Definition: subscripting.h:161
Expr * refassgnexpr
Definition: primnodes.h:554
List * refupperindexpr
Definition: primnodes.h:547
Expr * refexpr
Definition: primnodes.h:552
Oid refcontainertype
Definition: primnodes.h:542
List * reflowerindexpr
Definition: primnodes.h:549

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, 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(), SubscriptingRefState::prevnull, SubscriptingRefState::prevvalue, SubscriptingRef::refassgnexpr, SubscriptingRef::refcontainertype, SubscriptingRef::refexpr, 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, SubscriptingRefState::upperindex, SubscriptingRefState::upperindexnull, and SubscriptingRefState::upperprovided.

Referenced by ExecInitExprRec().

◆ ExecInitWholeRowVar()

static void ExecInitWholeRowVar ( ExprEvalStep scratch,
Var variable,
ExprState state 
)
static

Definition at line 2763 of file execExpr.c.

2764 {
2765  PlanState *parent = state->parent;
2766 
2767  /* fill in all but the target */
2768  scratch->opcode = EEOP_WHOLEROW;
2769  scratch->d.wholerow.var = variable;
2770  scratch->d.wholerow.first = true;
2771  scratch->d.wholerow.slow = false;
2772  scratch->d.wholerow.tupdesc = NULL; /* filled at runtime */
2773  scratch->d.wholerow.junkFilter = NULL;
2774 
2775  /*
2776  * If the input tuple came from a subquery, it might contain "resjunk"
2777  * columns (such as GROUP BY or ORDER BY columns), which we don't want to
2778  * keep in the whole-row result. We can get rid of such columns by
2779  * passing the tuple through a JunkFilter --- but to make one, we have to
2780  * lay our hands on the subquery's targetlist. Fortunately, there are not
2781  * very many cases where this can happen, and we can identify all of them
2782  * by examining our parent PlanState. We assume this is not an issue in
2783  * standalone expressions that don't have parent plans. (Whole-row Vars
2784  * can occur in such expressions, but they will always be referencing
2785  * table rows.)
2786  */
2787  if (parent)
2788  {
2789  PlanState *subplan = NULL;
2790 
2791  switch (nodeTag(parent))
2792  {
2793  case T_SubqueryScanState:
2794  subplan = ((SubqueryScanState *) parent)->subplan;
2795  break;
2796  case T_CteScanState:
2797  subplan = ((CteScanState *) parent)->cteplanstate;
2798  break;
2799  default:
2800  break;
2801  }
2802 
2803  if (subplan)
2804  {
2805  bool junk_filter_needed = false;
2806  ListCell *tlist;
2807 
2808  /* Detect whether subplan tlist actually has any junk columns */
2809  foreach(tlist, subplan->plan->targetlist)
2810  {
2811  TargetEntry *tle = (TargetEntry *) lfirst(tlist);
2812 
2813  if (tle->resjunk)
2814  {
2815  junk_filter_needed = true;
2816  break;
2817  }
2818  }
2819 
2820  /* If so, build the junkfilter now */
2821  if (junk_filter_needed)
2822  {
2823  scratch->d.wholerow.junkFilter =
2825  ExecInitExtraTupleSlot(parent->state, NULL,
2826  &TTSOpsVirtual));
2827  }
2828  }
2829  }
2830 }
@ EEOP_WHOLEROW
Definition: execExpr.h:85
JunkFilter * ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
Definition: execJunk.c:60
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1831
struct ExprEvalStep::@50::@53 wholerow
Plan * plan
Definition: execnodes.h:1029
EState * state
Definition: execnodes.h:1031
List * targetlist
Definition: plannodes.h:153

References ExprEvalStep::d, EEOP_WHOLEROW, ExecInitExtraTupleSlot(), ExecInitJunkFilter(), lfirst, nodeTag, ExprEvalStep::opcode, PlanState::plan, TargetEntry::resjunk, PlanState::state, Plan::targetlist, TTSOpsVirtual, and ExprEvalStep::wholerow.

Referenced by ExecInitExprRec().

◆ ExecPrepareCheck()

ExprState* ExecPrepareCheck ( List qual,
EState estate 
)

Definition at line 798 of file execExpr.c.

799 {
800  ExprState *result;
801  MemoryContext oldcontext;
802 
803  oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
804 
805  qual = (List *) expression_planner((Expr *) qual);
806 
807  result = ExecInitCheck(qual, NULL);
808 
809  MemoryContextSwitchTo(oldcontext);
810 
811  return result;
812 }
ExprState * ExecInitCheck(List *qual, PlanState *parent)
Definition: execExpr.c:299
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:135
Expr * expression_planner(Expr *expr)
Definition: planner.c:6147
MemoryContext es_query_cxt
Definition: execnodes.h:655

References EState::es_query_cxt, ExecInitCheck(), expression_planner(), and MemoryContextSwitchTo().

Referenced by ExecPartitionCheck().

◆ ExecPrepareExpr()

ExprState* ExecPrepareExpr ( Expr node,
EState estate 
)

Definition at line 747 of file execExpr.c.

748 {
749  ExprState *result;
750  MemoryContext oldcontext;
751 
752  oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
753 
754  node = expression_planner(node);
755 
756  result = ExecInitExpr(node, NULL);
757 
758  MemoryContextSwitchTo(oldcontext);
759 
760  return result;
761 }

References EState::es_query_cxt, ExecInitExpr(), expression_planner(), and MemoryContextSwitchTo().

Referenced by ATRewriteTable(), check_default_partition_contents(), compute_expr_stats(), ExecComputeStoredGenerated(), ExecPrepareExprList(), ExecRelCheck(), ExecuteCallStmt(), pgoutput_row_filter_init(), StoreAttrDefault(), and validateDomainConstraint().

◆ ExecPrepareExprList()

List* ExecPrepareExprList ( List nodes,
EState estate 
)

Definition at line 821 of file execExpr.c.

822 {
823  List *result = NIL;
824  MemoryContext oldcontext;
825  ListCell *lc;
826 
827  /* Ensure that the list cell nodes are in the right context too */
828  oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
829 
830  foreach(lc, nodes)
831  {
832  Expr *e = (Expr *) lfirst(lc);
833 
834  result = lappend(result, ExecPrepareExpr(e, estate));
835  }
836 
837  MemoryContextSwitchTo(oldcontext);
838 
839  return result;
840 }
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:747

References EState::es_query_cxt, ExecPrepareExpr(), lappend(), lfirst, MemoryContextSwitchTo(), and NIL.

Referenced by EvaluateParams(), FormIndexDatum(), FormPartitionKeyDatum(), and make_build_data().

◆ ExecPrepareQual()

ExprState* ExecPrepareQual ( List qual,
EState estate 
)

Definition at line 775 of file execExpr.c.

776 {
777  ExprState *result;
778  MemoryContext oldcontext;
779 
780  oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
781 
782  qual = (List *) expression_planner((Expr *) qual);
783 
784  result = ExecInitQual(qual, NULL);
785 
786  MemoryContextSwitchTo(oldcontext);
787 
788  return result;
789 }
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:210

References EState::es_query_cxt, ExecInitQual(), expression_planner(), and MemoryContextSwitchTo().

Referenced by compute_index_stats(), ExecCheckIndexConstraints(), ExecInsertIndexTuples(), heapam_index_build_range_scan(), heapam_index_validate_scan(), IndexCheckExclusion(), and TriggerEnabled().

◆ ExecPushExprSlots()

static void ExecPushExprSlots ( ExprState state,
LastAttnumInfo info 
)
static

Definition at line 2567 of file execExpr.c.

2568 {
2569  ExprEvalStep scratch = {0};
2570 
2571  scratch.resvalue = NULL;
2572  scratch.resnull = NULL;
2573 
2574  /* Emit steps as needed */
2575  if (info->last_inner > 0)
2576  {
2577  scratch.opcode = EEOP_INNER_FETCHSOME;
2578  scratch.d.fetch.last_var = info->last_inner;
2579  scratch.d.fetch.fixed = false;
2580  scratch.d.fetch.kind = NULL;
2581  scratch.d.fetch.known_desc = NULL;
2582  if (ExecComputeSlotInfo(state, &scratch))
2583  ExprEvalPushStep(state, &scratch);
2584  }
2585  if (info->last_outer > 0)
2586  {
2587  scratch.opcode = EEOP_OUTER_FETCHSOME;
2588  scratch.d.fetch.last_var = info->last_outer;
2589  scratch.d.fetch.fixed = false;
2590  scratch.d.fetch.kind = NULL;
2591  scratch.d.fetch.known_desc = NULL;
2592  if (ExecComputeSlotInfo(state, &scratch))
2593  ExprEvalPushStep(state, &scratch);
2594  }
2595  if (info->last_scan > 0)
2596  {
2597  scratch.opcode = EEOP_SCAN_FETCHSOME;
2598  scratch.d.fetch.last_var = info->last_scan;
2599  scratch.d.fetch.fixed = false;
2600  scratch.d.fetch.kind = NULL;
2601  scratch.d.fetch.known_desc = NULL;
2602  if (ExecComputeSlotInfo(state, &scratch))
2603  ExprEvalPushStep(state, &scratch);
2604  }
2605 }
AttrNumber last_inner
Definition: execExpr.c:57

References ExprEvalStep::d, EEOP_INNER_FETCHSOME, EEOP_OUTER_FETCHSOME, EEOP_SCAN_FETCHSOME, ExecComputeSlotInfo(), ExprEvalPushStep(), ExprEvalStep::fetch, LastAttnumInfo::last_inner, LastAttnumInfo::last_outer, LastAttnumInfo::last_scan, ExprEvalStep::opcode, ExprEvalStep::resnull, and ExprEvalStep::resvalue.

Referenced by ExecBuildAggTrans(), ExecBuildUpdateProjection(), and ExecInitExprSlots().

◆ ExecReadyExpr()

static void ExecReadyExpr ( ExprState state)
static

Definition at line 884 of file execExpr.c.

885 {
886  if (jit_compile_expr(state))
887  return;
888 
890 }
void ExecReadyInterpretedExpr(ExprState *state)
bool jit_compile_expr(struct ExprState *state)
Definition: jit.c:153

References ExecReadyInterpretedExpr(), and jit_compile_expr().

Referenced by ExecBuildAggTrans(), ExecBuildGroupingEqual(), ExecBuildParamSetEqual(), ExecBuildProjectionInfo(), ExecBuildUpdateProjection(), ExecInitExpr(), ExecInitExprRec(), ExecInitExprWithParams(), and ExecInitQual().

◆ ExprEvalPushStep()

void ExprEvalPushStep ( ExprState es,
const ExprEvalStep s 
)

Definition at line 2418 of file execExpr.c.

2419 {
2420  if (es->steps_alloc == 0)
2421  {
2422  es->steps_alloc = 16;
2423  es->steps = palloc(sizeof(ExprEvalStep) * es->steps_alloc);
2424  }
2425  else if (es->steps_alloc == es->steps_len)
2426  {
2427  es->steps_alloc *= 2;
2428  es->steps = repalloc(es->steps,
2429  sizeof(ExprEvalStep) * es->steps_alloc);
2430  }
2431 
2432  memcpy(&es->steps[es->steps_len++], s, sizeof(ExprEvalStep));
2433 }
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1321
int steps_alloc
Definition: execnodes.h:121

References palloc(), repalloc(), ExprState::steps, ExprState::steps_alloc, and ExprState::steps_len.

Referenced by ExecBuildAggTrans(), ExecBuildAggTransCall(), ExecBuildGroupingEqual(), ExecBuildParamSetEqual(), ExecBuildProjectionInfo(), ExecBuildUpdateProjection(), ExecInitCoerceToDomain(), ExecInitExpr(), ExecInitExprRec(), ExecInitExprWithParams(), ExecInitQual(), ExecInitSubscriptingRef(), ExecPushExprSlots(), and plpgsql_param_compile().

◆ get_last_attnums_walker()

static bool get_last_attnums_walker ( Node node,
LastAttnumInfo info 
)
static

Definition at line 2611 of file execExpr.c.

2612 {
2613  if (node == NULL)
2614  return false;
2615  if (IsA(node, Var))
2616  {
2617  Var *variable = (Var *) node;
2618  AttrNumber attnum = variable->varattno;
2619 
2620  switch (variable->varno)
2621  {
2622  case INNER_VAR:
2623  info->last_inner = Max(info->last_inner, attnum);
2624  break;
2625 
2626  case OUTER_VAR:
2627  info->last_outer = Max(info->last_outer, attnum);
2628  break;
2629 
2630  /* INDEX_VAR is handled by default case */
2631 
2632  default:
2633  info->last_scan = Max(info->last_scan, attnum);
2634  break;
2635  }
2636  return false;
2637  }
2638 
2639  /*
2640  * Don't examine the arguments or filters of Aggrefs or WindowFuncs,
2641  * because those do not represent expressions to be evaluated within the
2642  * calling expression's econtext. GroupingFunc arguments are never
2643  * evaluated at all.
2644  */
2645  if (IsA(node, Aggref))
2646  return false;
2647  if (IsA(node, WindowFunc))
2648  return false;
2649  if (IsA(node, GroupingFunc))
2650  return false;
2652  (void *) info);
2653 }
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:151

References attnum, expression_tree_walker, INNER_VAR, IsA, LastAttnumInfo::last_inner, LastAttnumInfo::last_outer, LastAttnumInfo::last_scan, Max, and OUTER_VAR.

Referenced by ExecBuildAggTrans(), ExecBuildUpdateProjection(), and ExecInitExprSlots().

◆ isAssignmentIndirectionExpr()

static bool isAssignmentIndirectionExpr ( Expr expr)
static

Definition at line 3078 of file execExpr.c.

3079 {
3080  if (expr == NULL)
3081  return false; /* just paranoia */
3082  if (IsA(expr, FieldStore))
3083  {
3084  FieldStore *fstore = (FieldStore *) expr;
3085 
3086  if (fstore->arg && IsA(fstore->arg, CaseTestExpr))
3087  return true;
3088  }
3089  else if (IsA(expr, SubscriptingRef))
3090  {
3091  SubscriptingRef *sbsRef = (SubscriptingRef *) expr;
3092 
3093  if (sbsRef->refexpr && IsA(sbsRef->refexpr, CaseTestExpr))
3094  return true;
3095  }
3096  else if (IsA(expr, CoerceToDomain))
3097  {
3098  CoerceToDomain *cd = (CoerceToDomain *) expr;
3099 
3100  return isAssignmentIndirectionExpr(cd->arg);
3101  }
3102  return false;
3103 }

References FieldStore::arg, CoerceToDomain::arg, IsA, and SubscriptingRef::refexpr.

Referenced by ExecInitSubscriptingRef().