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

Go to the source code of this file.

Data Structures

struct  LastAttnumInfo
 

Typedefs

typedef struct LastAttnumInfo LastAttnumInfo
 

Functions

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

Typedef Documentation

◆ LastAttnumInfo

Function Documentation

◆ ExecBuildAggTrans()

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

Definition at line 3290 of file execExpr.c.

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

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

References ExprEvalStep::agg_plain_pergroup_nullcheck, ExprEvalStep::agg_trans, AggState::aggcontexts, Assert(), ExprEvalStep::d, EEOP_AGG_ORDERED_TRANS_DATUM, EEOP_AGG_ORDERED_TRANS_TUPLE, EEOP_AGG_PLAIN_PERGROUP_NULLCHECK, EEOP_AGG_PLAIN_TRANS_BYREF, EEOP_AGG_PLAIN_TRANS_BYVAL, EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF, EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL, EEOP_AGG_PLAIN_TRANS_STRICT_BYREF, EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL, ExprEvalPushStep(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_strict, AggState::hashcontext, AggStatePerTransData::initValueIsNull, AggStatePerTransData::numInputs, AggStatePerTransData::numSortCols, ExprEvalStep::opcode, 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 3708 of file execExpr.c.

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

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

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_FUNCTION, ExprEvalStep::opcode, palloc0(), pg_proc_aclcheck(), 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 353 of file execExpr.c.

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

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, T_ExprState, TupleDescAttr, and ExprState::type.

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

◆ ExecBuildUpdateProjection()

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

Definition at line 513 of file execExpr.c.

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

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, T_ExprState, TupleDescAttr, and ExprState::type.

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

◆ ExecCheck()

bool ExecCheck ( ExprState state,
ExprContext econtext 
)

Definition at line 853 of file execExpr.c.

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

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

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

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

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

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

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

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

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

◆ ExecInitExprList()

List* ExecInitExprList ( List nodes,
PlanState parent 
)

Definition at line 318 of file execExpr.c.

319 {
320  List *result = NIL;
321  ListCell *lc;
322 
323  foreach(lc, nodes)
324  {
325  Expr *e = lfirst(lc);
326 
327  result = lappend(result, ExecInitExpr(e, parent));
328  }
329 
330  return result;
331 }
List * lappend(List *list, void *datum)
Definition: list.c:336
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 900 of file execExpr.c.

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

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, GroupingFunc::cols, 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_SQLVALUEFUNCTION, 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, ScalarArrayOpExpr::hashfuncid, 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, ScalarArrayOpExpr::negfuncid, FieldStore::newvals, ExprEvalStep::nextvalueexpr, NIL, nodeTag, NOT_EXPR, ExprEvalStep::nulltest_row, NullTest::nulltesttype, WindowAggState::numaggs, WindowAggState::numfuncs, OBJECT_FUNCTION, ObjectIdGetDatum, OidIsValid, MinMaxExpr::op, ExprEvalStep::opcode, RowCompareExpr::opfamilies, OpExpr::opfuncid, ScalarArrayOpExpr::opfuncid, RowCompareExpr::opnos, OR_EXPR, OUTER_VAR, palloc(), palloc0(), ExprEvalStep::param, PARAM_EXEC, PARAM_EXTERN, ParamListInfoData::paramCompile, Param::paramid, Param::paramkind, Param::paramtype, ExprState::parent, pg_proc_aclcheck(), 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, ExprEvalStep::sqlvaluefunction, ExprState::steps, ExprState::steps_len, ExprEvalStep::subplan, T_Aggref, T_ArrayCoerceExpr, T_ArrayExpr, T_BooleanTest, T_BoolExpr, T_CaseExpr, T_CaseTestExpr, T_CoalesceExpr, T_CoerceToDomain, T_CoerceToDomainValue, T_CoerceViaIO, T_Const, T_ConvertRowtypeExpr, T_CurrentOfExpr, T_DistinctExpr, T_FieldSelect, T_FieldStore, T_FuncExpr, T_GroupingFunc, T_MinMaxExpr, T_NextValueExpr, T_NullIfExpr, T_NullTest, T_OpExpr, T_Param, T_RelabelType, T_RowCompareExpr, T_RowExpr, T_ScalarArrayOpExpr, T_SQLValueFunction, T_SubPlan, T_SubscriptingRef, T_Var, T_WindowFunc, T_XmlExpr, TupleDescAttr, TYPECACHE_CMP_PROC, NextValueExpr::typeId, ScalarArrayOpExpr::useOr, NullableDatum::value, values, ExprEvalStep::var, 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 2576 of file execExpr.c.

2577 {
2578  LastAttnumInfo info = {0, 0, 0};
2579 
2580  /*
2581  * Figure out which attributes we're going to need.
2582  */
2583  get_last_attnums_walker(node, &info);
2584 
2585  ExecPushExprSlots(state, &info);
2586 }

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

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

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

Referenced by exec_eval_simple_expr().

◆ ExecInitFunc()

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

Definition at line 2471 of file execExpr.c.

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

Referenced by ExecInitExprRec().

◆ ExecInitQual()

ExprState* ExecInitQual ( List qual,
PlanState parent 
)

Definition at line 209 of file execExpr.c.

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

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(), ExecInitMergeJoin(), ExecInitModifyTable(), ExecInitNamedTuplestoreScan(), ExecInitNestLoop(), ExecInitPartitionInfo(), ExecInitResult(), ExecInitSampleScan(), ExecInitSeqScan(), ExecInitSubqueryScan(), ExecInitTableFuncScan(), ExecInitTidRangeScan(), ExecInitTidScan(), ExecInitValuesScan(), ExecInitWorkTableScan(), and ExecPrepareQual().

◆ ExecInitSubscriptingRef()

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

Definition at line 2863 of file execExpr.c.

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

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

2791 {
2792  PlanState *parent = state->parent;
2793 
2794  /* fill in all but the target */
2795  scratch->opcode = EEOP_WHOLEROW;
2796  scratch->d.wholerow.var = variable;
2797  scratch->d.wholerow.first = true;
2798  scratch->d.wholerow.slow = false;
2799  scratch->d.wholerow.tupdesc = NULL; /* filled at runtime */
2800  scratch->d.wholerow.junkFilter = NULL;
2801 
2802  /*
2803  * If the input tuple came from a subquery, it might contain "resjunk"
2804  * columns (such as GROUP BY or ORDER BY columns), which we don't want to
2805  * keep in the whole-row result. We can get rid of such columns by
2806  * passing the tuple through a JunkFilter --- but to make one, we have to
2807  * lay our hands on the subquery's targetlist. Fortunately, there are not
2808  * very many cases where this can happen, and we can identify all of them
2809  * by examining our parent PlanState. We assume this is not an issue in
2810  * standalone expressions that don't have parent plans. (Whole-row Vars
2811  * can occur in such expressions, but they will always be referencing
2812  * table rows.)
2813  */
2814  if (parent)
2815  {
2816  PlanState *subplan = NULL;
2817 
2818  switch (nodeTag(parent))
2819  {
2820  case T_SubqueryScanState:
2821  subplan = ((SubqueryScanState *) parent)->subplan;
2822  break;
2823  case T_CteScanState:
2824  subplan = ((CteScanState *) parent)->cteplanstate;
2825  break;
2826  default:
2827  break;
2828  }
2829 
2830  if (subplan)
2831  {
2832  bool junk_filter_needed = false;
2833  ListCell *tlist;
2834 
2835  /* Detect whether subplan tlist actually has any junk columns */
2836  foreach(tlist, subplan->plan->targetlist)
2837  {
2838  TargetEntry *tle = (TargetEntry *) lfirst(tlist);
2839 
2840  if (tle->resjunk)
2841  {
2842  junk_filter_needed = true;
2843  break;
2844  }
2845  }
2846 
2847  /* If so, build the junkfilter now */
2848  if (junk_filter_needed)
2849  {
2850  scratch->d.wholerow.junkFilter =
2852  ExecInitExtraTupleSlot(parent->state, NULL,
2853  &TTSOpsVirtual));
2854  }
2855  }
2856  }
2857 }
@ 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
@ T_SubqueryScanState
Definition: nodes.h:122
@ T_CteScanState
Definition: nodes.h:126
struct ExprEvalStep::@48::@51 wholerow
Plan * plan
Definition: execnodes.h:971
EState * state
Definition: execnodes.h:973
List * targetlist
Definition: plannodes.h:141

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

Referenced by ExecInitExprRec().

◆ ExecPrepareCheck()

ExprState* ExecPrepareCheck ( List qual,
EState estate 
)

Definition at line 797 of file execExpr.c.

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

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

Referenced by ExecPartitionCheck().

◆ ExecPrepareExpr()

ExprState* ExecPrepareExpr ( Expr node,
EState estate 
)

Definition at line 746 of file execExpr.c.

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

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

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

◆ ExecPrepareExprList()

List* ExecPrepareExprList ( List nodes,
EState estate 
)

Definition at line 820 of file execExpr.c.

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

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

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

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

2595 {
2596  ExprEvalStep scratch = {0};
2597 
2598  scratch.resvalue = NULL;
2599  scratch.resnull = NULL;
2600 
2601  /* Emit steps as needed */
2602  if (info->last_inner > 0)
2603  {
2604  scratch.opcode = EEOP_INNER_FETCHSOME;
2605  scratch.d.fetch.last_var = info->last_inner;
2606  scratch.d.fetch.fixed = false;
2607  scratch.d.fetch.kind = NULL;
2608  scratch.d.fetch.known_desc = NULL;
2609  if (ExecComputeSlotInfo(state, &scratch))
2610  ExprEvalPushStep(state, &scratch);
2611  }
2612  if (info->last_outer > 0)
2613  {
2614  scratch.opcode = EEOP_OUTER_FETCHSOME;
2615  scratch.d.fetch.last_var = info->last_outer;
2616  scratch.d.fetch.fixed = false;
2617  scratch.d.fetch.kind = NULL;
2618  scratch.d.fetch.known_desc = NULL;
2619  if (ExecComputeSlotInfo(state, &scratch))
2620  ExprEvalPushStep(state, &scratch);
2621  }
2622  if (info->last_scan > 0)
2623  {
2624  scratch.opcode = EEOP_SCAN_FETCHSOME;
2625  scratch.d.fetch.last_var = info->last_scan;
2626  scratch.d.fetch.fixed = false;
2627  scratch.d.fetch.kind = NULL;
2628  scratch.d.fetch.known_desc = NULL;
2629  if (ExecComputeSlotInfo(state, &scratch))
2630  ExprEvalPushStep(state, &scratch);
2631  }
2632 }
AttrNumber last_inner
Definition: execExpr.c:56

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

884 {
885  if (jit_compile_expr(state))
886  return;
887 
889 }
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 2445 of file execExpr.c.

2446 {
2447  if (es->steps_alloc == 0)
2448  {
2449  es->steps_alloc = 16;
2450  es->steps = palloc(sizeof(ExprEvalStep) * es->steps_alloc);
2451  }
2452  else if (es->steps_alloc == es->steps_len)
2453  {
2454  es->steps_alloc *= 2;
2455  es->steps = repalloc(es->steps,
2456  sizeof(ExprEvalStep) * es->steps_alloc);
2457  }
2458 
2459  memcpy(&es->steps[es->steps_len++], s, sizeof(ExprEvalStep));
2460 }
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1182
int steps_alloc
Definition: execnodes.h:106

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

2639 {
2640  if (node == NULL)
2641  return false;
2642  if (IsA(node, Var))
2643  {
2644  Var *variable = (Var *) node;
2645  AttrNumber attnum = variable->varattno;
2646 
2647  switch (variable->varno)
2648  {
2649  case INNER_VAR:
2650  info->last_inner = Max(info->last_inner, attnum);
2651  break;
2652 
2653  case OUTER_VAR:
2654  info->last_outer = Max(info->last_outer, attnum);
2655  break;
2656 
2657  /* INDEX_VAR is handled by default case */
2658 
2659  default:
2660  info->last_scan = Max(info->last_scan, attnum);
2661  break;
2662  }
2663  return false;
2664  }
2665 
2666  /*
2667  * Don't examine the arguments or filters of Aggrefs or WindowFuncs,
2668  * because those do not represent expressions to be evaluated within the
2669  * calling expression's econtext. GroupingFunc arguments are never
2670  * evaluated at all.
2671  */
2672  if (IsA(node, Aggref))
2673  return false;
2674  if (IsA(node, WindowFunc))
2675  return false;
2676  if (IsA(node, GroupingFunc))
2677  return false;
2679  (void *) info);
2680 }
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1904

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

3106 {
3107  if (expr == NULL)
3108  return false; /* just paranoia */
3109  if (IsA(expr, FieldStore))
3110  {
3111  FieldStore *fstore = (FieldStore *) expr;
3112 
3113  if (fstore->arg && IsA(fstore->arg, CaseTestExpr))
3114  return true;
3115  }
3116  else if (IsA(expr, SubscriptingRef))
3117  {
3118  SubscriptingRef *sbsRef = (SubscriptingRef *) expr;
3119 
3120  if (sbsRef->refexpr && IsA(sbsRef->refexpr, CaseTestExpr))
3121  return true;
3122  }
3123  else if (IsA(expr, CoerceToDomain))
3124  {
3125  CoerceToDomain *cd = (CoerceToDomain *) expr;
3126 
3127  return isAssignmentIndirectionExpr(cd->arg);
3128  }
3129  return false;
3130 }

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

Referenced by ExecInitSubscriptingRef().