PostgreSQL Source Code  git master
execExpr.c File Reference
#include "postgres.h"
#include "access/nbtree.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "executor/execExpr.h"
#include "executor/nodeSubplan.h"
#include "funcapi.h"
#include "jit/jit.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/subscripting.h"
#include "optimizer/optimizer.h"
#include "pgstat.h"
#include "utils/acl.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/jsonfuncs.h"
#include "utils/jsonpath.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  ExprSetupInfo
 

Typedefs

typedef struct ExprSetupInfo ExprSetupInfo
 

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 ExecCreateExprSetupSteps (ExprState *state, Node *node)
 
static void ExecPushExprSetupSteps (ExprState *state, ExprSetupInfo *info)
 
static bool expr_setup_walker (Node *node, ExprSetupInfo *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)
 
static void ExecInitJsonExpr (JsonExpr *jsexpr, ExprState *state, Datum *resv, bool *resnull, ExprEvalStep *scratch)
 
static void ExecInitJsonCoercion (ExprState *state, JsonReturning *returning, ErrorSaveContext *escontext, Datum *resv, bool *resnull)
 
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

◆ ExprSetupInfo

typedef struct ExprSetupInfo ExprSetupInfo

Function Documentation

◆ ExecBuildAggTrans()

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

Definition at line 3490 of file execExpr.c.

3492 {
3494  PlanState *parent = &aggstate->ss.ps;
3495  ExprEvalStep scratch = {0};
3496  bool isCombine = DO_AGGSPLIT_COMBINE(aggstate->aggsplit);
3497  ExprSetupInfo deform = {0, 0, 0, NIL};
3498 
3499  state->expr = (Expr *) aggstate;
3500  state->parent = parent;
3501 
3502  scratch.resvalue = &state->resvalue;
3503  scratch.resnull = &state->resnull;
3504 
3505  /*
3506  * First figure out which slots, and how many columns from each, we're
3507  * going to need.
3508  */
3509  for (int transno = 0; transno < aggstate->numtrans; transno++)
3510  {
3511  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3512 
3513  expr_setup_walker((Node *) pertrans->aggref->aggdirectargs,
3514  &deform);
3515  expr_setup_walker((Node *) pertrans->aggref->args,
3516  &deform);
3517  expr_setup_walker((Node *) pertrans->aggref->aggorder,
3518  &deform);
3519  expr_setup_walker((Node *) pertrans->aggref->aggdistinct,
3520  &deform);
3521  expr_setup_walker((Node *) pertrans->aggref->aggfilter,
3522  &deform);
3523  }
3524  ExecPushExprSetupSteps(state, &deform);
3525 
3526  /*
3527  * Emit instructions for each transition value / grouping set combination.
3528  */
3529  for (int transno = 0; transno < aggstate->numtrans; transno++)
3530  {
3531  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3532  FunctionCallInfo trans_fcinfo = pertrans->transfn_fcinfo;
3533  List *adjust_bailout = NIL;
3534  NullableDatum *strictargs = NULL;
3535  bool *strictnulls = NULL;
3536  int argno;
3537  ListCell *bail;
3538 
3539  /*
3540  * If filter present, emit. Do so before evaluating the input, to
3541  * avoid potentially unneeded computations, or even worse, unintended
3542  * side-effects. When combining, all the necessary filtering has
3543  * already been done.
3544  */
3545  if (pertrans->aggref->aggfilter && !isCombine)
3546  {
3547  /* evaluate filter expression */
3548  ExecInitExprRec(pertrans->aggref->aggfilter, state,
3549  &state->resvalue, &state->resnull);
3550  /* and jump out if false */
3551  scratch.opcode = EEOP_JUMP_IF_NOT_TRUE;
3552  scratch.d.jump.jumpdone = -1; /* adjust later */
3553  ExprEvalPushStep(state, &scratch);
3554  adjust_bailout = lappend_int(adjust_bailout,
3555  state->steps_len - 1);
3556  }
3557 
3558  /*
3559  * Evaluate arguments to aggregate/combine function.
3560  */
3561  argno = 0;
3562  if (isCombine)
3563  {
3564  /*
3565  * Combining two aggregate transition values. Instead of directly
3566  * coming from a tuple the input is a, potentially deserialized,
3567  * transition value.
3568  */
3569  TargetEntry *source_tle;
3570 
3571  Assert(pertrans->numSortCols == 0);
3572  Assert(list_length(pertrans->aggref->args) == 1);
3573 
3574  strictargs = trans_fcinfo->args + 1;
3575  source_tle = (TargetEntry *) linitial(pertrans->aggref->args);
3576 
3577  /*
3578  * deserialfn_oid will be set if we must deserialize the input
3579  * state before calling the combine function.
3580  */
3581  if (!OidIsValid(pertrans->deserialfn_oid))
3582  {
3583  /*
3584  * Start from 1, since the 0th arg will be the transition
3585  * value
3586  */
3587  ExecInitExprRec(source_tle->expr, state,
3588  &trans_fcinfo->args[argno + 1].value,
3589  &trans_fcinfo->args[argno + 1].isnull);
3590  }
3591  else
3592  {
3593  FunctionCallInfo ds_fcinfo = pertrans->deserialfn_fcinfo;
3594 
3595  /* evaluate argument */
3596  ExecInitExprRec(source_tle->expr, state,
3597  &ds_fcinfo->args[0].value,
3598  &ds_fcinfo->args[0].isnull);
3599 
3600  /* Dummy second argument for type-safety reasons */
3601  ds_fcinfo->args[1].value = PointerGetDatum(NULL);
3602  ds_fcinfo->args[1].isnull = false;
3603 
3604  /*
3605  * Don't call a strict deserialization function with NULL
3606  * input
3607  */
3608  if (pertrans->deserialfn.fn_strict)
3610  else
3611  scratch.opcode = EEOP_AGG_DESERIALIZE;
3612 
3613  scratch.d.agg_deserialize.fcinfo_data = ds_fcinfo;
3614  scratch.d.agg_deserialize.jumpnull = -1; /* adjust later */
3615  scratch.resvalue = &trans_fcinfo->args[argno + 1].value;
3616  scratch.resnull = &trans_fcinfo->args[argno + 1].isnull;
3617 
3618  ExprEvalPushStep(state, &scratch);
3619  /* don't add an adjustment unless the function is strict */
3620  if (pertrans->deserialfn.fn_strict)
3621  adjust_bailout = lappend_int(adjust_bailout,
3622  state->steps_len - 1);
3623 
3624  /* restore normal settings of scratch fields */
3625  scratch.resvalue = &state->resvalue;
3626  scratch.resnull = &state->resnull;
3627  }
3628  argno++;
3629 
3630  Assert(pertrans->numInputs == argno);
3631  }
3632  else if (!pertrans->aggsortrequired)
3633  {
3634  ListCell *arg;
3635 
3636  /*
3637  * Normal transition function without ORDER BY / DISTINCT or with
3638  * ORDER BY / DISTINCT but the planner has given us pre-sorted
3639  * input.
3640  */
3641  strictargs = trans_fcinfo->args + 1;
3642 
3643  foreach(arg, pertrans->aggref->args)
3644  {
3645  TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3646 
3647  /*
3648  * Don't initialize args for any ORDER BY clause that might
3649  * exist in a presorted aggregate.
3650  */
3651  if (argno == pertrans->numTransInputs)
3652  break;
3653 
3654  /*
3655  * Start from 1, since the 0th arg will be the transition
3656  * value
3657  */
3658  ExecInitExprRec(source_tle->expr, state,
3659  &trans_fcinfo->args[argno + 1].value,
3660  &trans_fcinfo->args[argno + 1].isnull);
3661  argno++;
3662  }
3663  Assert(pertrans->numTransInputs == argno);
3664  }
3665  else if (pertrans->numInputs == 1)
3666  {
3667  /*
3668  * Non-presorted DISTINCT and/or ORDER BY case, with a single
3669  * column sorted on.
3670  */
3671  TargetEntry *source_tle =
3672  (TargetEntry *) linitial(pertrans->aggref->args);
3673 
3674  Assert(list_length(pertrans->aggref->args) == 1);
3675 
3676  ExecInitExprRec(source_tle->expr, state,
3677  &state->resvalue,
3678  &state->resnull);
3679  strictnulls = &state->resnull;
3680  argno++;
3681 
3682  Assert(pertrans->numInputs == argno);
3683  }
3684  else
3685  {
3686  /*
3687  * Non-presorted DISTINCT and/or ORDER BY case, with multiple
3688  * columns sorted on.
3689  */
3690  Datum *values = pertrans->sortslot->tts_values;
3691  bool *nulls = pertrans->sortslot->tts_isnull;
3692  ListCell *arg;
3693 
3694  strictnulls = nulls;
3695 
3696  foreach(arg, pertrans->aggref->args)
3697  {
3698  TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3699 
3700  ExecInitExprRec(source_tle->expr, state,
3701  &values[argno], &nulls[argno]);
3702  argno++;
3703  }
3704  Assert(pertrans->numInputs == argno);
3705  }
3706 
3707  /*
3708  * For a strict transfn, nothing happens when there's a NULL input; we
3709  * just keep the prior transValue. This is true for both plain and
3710  * sorted/distinct aggregates.
3711  */
3712  if (trans_fcinfo->flinfo->fn_strict && pertrans->numTransInputs > 0)
3713  {
3714  if (strictnulls)
3716  else
3718  scratch.d.agg_strict_input_check.nulls = strictnulls;
3719  scratch.d.agg_strict_input_check.args = strictargs;
3720  scratch.d.agg_strict_input_check.jumpnull = -1; /* adjust later */
3721  scratch.d.agg_strict_input_check.nargs = pertrans->numTransInputs;
3722  ExprEvalPushStep(state, &scratch);
3723  adjust_bailout = lappend_int(adjust_bailout,
3724  state->steps_len - 1);
3725  }
3726 
3727  /* Handle DISTINCT aggregates which have pre-sorted input */
3728  if (pertrans->numDistinctCols > 0 && !pertrans->aggsortrequired)
3729  {
3730  if (pertrans->numDistinctCols > 1)
3732  else
3734 
3735  scratch.d.agg_presorted_distinctcheck.pertrans = pertrans;
3736  scratch.d.agg_presorted_distinctcheck.jumpdistinct = -1; /* adjust later */
3737  ExprEvalPushStep(state, &scratch);
3738  adjust_bailout = lappend_int(adjust_bailout,
3739  state->steps_len - 1);
3740  }
3741 
3742  /*
3743  * Call transition function (once for each concurrently evaluated
3744  * grouping set). Do so for both sort and hash based computations, as
3745  * applicable.
3746  */
3747  if (doSort)
3748  {
3749  int processGroupingSets = Max(phase->numsets, 1);
3750  int setoff = 0;
3751 
3752  for (int setno = 0; setno < processGroupingSets; setno++)
3753  {
3754  ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3755  pertrans, transno, setno, setoff, false,
3756  nullcheck);
3757  setoff++;
3758  }
3759  }
3760 
3761  if (doHash)
3762  {
3763  int numHashes = aggstate->num_hashes;
3764  int setoff;
3765 
3766  /* in MIXED mode, there'll be preceding transition values */
3767  if (aggstate->aggstrategy != AGG_HASHED)
3768  setoff = aggstate->maxsets;
3769  else
3770  setoff = 0;
3771 
3772  for (int setno = 0; setno < numHashes; setno++)
3773  {
3774  ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3775  pertrans, transno, setno, setoff, true,
3776  nullcheck);
3777  setoff++;
3778  }
3779  }
3780 
3781  /* adjust early bail out jump target(s) */
3782  foreach(bail, adjust_bailout)
3783  {
3784  ExprEvalStep *as = &state->steps[lfirst_int(bail)];
3785 
3786  if (as->opcode == EEOP_JUMP_IF_NOT_TRUE)
3787  {
3788  Assert(as->d.jump.jumpdone == -1);
3789  as->d.jump.jumpdone = state->steps_len;
3790  }
3791  else if (as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_ARGS ||
3793  {
3794  Assert(as->d.agg_strict_input_check.jumpnull == -1);
3795  as->d.agg_strict_input_check.jumpnull = state->steps_len;
3796  }
3797  else if (as->opcode == EEOP_AGG_STRICT_DESERIALIZE)
3798  {
3799  Assert(as->d.agg_deserialize.jumpnull == -1);
3800  as->d.agg_deserialize.jumpnull = state->steps_len;
3801  }
3802  else if (as->opcode == EEOP_AGG_PRESORTED_DISTINCT_SINGLE ||
3804  {
3805  Assert(as->d.agg_presorted_distinctcheck.jumpdistinct == -1);
3806  as->d.agg_presorted_distinctcheck.jumpdistinct = state->steps_len;
3807  }
3808  else
3809  Assert(false);
3810  }
3811  }
3812 
3813  scratch.resvalue = NULL;
3814  scratch.resnull = NULL;
3815  scratch.opcode = EEOP_DONE;
3816  ExprEvalPushStep(state, &scratch);
3817 
3819 
3820  return state;
3821 }
static Datum values[MAXATTR]
Definition: bootstrap.c:152
#define Max(x, y)
Definition: c.h:998
#define Assert(condition)
Definition: c.h:858
#define OidIsValid(objectId)
Definition: c.h:775
static void ExecPushExprSetupSteps(ExprState *state, ExprSetupInfo *info)
Definition: execExpr.c:2738
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:893
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:3829
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2591
static bool expr_setup_walker(Node *node, ExprSetupInfo *info)
Definition: execExpr.c:2821
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:876
@ EEOP_AGG_STRICT_DESERIALIZE
Definition: execExpr.h:253
@ EEOP_DONE
Definition: execExpr.h:69
@ EEOP_AGG_PRESORTED_DISTINCT_MULTI
Definition: execExpr.h:265
@ EEOP_AGG_STRICT_INPUT_CHECK_NULLS
Definition: execExpr.h:256
@ EEOP_AGG_STRICT_INPUT_CHECK_ARGS
Definition: execExpr.h:255
@ EEOP_AGG_DESERIALIZE
Definition: execExpr.h:254
@ EEOP_JUMP_IF_NOT_TRUE
Definition: execExpr.h:143
@ EEOP_AGG_PRESORTED_DISTINCT_SINGLE
Definition: execExpr.h:264
List * lappend_int(List *list, int datum)
Definition: list.c:357
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:384
@ AGG_HASHED
Definition: nodes.h:355
#define makeNode(_type_)
Definition: nodes.h:155
void * arg
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define lfirst_int(lc)
Definition: pg_list.h:173
#define linitial(l)
Definition: pg_list.h:178
#define bail(...)
Definition: pg_regress.c:168
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
TupleTableSlot * sortslot
Definition: nodeAgg.h:141
Aggref * aggref
Definition: nodeAgg.h:44
FmgrInfo deserialfn
Definition: nodeAgg.h:92
FunctionCallInfo deserialfn_fcinfo
Definition: nodeAgg.h:175
FunctionCallInfo transfn_fcinfo
Definition: nodeAgg.h:170
ScanState ss
Definition: execnodes.h:2463
AggStatePerTrans pertrans
Definition: execnodes.h:2473
AggStrategy aggstrategy
Definition: execnodes.h:2467
int numtrans
Definition: execnodes.h:2466
AggSplit aggsplit
Definition: execnodes.h:2468
int num_hashes
Definition: execnodes.h:2504
int maxsets
Definition: execnodes.h:2493
List * aggdistinct
Definition: primnodes.h:474
List * aggdirectargs
Definition: primnodes.h:465
List * args
Definition: primnodes.h:468
Expr * aggfilter
Definition: primnodes.h:477
List * aggorder
Definition: primnodes.h:471
union ExprEvalStep::@54 d
struct ExprEvalStep::@54::@96 agg_presorted_distinctcheck
intptr_t opcode
Definition: execExpr.h:281
Datum * resvalue
Definition: execExpr.h:284
struct ExprEvalStep::@54::@94 agg_strict_input_check
struct ExprEvalStep::@54::@64 jump
bool * resnull
Definition: execExpr.h:285
struct ExprEvalStep::@54::@93 agg_deserialize
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:54
Definition: nodes.h:129
Datum value
Definition: postgres.h:75
bool isnull
Definition: postgres.h:77
PlanState ps
Definition: execnodes.h:1564
Expr * expr
Definition: primnodes.h:2192
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
Definition: regguts.h:323

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

Referenced by ExecInitAgg(), and hashagg_recompile_expressions().

◆ ExecBuildAggTransCall()

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

Definition at line 3829 of file execExpr.c.

3834 {
3835  ExprContext *aggcontext;
3836  int adjust_jumpnull = -1;
3837 
3838  if (ishash)
3839  aggcontext = aggstate->hashcontext;
3840  else
3841  aggcontext = aggstate->aggcontexts[setno];
3842 
3843  /* add check for NULL pointer? */
3844  if (nullcheck)
3845  {
3847  scratch->d.agg_plain_pergroup_nullcheck.setoff = setoff;
3848  /* adjust later */
3849  scratch->d.agg_plain_pergroup_nullcheck.jumpnull = -1;
3850  ExprEvalPushStep(state, scratch);
3851  adjust_jumpnull = state->steps_len - 1;
3852  }
3853 
3854  /*
3855  * Determine appropriate transition implementation.
3856  *
3857  * For non-ordered aggregates and ORDER BY / DISTINCT aggregates with
3858  * presorted input:
3859  *
3860  * If the initial value for the transition state doesn't exist in the
3861  * pg_aggregate table then we will let the first non-NULL value returned
3862  * from the outer procNode become the initial value. (This is useful for
3863  * aggregates like max() and min().) The noTransValue flag signals that we
3864  * need to do so. If true, generate a
3865  * EEOP_AGG_INIT_STRICT_PLAIN_TRANS{,_BYVAL} step. This step also needs to
3866  * do the work described next:
3867  *
3868  * If the function is strict, but does have an initial value, choose
3869  * EEOP_AGG_STRICT_PLAIN_TRANS{,_BYVAL}, which skips the transition
3870  * function if the transition value has become NULL (because a previous
3871  * transition function returned NULL). This step also needs to do the work
3872  * described next:
3873  *
3874  * Otherwise we call EEOP_AGG_PLAIN_TRANS{,_BYVAL}, which does not have to
3875  * perform either of the above checks.
3876  *
3877  * Having steps with overlapping responsibilities is not nice, but
3878  * aggregations are very performance sensitive, making this worthwhile.
3879  *
3880  * For ordered aggregates:
3881  *
3882  * Only need to choose between the faster path for a single ordered
3883  * column, and the one between multiple columns. Checking strictness etc
3884  * is done when finalizing the aggregate. See
3885  * process_ordered_aggregate_{single, multi} and
3886  * advance_transition_function.
3887  */
3888  if (!pertrans->aggsortrequired)
3889  {
3890  if (pertrans->transtypeByVal)
3891  {
3892  if (fcinfo->flinfo->fn_strict &&
3893  pertrans->initValueIsNull)
3895  else if (fcinfo->flinfo->fn_strict)
3897  else
3899  }
3900  else
3901  {
3902  if (fcinfo->flinfo->fn_strict &&
3903  pertrans->initValueIsNull)
3905  else if (fcinfo->flinfo->fn_strict)
3907  else
3909  }
3910  }
3911  else if (pertrans->numInputs == 1)
3913  else
3915 
3916  scratch->d.agg_trans.pertrans = pertrans;
3917  scratch->d.agg_trans.setno = setno;
3918  scratch->d.agg_trans.setoff = setoff;
3919  scratch->d.agg_trans.transno = transno;
3920  scratch->d.agg_trans.aggcontext = aggcontext;
3921  ExprEvalPushStep(state, scratch);
3922 
3923  /* fix up jumpnull */
3924  if (adjust_jumpnull != -1)
3925  {
3926  ExprEvalStep *as = &state->steps[adjust_jumpnull];
3927 
3929  Assert(as->d.agg_plain_pergroup_nullcheck.jumpnull == -1);
3930  as->d.agg_plain_pergroup_nullcheck.jumpnull = state->steps_len;
3931  }
3932 }
@ EEOP_AGG_PLAIN_PERGROUP_NULLCHECK
Definition: execExpr.h:257
@ EEOP_AGG_PLAIN_TRANS_BYREF
Definition: execExpr.h:263
@ EEOP_AGG_PLAIN_TRANS_BYVAL
Definition: execExpr.h:260
@ EEOP_AGG_ORDERED_TRANS_DATUM
Definition: execExpr.h:266
@ EEOP_AGG_PLAIN_TRANS_STRICT_BYREF
Definition: execExpr.h:262
@ EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL
Definition: execExpr.h:258
@ EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL
Definition: execExpr.h:259
@ EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF
Definition: execExpr.h:261
@ EEOP_AGG_ORDERED_TRANS_TUPLE
Definition: execExpr.h:267
ExprContext * hashcontext
Definition: execnodes.h:2474
ExprContext ** aggcontexts
Definition: execnodes.h:2475
struct ExprEvalStep::@54::@95 agg_plain_pergroup_nullcheck
struct ExprEvalStep::@54::@97 agg_trans

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

Referenced by ExecBuildAggTrans().

◆ ExecBuildGroupingEqual()

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

Definition at line 3946 of file execExpr.c.

3953 {
3955  ExprEvalStep scratch = {0};
3956  int maxatt = -1;
3957  List *adjust_jumps = NIL;
3958  ListCell *lc;
3959 
3960  /*
3961  * When no columns are actually compared, the result's always true. See
3962  * special case in ExecQual().
3963  */
3964  if (numCols == 0)
3965  return NULL;
3966 
3967  state->expr = NULL;
3968  state->flags = EEO_FLAG_IS_QUAL;
3969  state->parent = parent;
3970 
3971  scratch.resvalue = &state->resvalue;
3972  scratch.resnull = &state->resnull;
3973 
3974  /* compute max needed attribute */
3975  for (int natt = 0; natt < numCols; natt++)
3976  {
3977  int attno = keyColIdx[natt];
3978 
3979  if (attno > maxatt)
3980  maxatt = attno;
3981  }
3982  Assert(maxatt >= 0);
3983 
3984  /* push deform steps */
3985  scratch.opcode = EEOP_INNER_FETCHSOME;
3986  scratch.d.fetch.last_var = maxatt;
3987  scratch.d.fetch.fixed = false;
3988  scratch.d.fetch.known_desc = ldesc;
3989  scratch.d.fetch.kind = lops;
3990  if (ExecComputeSlotInfo(state, &scratch))
3991  ExprEvalPushStep(state, &scratch);
3992 
3993  scratch.opcode = EEOP_OUTER_FETCHSOME;
3994  scratch.d.fetch.last_var = maxatt;
3995  scratch.d.fetch.fixed = false;
3996  scratch.d.fetch.known_desc = rdesc;
3997  scratch.d.fetch.kind = rops;
3998  if (ExecComputeSlotInfo(state, &scratch))
3999  ExprEvalPushStep(state, &scratch);
4000 
4001  /*
4002  * Start comparing at the last field (least significant sort key). That's
4003  * the most likely to be different if we are dealing with sorted input.
4004  */
4005  for (int natt = numCols; --natt >= 0;)
4006  {
4007  int attno = keyColIdx[natt];
4008  Form_pg_attribute latt = TupleDescAttr(ldesc, attno - 1);
4009  Form_pg_attribute ratt = TupleDescAttr(rdesc, attno - 1);
4010  Oid foid = eqfunctions[natt];
4011  Oid collid = collations[natt];
4012  FmgrInfo *finfo;
4013  FunctionCallInfo fcinfo;
4014  AclResult aclresult;
4015 
4016  /* Check permission to call function */
4017  aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE);
4018  if (aclresult != ACLCHECK_OK)
4019  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
4020 
4022 
4023  /* Set up the primary fmgr lookup information */
4024  finfo = palloc0(sizeof(FmgrInfo));
4025  fcinfo = palloc0(SizeForFunctionCallInfo(2));
4026  fmgr_info(foid, finfo);
4027  fmgr_info_set_expr(NULL, finfo);
4028  InitFunctionCallInfoData(*fcinfo, finfo, 2,
4029  collid, NULL, NULL);
4030 
4031  /* left arg */
4032  scratch.opcode = EEOP_INNER_VAR;
4033  scratch.d.var.attnum = attno - 1;
4034  scratch.d.var.vartype = latt->atttypid;
4035  scratch.resvalue = &fcinfo->args[0].value;
4036  scratch.resnull = &fcinfo->args[0].isnull;
4037  ExprEvalPushStep(state, &scratch);
4038 
4039  /* right arg */
4040  scratch.opcode = EEOP_OUTER_VAR;
4041  scratch.d.var.attnum = attno - 1;
4042  scratch.d.var.vartype = ratt->atttypid;
4043  scratch.resvalue = &fcinfo->args[1].value;
4044  scratch.resnull = &fcinfo->args[1].isnull;
4045  ExprEvalPushStep(state, &scratch);
4046 
4047  /* evaluate distinctness */
4048  scratch.opcode = EEOP_NOT_DISTINCT;
4049  scratch.d.func.finfo = finfo;
4050  scratch.d.func.fcinfo_data = fcinfo;
4051  scratch.d.func.fn_addr = finfo->fn_addr;
4052  scratch.d.func.nargs = 2;
4053  scratch.resvalue = &state->resvalue;
4054  scratch.resnull = &state->resnull;
4055  ExprEvalPushStep(state, &scratch);
4056 
4057  /* then emit EEOP_QUAL to detect if result is false (or null) */
4058  scratch.opcode = EEOP_QUAL;
4059  scratch.d.qualexpr.jumpdone = -1;
4060  scratch.resvalue = &state->resvalue;
4061  scratch.resnull = &state->resnull;
4062  ExprEvalPushStep(state, &scratch);
4063  adjust_jumps = lappend_int(adjust_jumps,
4064  state->steps_len - 1);
4065  }
4066 
4067  /* adjust jump targets */
4068  foreach(lc, adjust_jumps)
4069  {
4070  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4071 
4072  Assert(as->opcode == EEOP_QUAL);
4073  Assert(as->d.qualexpr.jumpdone == -1);
4074  as->d.qualexpr.jumpdone = state->steps_len;
4075  }
4076 
4077  scratch.resvalue = NULL;
4078  scratch.resnull = NULL;
4079  scratch.opcode = EEOP_DONE;
4080  ExprEvalPushStep(state, &scratch);
4081 
4083 
4084  return state;
4085 }
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2702
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3890
Oid collid
static bool ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op)
Definition: execExpr.c:2885
@ EEOP_NOT_DISTINCT
Definition: execExpr.h:174
@ EEOP_INNER_VAR
Definition: execExpr.h:77
@ EEOP_QUAL
Definition: execExpr.h:135
@ EEOP_INNER_FETCHSOME
Definition: execExpr.h:72
@ EEOP_OUTER_FETCHSOME
Definition: execExpr.h:73
@ EEOP_OUTER_VAR
Definition: execExpr.h:78
#define EEO_FLAG_IS_QUAL
Definition: execnodes.h:76
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
#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:1608
void * palloc0(Size size)
Definition: mcxt.c:1346
Oid GetUserId(void)
Definition: miscinit.c:514
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:213
@ OBJECT_FUNCTION
Definition: parsenodes.h:2280
#define ACL_EXECUTE
Definition: parsenodes.h:83
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
unsigned int Oid
Definition: postgres_ext.h:31
struct ExprEvalStep::@54::@56 var
struct ExprEvalStep::@54::@61 func
struct ExprEvalStep::@54::@63 qualexpr
struct ExprEvalStep::@54::@55 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, collid, ExprEvalStep::d, EEO_FLAG_IS_QUAL, EEOP_DONE, EEOP_INNER_FETCHSOME, EEOP_INNER_VAR, EEOP_NOT_DISTINCT, EEOP_OUTER_FETCHSOME, EEOP_OUTER_VAR, EEOP_QUAL, ExecComputeSlotInfo(), ExecReadyExpr(), ExprEvalPushStep(), ExprEvalStep::fetch, fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_addr, ExprEvalStep::func, get_func_name(), GetUserId(), InitFunctionCallInfoData, InvokeFunctionExecuteHook, NullableDatum::isnull, lappend_int(), lfirst_int, makeNode, NIL, object_aclcheck(), OBJECT_FUNCTION, ExprEvalStep::opcode, palloc0(), ExprEvalStep::qualexpr, ExprEvalStep::resnull, ExprEvalStep::resvalue, SizeForFunctionCallInfo, TupleDescAttr, NullableDatum::value, and ExprEvalStep::var.

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

◆ ExecBuildParamSetEqual()

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

Definition at line 4103 of file execExpr.c.

4110 {
4112  ExprEvalStep scratch = {0};
4113  int maxatt = list_length(param_exprs);
4114  List *adjust_jumps = NIL;
4115  ListCell *lc;
4116 
4117  state->expr = NULL;
4118  state->flags = EEO_FLAG_IS_QUAL;
4119  state->parent = parent;
4120 
4121  scratch.resvalue = &state->resvalue;
4122  scratch.resnull = &state->resnull;
4123 
4124  /* push deform steps */
4125  scratch.opcode = EEOP_INNER_FETCHSOME;
4126  scratch.d.fetch.last_var = maxatt;
4127  scratch.d.fetch.fixed = false;
4128  scratch.d.fetch.known_desc = desc;
4129  scratch.d.fetch.kind = lops;
4130  if (ExecComputeSlotInfo(state, &scratch))
4131  ExprEvalPushStep(state, &scratch);
4132 
4133  scratch.opcode = EEOP_OUTER_FETCHSOME;
4134  scratch.d.fetch.last_var = maxatt;
4135  scratch.d.fetch.fixed = false;
4136  scratch.d.fetch.known_desc = desc;
4137  scratch.d.fetch.kind = rops;
4138  if (ExecComputeSlotInfo(state, &scratch))
4139  ExprEvalPushStep(state, &scratch);
4140 
4141  for (int attno = 0; attno < maxatt; attno++)
4142  {
4143  Form_pg_attribute att = TupleDescAttr(desc, attno);
4144  Oid foid = eqfunctions[attno];
4145  Oid collid = collations[attno];
4146  FmgrInfo *finfo;
4147  FunctionCallInfo fcinfo;
4148  AclResult aclresult;
4149 
4150  /* Check permission to call function */
4151  aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE);
4152  if (aclresult != ACLCHECK_OK)
4153  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
4154 
4156 
4157  /* Set up the primary fmgr lookup information */
4158  finfo = palloc0(sizeof(FmgrInfo));
4159  fcinfo = palloc0(SizeForFunctionCallInfo(2));
4160  fmgr_info(foid, finfo);
4161  fmgr_info_set_expr(NULL, finfo);
4162  InitFunctionCallInfoData(*fcinfo, finfo, 2,
4163  collid, NULL, NULL);
4164 
4165  /* left arg */
4166  scratch.opcode = EEOP_INNER_VAR;
4167  scratch.d.var.attnum = attno;
4168  scratch.d.var.vartype = att->atttypid;
4169  scratch.resvalue = &fcinfo->args[0].value;
4170  scratch.resnull = &fcinfo->args[0].isnull;
4171  ExprEvalPushStep(state, &scratch);
4172 
4173  /* right arg */
4174  scratch.opcode = EEOP_OUTER_VAR;
4175  scratch.d.var.attnum = attno;
4176  scratch.d.var.vartype = att->atttypid;
4177  scratch.resvalue = &fcinfo->args[1].value;
4178  scratch.resnull = &fcinfo->args[1].isnull;
4179  ExprEvalPushStep(state, &scratch);
4180 
4181  /* evaluate distinctness */
4182  scratch.opcode = EEOP_NOT_DISTINCT;
4183  scratch.d.func.finfo = finfo;
4184  scratch.d.func.fcinfo_data = fcinfo;
4185  scratch.d.func.fn_addr = finfo->fn_addr;
4186  scratch.d.func.nargs = 2;
4187  scratch.resvalue = &state->resvalue;
4188  scratch.resnull = &state->resnull;
4189  ExprEvalPushStep(state, &scratch);
4190 
4191  /* then emit EEOP_QUAL to detect if result is false (or null) */
4192  scratch.opcode = EEOP_QUAL;
4193  scratch.d.qualexpr.jumpdone = -1;
4194  scratch.resvalue = &state->resvalue;
4195  scratch.resnull = &state->resnull;
4196  ExprEvalPushStep(state, &scratch);
4197  adjust_jumps = lappend_int(adjust_jumps,
4198  state->steps_len - 1);
4199  }
4200 
4201  /* adjust jump targets */
4202  foreach(lc, adjust_jumps)
4203  {
4204  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4205 
4206  Assert(as->opcode == EEOP_QUAL);
4207  Assert(as->d.qualexpr.jumpdone == -1);
4208  as->d.qualexpr.jumpdone = state->steps_len;
4209  }
4210 
4211  scratch.resvalue = NULL;
4212  scratch.resnull = NULL;
4213  scratch.opcode = EEOP_DONE;
4214  ExprEvalPushStep(state, &scratch);
4215 
4217 
4218  return state;
4219 }

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

Referenced by ExecInitMemoize().

◆ ExecBuildProjectionInfo()

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

Definition at line 361 of file execExpr.c.

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

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

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

◆ ExecBuildUpdateProjection()

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

Definition at line 521 of file execExpr.c.

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

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(), ExecPushExprSetupSteps(), ExecReadyExpr(), TargetEntry::expr, expr_setup_walker(), ExprEvalPushStep(), exprType(), forboth, format_type_be(), ExprSetupInfo::last_outer, ExprSetupInfo::last_scan, lfirst_int, lfirst_node, list_length(), makeNode, TupleDescData::natts, NIL, ExprEvalStep::opcode, ProjectionInfo::pi_exprContext, ProjectionInfo::pi_state, ExprEvalStep::resnull, ExprEvalStep::resvalue, TupleDescAttr, and ExprState::type.

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

◆ ExecCheck()

bool ExecCheck ( ExprState state,
ExprContext econtext 
)

Definition at line 846 of file execExpr.c.

847 {
848  Datum ret;
849  bool isnull;
850 
851  /* short-circuit (here and in ExecInitCheck) for empty restriction list */
852  if (state == NULL)
853  return true;
854 
855  /* verify that expression was not compiled using ExecInitQual */
856  Assert(!(state->flags & EEO_FLAG_IS_QUAL));
857 
858  ret = ExecEvalExprSwitchContext(state, econtext, &isnull);
859 
860  if (isnull)
861  return true;
862 
863  return DatumGetBool(ret);
864 }
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:348
static bool DatumGetBool(Datum X)
Definition: postgres.h:90

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

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

◆ ExecComputeSlotInfo()

static bool ExecComputeSlotInfo ( ExprState state,
ExprEvalStep op 
)
static

Definition at line 2885 of file execExpr.c.

2886 {
2887  PlanState *parent = state->parent;
2888  TupleDesc desc = NULL;
2889  const TupleTableSlotOps *tts_ops = NULL;
2890  bool isfixed = false;
2891  ExprEvalOp opcode = op->opcode;
2892 
2893  Assert(opcode == EEOP_INNER_FETCHSOME ||
2894  opcode == EEOP_OUTER_FETCHSOME ||
2895  opcode == EEOP_SCAN_FETCHSOME);
2896 
2897  if (op->d.fetch.known_desc != NULL)
2898  {
2899  desc = op->d.fetch.known_desc;
2900  tts_ops = op->d.fetch.kind;
2901  isfixed = op->d.fetch.kind != NULL;
2902  }
2903  else if (!parent)
2904  {
2905  isfixed = false;
2906  }
2907  else if (opcode == EEOP_INNER_FETCHSOME)
2908  {
2909  PlanState *is = innerPlanState(parent);
2910 
2911  if (parent->inneropsset && !parent->inneropsfixed)
2912  {
2913  isfixed = false;
2914  }
2915  else if (parent->inneropsset && parent->innerops)
2916  {
2917  isfixed = true;
2918  tts_ops = parent->innerops;
2919  desc = ExecGetResultType(is);
2920  }
2921  else if (is)
2922  {
2923  tts_ops = ExecGetResultSlotOps(is, &isfixed);
2924  desc = ExecGetResultType(is);
2925  }
2926  }
2927  else if (opcode == EEOP_OUTER_FETCHSOME)
2928  {
2929  PlanState *os = outerPlanState(parent);
2930 
2931  if (parent->outeropsset && !parent->outeropsfixed)
2932  {
2933  isfixed = false;
2934  }
2935  else if (parent->outeropsset && parent->outerops)
2936  {
2937  isfixed = true;
2938  tts_ops = parent->outerops;
2939  desc = ExecGetResultType(os);
2940  }
2941  else if (os)
2942  {
2943  tts_ops = ExecGetResultSlotOps(os, &isfixed);
2944  desc = ExecGetResultType(os);
2945  }
2946  }
2947  else if (opcode == EEOP_SCAN_FETCHSOME)
2948  {
2949  desc = parent->scandesc;
2950 
2951  if (parent->scanops)
2952  tts_ops = parent->scanops;
2953 
2954  if (parent->scanopsset)
2955  isfixed = parent->scanopsfixed;
2956  }
2957 
2958  if (isfixed && desc != NULL && tts_ops != NULL)
2959  {
2960  op->d.fetch.fixed = true;
2961  op->d.fetch.kind = tts_ops;
2962  op->d.fetch.known_desc = desc;
2963  }
2964  else
2965  {
2966  op->d.fetch.fixed = false;
2967  op->d.fetch.kind = NULL;
2968  op->d.fetch.known_desc = NULL;
2969  }
2970 
2971  /* if the slot is known to always virtual we never need to deform */
2972  if (op->d.fetch.fixed && op->d.fetch.kind == &TTSOpsVirtual)
2973  return false;
2974 
2975  return true;
2976 }
ExprEvalOp
Definition: execExpr.h:67
@ EEOP_SCAN_FETCHSOME
Definition: execExpr.h:74
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:84
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:493
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:502
#define outerPlanState(node)
Definition: execnodes.h:1213
#define innerPlanState(node)
Definition: execnodes.h:1212
bool inneropsset
Definition: execnodes.h:1201
bool outeropsset
Definition: execnodes.h:1200
const TupleTableSlotOps * outerops
Definition: execnodes.h:1192
const TupleTableSlotOps * innerops
Definition: execnodes.h:1193
const TupleTableSlotOps * scanops
Definition: execnodes.h:1191
bool outeropsfixed
Definition: execnodes.h:1196
bool scanopsset
Definition: execnodes.h:1199
TupleDesc scandesc
Definition: execnodes.h:1166
bool scanopsfixed
Definition: execnodes.h:1195
bool inneropsfixed
Definition: execnodes.h:1197

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

◆ ExecCreateExprSetupSteps()

static void ExecCreateExprSetupSteps ( ExprState state,
Node node 
)
static

Definition at line 2722 of file execExpr.c.

2723 {
2724  ExprSetupInfo info = {0, 0, 0, NIL};
2725 
2726  /* Prescan to find out what we need. */
2727  expr_setup_walker(node, &info);
2728 
2729  /* And generate those steps. */
2730  ExecPushExprSetupSteps(state, &info);
2731 }

References ExecPushExprSetupSteps(), expr_setup_walker(), and NIL.

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

◆ ExecInitCheck()

ExprState* ExecInitCheck ( List qual,
PlanState parent 
)

Definition at line 306 of file execExpr.c.

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

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

3337 {
3338  DomainConstraintRef *constraint_ref;
3339  Datum *domainval = NULL;
3340  bool *domainnull = NULL;
3341  ListCell *l;
3342 
3343  scratch->d.domaincheck.resulttype = ctest->resulttype;
3344  /* we'll allocate workspace only if needed */
3345  scratch->d.domaincheck.checkvalue = NULL;
3346  scratch->d.domaincheck.checknull = NULL;
3347  scratch->d.domaincheck.escontext = state->escontext;
3348 
3349  /*
3350  * Evaluate argument - it's fine to directly store it into resv/resnull,
3351  * if there's constraint failures there'll be errors, otherwise it's what
3352  * needs to be returned.
3353  */
3354  ExecInitExprRec(ctest->arg, state, resv, resnull);
3355 
3356  /*
3357  * Note: if the argument is of varlena type, it could be a R/W expanded
3358  * object. We want to return the R/W pointer as the final result, but we
3359  * have to pass a R/O pointer as the value to be tested by any functions
3360  * in check expressions. We don't bother to emit a MAKE_READONLY step
3361  * unless there's actually at least one check expression, though. Until
3362  * we've tested that, domainval/domainnull are NULL.
3363  */
3364 
3365  /*
3366  * Collect the constraints associated with the domain.
3367  *
3368  * Note: before PG v10 we'd recheck the set of constraints during each
3369  * evaluation of the expression. Now we bake them into the ExprState
3370  * during executor initialization. That means we don't need typcache.c to
3371  * provide compiled exprs.
3372  */
3373  constraint_ref = (DomainConstraintRef *)
3374  palloc(sizeof(DomainConstraintRef));
3376  constraint_ref,
3378  false);
3379 
3380  /*
3381  * Compile code to check each domain constraint. NOTNULL constraints can
3382  * just be applied on the resv/resnull value, but for CHECK constraints we
3383  * need more pushups.
3384  */
3385  foreach(l, constraint_ref->constraints)
3386  {
3388  Datum *save_innermost_domainval;
3389  bool *save_innermost_domainnull;
3390 
3391  scratch->d.domaincheck.constraintname = con->name;
3392 
3393  switch (con->constrainttype)
3394  {
3396  scratch->opcode = EEOP_DOMAIN_NOTNULL;
3397  ExprEvalPushStep(state, scratch);
3398  break;
3399  case DOM_CONSTRAINT_CHECK:
3400  /* Allocate workspace for CHECK output if we didn't yet */
3401  if (scratch->d.domaincheck.checkvalue == NULL)
3402  {
3403  scratch->d.domaincheck.checkvalue =
3404  (Datum *) palloc(sizeof(Datum));
3405  scratch->d.domaincheck.checknull =
3406  (bool *) palloc(sizeof(bool));
3407  }
3408 
3409  /*
3410  * If first time through, determine where CoerceToDomainValue
3411  * nodes should read from.
3412  */
3413  if (domainval == NULL)
3414  {
3415  /*
3416  * Since value might be read multiple times, force to R/O
3417  * - but only if it could be an expanded datum.
3418  */
3419  if (get_typlen(ctest->resulttype) == -1)
3420  {
3421  ExprEvalStep scratch2 = {0};
3422 
3423  /* Yes, so make output workspace for MAKE_READONLY */
3424  domainval = (Datum *) palloc(sizeof(Datum));
3425  domainnull = (bool *) palloc(sizeof(bool));
3426 
3427  /* Emit MAKE_READONLY */
3428  scratch2.opcode = EEOP_MAKE_READONLY;
3429  scratch2.resvalue = domainval;
3430  scratch2.resnull = domainnull;
3431  scratch2.d.make_readonly.value = resv;
3432  scratch2.d.make_readonly.isnull = resnull;
3433  ExprEvalPushStep(state, &scratch2);
3434  }
3435  else
3436  {
3437  /* No, so it's fine to read from resv/resnull */
3438  domainval = resv;
3439  domainnull = resnull;
3440  }
3441  }
3442 
3443  /*
3444  * Set up value to be returned by CoerceToDomainValue nodes.
3445  * We must save and restore innermost_domainval/null fields,
3446  * in case this node is itself within a check expression for
3447  * another domain.
3448  */
3449  save_innermost_domainval = state->innermost_domainval;
3450  save_innermost_domainnull = state->innermost_domainnull;
3451  state->innermost_domainval = domainval;
3452  state->innermost_domainnull = domainnull;
3453 
3454  /* evaluate check expression value */
3456  scratch->d.domaincheck.checkvalue,
3457  scratch->d.domaincheck.checknull);
3458 
3459  state->innermost_domainval = save_innermost_domainval;
3460  state->innermost_domainnull = save_innermost_domainnull;
3461 
3462  /* now test result */
3463  scratch->opcode = EEOP_DOMAIN_CHECK;
3464  ExprEvalPushStep(state, scratch);
3465 
3466  break;
3467  default:
3468  elog(ERROR, "unrecognized constraint type: %d",
3469  (int) con->constrainttype);
3470  break;
3471  }
3472  }
3473 }
@ EEOP_DOMAIN_CHECK
Definition: execExpr.h:234
@ EEOP_DOMAIN_NOTNULL
Definition: execExpr.h:231
@ EEOP_MAKE_READONLY
Definition: execExpr.h:168
@ DOM_CONSTRAINT_CHECK
Definition: execnodes.h:1001
@ DOM_CONSTRAINT_NOTNULL
Definition: execnodes.h:1000
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void * palloc(Size size)
Definition: mcxt.c:1316
DomainConstraintType constrainttype
Definition: execnodes.h:1007
struct ExprEvalStep::@54::@69 make_readonly
struct ExprEvalStep::@54::@83 domaincheck
void InitDomainConstraintRef(Oid type_id, DomainConstraintRef *ref, MemoryContext refctx, bool need_exprstate)
Definition: typcache.c:1313

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

135 {
136  ExprState *state;
137  ExprEvalStep scratch = {0};
138 
139  /* Special case: NULL expression produces a NULL ExprState pointer */
140  if (node == NULL)
141  return NULL;
142 
143  /* Initialize ExprState with empty step list */
145  state->expr = node;
146  state->parent = parent;
147  state->ext_params = NULL;
148 
149  /* Insert setup steps as needed */
151 
152  /* Compile the expression proper */
153  ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
154 
155  /* Finally, append a DONE step */
156  scratch.opcode = EEOP_DONE;
157  ExprEvalPushStep(state, &scratch);
158 
160 
161  return state;
162 }

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

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

◆ ExecInitExprList()

List* ExecInitExprList ( List nodes,
PlanState parent 
)

Definition at line 326 of file execExpr.c.

327 {
328  List *result = NIL;
329  ListCell *lc;
330 
331  foreach(lc, nodes)
332  {
333  Expr *e = lfirst(lc);
334 
335  result = lappend(result, ExecInitExpr(e, parent));
336  }
337 
338  return result;
339 }
List * lappend(List *list, void *datum)
Definition: list.c:339
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 893 of file execExpr.c.

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

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, WindowFuncExprState::aggfilter, WindowFunc::aggfilter, ExprEvalStep::aggref, AggState::aggs, AND_EXPR, arg, FieldSelect::arg, FieldStore::arg, RelabelType::arg, CoerceViaIO::arg, ArrayCoerceExpr::arg, CaseExpr::arg, NullTest::arg, BooleanTest::arg, JsonConstructorExprState::arg_nulls, JsonConstructorExprState::arg_type_cache, JsonConstructorExprState::arg_types, JsonConstructorExprState::arg_values, generate_unaccent_rules::args, FunctionCallInfoBaseData::args, WindowFuncExprState::args, WindowFunc::args, FuncExpr::args, OpExpr::args, ScalarArrayOpExpr::args, BoolExpr::args, CaseExpr::args, RowExpr::args, CoalesceExpr::args, MinMaxExpr::args, XmlExpr::args, JsonConstructorExpr::args, ExprEvalStep::arraycoerce, ExprEvalStep::arrayexpr, Assert, BlessTupleDesc(), ExprEvalStep::boolexpr, BoolExpr::boolop, BooleanTest::booltesttype, BTORDER_PROC, ExprEvalRowtypeCache::cacheptr, ExprEvalStep::casetest, castNode, JsonConstructorExprState::category, check_stack_depth(), CMD_MERGE, TypeCacheEntry::cmp_proc, JsonConstructorExpr::coercion, JsonConstructorExprState::constructor, ExprEvalStep::constval, FunctionCallInfoBaseData::context, 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_IOCOERCE_SAFE, EEOP_IS_JSON, EEOP_JSON_CONSTRUCTOR, EEOP_JUMP, EEOP_JUMP_IF_NOT_NULL, EEOP_JUMP_IF_NOT_TRUE, EEOP_MAKE_READONLY, EEOP_MERGE_SUPPORT_FUNC, 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::elements, ArrayCoerceExpr::elemexpr, elog, ereport, errcode(), errmsg(), ERROR, ExecInitCoerceToDomain(), ExecInitExpr(), ExecInitExprList(), ExecInitFunc(), ExecInitJsonExpr(), ExecInitSubPlan(), ExecInitSubscriptingRef(), ExecInitWholeRowVar(), ExecReadyExpr(), ExecTypeFromExprList(), ExecTypeSetColNames(), ExprState::expr, JsonIsPredicate::expr, ExprEvalPushStep(), exprType(), ExprState::ext_params, FieldSelect::fieldnum, ExprEvalStep::fieldselect, ExprEvalStep::fieldstore, fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_addr, forboth, forfive, JsonReturning::format, JsonFormat::format_type, format_type_be(), JsonValueExpr::formatted_expr, JsonExpr::formatted_expr, JsonConstructorExpr::func, FuncExpr::funcid, WindowAggState::funcs, get_element_type(), get_func_name(), get_op_opfamily_properties(), get_opfamily_proc(), get_typlen(), get_typlenbyvalalign(), getTypeInputInfo(), getTypeOutputInfo(), GetUserId(), ExprEvalStep::grouping_func, Agg::groupingSets, ExprEvalStep::hashedscalararrayop, i, InitFunctionCallInfoData, INNER_VAR, ExprState::innermost_casenull, ExprState::innermost_caseval, Int32GetDatum(), InvalidAttrNumber, InvalidOid, InvokeFunctionExecuteHook, ExprEvalStep::iocoerce, IS_FALSE, ExprEvalStep::is_json, IS_NOT_FALSE, IS_NOT_NULL, IS_NOT_TRUE, IS_NOT_UNKNOWN, IS_NULL, IS_TRUE, IS_UNKNOWN, IsA, NullableDatum::isnull, JS_FORMAT_JSONB, JSCTOR_JSON_PARSE, JSCTOR_JSON_SCALAR, JSCTOR_JSON_SERIALIZE, json_categorize_type(), ExprEvalStep::json_constructor, JSON_TABLE_OP, 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, MULTIEXPR_SUBLINK, XmlExpr::named_args, JsonConstructorExprState::nargs, TupleDescData::natts, FieldStore::newvals, ExprEvalStep::nextvalueexpr, NIL, nodeTag, NOT_EXPR, ExprEvalStep::nulltest_row, NullTest::nulltesttype, WindowAggState::numaggs, WindowAggState::numfuncs, object_aclcheck(), OBJECT_FUNCTION, ObjectIdGetDatum(), OidIsValid, MinMaxExpr::op, JsonExpr::op, ExprEvalStep::opcode, OR_EXPR, OUTER_VAR, JsonConstructorExprState::outfuncid, palloc(), palloc0(), ExprEvalStep::param, PARAM_EXEC, PARAM_EXTERN, ParamListInfoData::paramCompile, Param::paramid, Param::paramkind, Param::paramtype, ExprState::parent, RowCompareExpr::rargs, RowCompareExpr::rctype, ReleaseTupleDesc, ExprEvalStep::resnull, ExprState::resnull, CoerceViaIO::resulttype, ArrayCoerceExpr::resulttype, ExprEvalStep::resvalue, ExprState::resvalue, JsonConstructorExpr::returning, ExprEvalStep::row, ExprEvalStep::rowcompare_final, ExprEvalStep::rowcompare_step, ExprEvalStep::scalararrayop, NextValueExpr::seqid, SizeForFunctionCallInfo, ExprEvalStep::sqlvaluefunction, ExprState::steps, ExprState::steps_len, SubPlan::subLinkType, ExprEvalStep::subplan, TupleDescAttr, JsonConstructorExpr::type, TYPECACHE_CMP_PROC, NextValueExpr::typeId, JsonConstructorExpr::unique, ScalarArrayOpExpr::useOr, NullableDatum::value, values, ExprEvalStep::var, WindowFuncExprState::wfunc, ExprEvalStep::window_func, and ExprEvalStep::xmlexpr.

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

◆ ExecInitExprWithParams()

ExprState* ExecInitExprWithParams ( Expr node,
ParamListInfo  ext_params 
)

Definition at line 171 of file execExpr.c.

172 {
173  ExprState *state;
174  ExprEvalStep scratch = {0};
175 
176  /* Special case: NULL expression produces a NULL ExprState pointer */
177  if (node == NULL)
178  return NULL;
179 
180  /* Initialize ExprState with empty step list */
182  state->expr = node;
183  state->parent = NULL;
184  state->ext_params = ext_params;
185 
186  /* Insert setup steps as needed */
188 
189  /* Compile the expression proper */
190  ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
191 
192  /* Finally, append a DONE step */
193  scratch.opcode = EEOP_DONE;
194  ExprEvalPushStep(state, &scratch);
195 
197 
198  return state;
199 }

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

Referenced by exec_eval_simple_expr(), and InitPartitionPruneContext().

◆ ExecInitFunc()

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

Definition at line 2617 of file execExpr.c.

2619 {
2620  int nargs = list_length(args);
2621  AclResult aclresult;
2622  FmgrInfo *flinfo;
2623  FunctionCallInfo fcinfo;
2624  int argno;
2625  ListCell *lc;
2626 
2627  /* Check permission to call function */
2628  aclresult = object_aclcheck(ProcedureRelationId, funcid, GetUserId(), ACL_EXECUTE);
2629  if (aclresult != ACLCHECK_OK)
2630  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(funcid));
2631  InvokeFunctionExecuteHook(funcid);
2632 
2633  /*
2634  * Safety check on nargs. Under normal circumstances this should never
2635  * fail, as parser should check sooner. But possibly it might fail if
2636  * server has been compiled with FUNC_MAX_ARGS smaller than some functions
2637  * declared in pg_proc?
2638  */
2639  if (nargs > FUNC_MAX_ARGS)
2640  ereport(ERROR,
2641  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2642  errmsg_plural("cannot pass more than %d argument to a function",
2643  "cannot pass more than %d arguments to a function",
2644  FUNC_MAX_ARGS,
2645  FUNC_MAX_ARGS)));
2646 
2647  /* Allocate function lookup data and parameter workspace for this call */
2648  scratch->d.func.finfo = palloc0(sizeof(FmgrInfo));
2649  scratch->d.func.fcinfo_data = palloc0(SizeForFunctionCallInfo(nargs));
2650  flinfo = scratch->d.func.finfo;
2651  fcinfo = scratch->d.func.fcinfo_data;
2652 
2653  /* Set up the primary fmgr lookup information */
2654  fmgr_info(funcid, flinfo);
2655  fmgr_info_set_expr((Node *) node, flinfo);
2656 
2657  /* Initialize function call parameter structure too */
2658  InitFunctionCallInfoData(*fcinfo, flinfo,
2659  nargs, inputcollid, NULL, NULL);
2660 
2661  /* Keep extra copies of this info to save an indirection at runtime */
2662  scratch->d.func.fn_addr = flinfo->fn_addr;
2663  scratch->d.func.nargs = nargs;
2664 
2665  /* We only support non-set functions here */
2666  if (flinfo->fn_retset)
2667  ereport(ERROR,
2668  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2669  errmsg("set-valued function called in context that cannot accept a set"),
2670  state->parent ?
2671  executor_errposition(state->parent->state,
2672  exprLocation((Node *) node)) : 0));
2673 
2674  /* Build code to evaluate arguments directly into the fcinfo struct */
2675  argno = 0;
2676  foreach(lc, args)
2677  {
2678  Expr *arg = (Expr *) lfirst(lc);
2679 
2680  if (IsA(arg, Const))
2681  {
2682  /*
2683  * Don't evaluate const arguments every round; especially
2684  * interesting for constants in comparisons.
2685  */
2686  Const *con = (Const *) arg;
2687 
2688  fcinfo->args[argno].value = con->constvalue;
2689  fcinfo->args[argno].isnull = con->constisnull;
2690  }
2691  else
2692  {
2694  &fcinfo->args[argno].value,
2695  &fcinfo->args[argno].isnull);
2696  }
2697  argno++;
2698  }
2699 
2700  /* Insert appropriate opcode depending on strictness and stats level */
2701  if (pgstat_track_functions <= flinfo->fn_stats)
2702  {
2703  if (flinfo->fn_strict && nargs > 0)
2704  scratch->opcode = EEOP_FUNCEXPR_STRICT;
2705  else
2706  scratch->opcode = EEOP_FUNCEXPR;
2707  }
2708  else
2709  {
2710  if (flinfo->fn_strict && nargs > 0)
2712  else
2713  scratch->opcode = EEOP_FUNCEXPR_FUSAGE;
2714  }
2715 }
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1180
@ EEOP_FUNCEXPR_STRICT_FUSAGE
Definition: execExpr.h:114
@ EEOP_FUNCEXPR_STRICT
Definition: execExpr.h:112
@ EEOP_FUNCEXPR
Definition: execExpr.h:111
@ EEOP_FUNCEXPR_FUSAGE
Definition: execExpr.h:113
int executor_errposition(EState *estate, int location)
Definition: execUtils.c:870
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1386
#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, ExprEvalStep::d, EEOP_FUNCEXPR, EEOP_FUNCEXPR_FUSAGE, EEOP_FUNCEXPR_STRICT, EEOP_FUNCEXPR_STRICT_FUSAGE, ereport, errcode(), errmsg(), errmsg_plural(), ERROR, ExecInitExprRec(), executor_errposition(), exprLocation(), fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_addr, FmgrInfo::fn_retset, FmgrInfo::fn_strict, ExprEvalStep::func, FUNC_MAX_ARGS, get_func_name(), GetUserId(), InitFunctionCallInfoData, InvokeFunctionExecuteHook, IsA, NullableDatum::isnull, lfirst, list_length(), object_aclcheck(), OBJECT_FUNCTION, ExprEvalStep::opcode, palloc0(), SizeForFunctionCallInfo, and NullableDatum::value.

Referenced by ExecInitExprRec().

◆ ExecInitJsonCoercion()

static void ExecInitJsonCoercion ( ExprState state,
JsonReturning returning,
ErrorSaveContext escontext,
Datum resv,
bool resnull 
)
static

Definition at line 4489 of file execExpr.c.

4492 {
4493  ExprEvalStep scratch = {0};
4494 
4495  /* For json_populate_type() */
4496  scratch.opcode = EEOP_JSONEXPR_COERCION;
4497  scratch.resvalue = resv;
4498  scratch.resnull = resnull;
4499  scratch.d.jsonexpr_coercion.targettype = returning->typid;
4500  scratch.d.jsonexpr_coercion.targettypmod = returning->typmod;
4501  scratch.d.jsonexpr_coercion.json_populate_type_cache = NULL;
4502  scratch.d.jsonexpr_coercion.escontext = escontext;
4503  ExprEvalPushStep(state, &scratch);
4504 }
@ EEOP_JSONEXPR_COERCION
Definition: execExpr.h:244
struct ExprEvalStep::@54::@100 jsonexpr_coercion

References ExprEvalStep::d, EEOP_JSONEXPR_COERCION, ExprEvalPushStep(), ExprEvalStep::jsonexpr_coercion, ExprEvalStep::opcode, ExprEvalStep::resnull, ExprEvalStep::resvalue, JsonReturning::typid, and JsonReturning::typmod.

Referenced by ExecInitJsonExpr().

◆ ExecInitJsonExpr()

static void ExecInitJsonExpr ( JsonExpr jsexpr,
ExprState state,
Datum resv,
bool resnull,
ExprEvalStep scratch 
)
static

Definition at line 4225 of file execExpr.c.

4228 {
4229  JsonExprState *jsestate = palloc0(sizeof(JsonExprState));
4230  ListCell *argexprlc;
4231  ListCell *argnamelc;
4232  List *jumps_return_null = NIL;
4233  List *jumps_to_end = NIL;
4234  ListCell *lc;
4235  ErrorSaveContext *escontext =
4236  jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR ?
4237  &jsestate->escontext : NULL;
4238 
4239  jsestate->jsexpr = jsexpr;
4240 
4241  /*
4242  * Evaluate formatted_expr storing the result into
4243  * jsestate->formatted_expr.
4244  */
4246  &jsestate->formatted_expr.value,
4247  &jsestate->formatted_expr.isnull);
4248 
4249  /* JUMP to return NULL if formatted_expr evaluates to NULL */
4250  jumps_return_null = lappend_int(jumps_return_null, state->steps_len);
4251  scratch->opcode = EEOP_JUMP_IF_NULL;
4252  scratch->resnull = &jsestate->formatted_expr.isnull;
4253  scratch->d.jump.jumpdone = -1; /* set below */
4254  ExprEvalPushStep(state, scratch);
4255 
4256  /*
4257  * Evaluate pathspec expression storing the result into
4258  * jsestate->pathspec.
4259  */
4260  ExecInitExprRec((Expr *) jsexpr->path_spec, state,
4261  &jsestate->pathspec.value,
4262  &jsestate->pathspec.isnull);
4263 
4264  /* JUMP to return NULL if path_spec evaluates to NULL */
4265  jumps_return_null = lappend_int(jumps_return_null, state->steps_len);
4266  scratch->opcode = EEOP_JUMP_IF_NULL;
4267  scratch->resnull = &jsestate->pathspec.isnull;
4268  scratch->d.jump.jumpdone = -1; /* set below */
4269  ExprEvalPushStep(state, scratch);
4270 
4271  /* Steps to compute PASSING args. */
4272  jsestate->args = NIL;
4273  forboth(argexprlc, jsexpr->passing_values,
4274  argnamelc, jsexpr->passing_names)
4275  {
4276  Expr *argexpr = (Expr *) lfirst(argexprlc);
4277  String *argname = lfirst_node(String, argnamelc);
4278  JsonPathVariable *var = palloc(sizeof(*var));
4279 
4280  var->name = argname->sval;
4281  var->typid = exprType((Node *) argexpr);
4282  var->typmod = exprTypmod((Node *) argexpr);
4283 
4284  ExecInitExprRec((Expr *) argexpr, state, &var->value, &var->isnull);
4285 
4286  jsestate->args = lappend(jsestate->args, var);
4287  }
4288 
4289  /* Step for jsonpath evaluation; see ExecEvalJsonExprPath(). */
4290  scratch->opcode = EEOP_JSONEXPR_PATH;
4291  scratch->resvalue = resv;
4292  scratch->resnull = resnull;
4293  scratch->d.jsonexpr.jsestate = jsestate;
4294  ExprEvalPushStep(state, scratch);
4295 
4296  /*
4297  * Step to return NULL after jumping to skip the EEOP_JSONEXPR_PATH step
4298  * when either formatted_expr or pathspec is NULL. Adjust jump target
4299  * addresses of JUMPs that we added above.
4300  */
4301  foreach(lc, jumps_return_null)
4302  {
4303  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4304 
4305  as->d.jump.jumpdone = state->steps_len;
4306  }
4307  scratch->opcode = EEOP_CONST;
4308  scratch->resvalue = resv;
4309  scratch->resnull = resnull;
4310  scratch->d.constval.value = (Datum) 0;
4311  scratch->d.constval.isnull = true;
4312  ExprEvalPushStep(state, scratch);
4313 
4314  /*
4315  * Jump to coerce the NULL using coercion_expr if present. Coercing NULL
4316  * is only interesting when the RETURNING type is a domain whose
4317  * constraints must be checked. jsexpr->coercion_expr containing a
4318  * CoerceToDomain node must have been set in that case.
4319  */
4320  if (jsexpr->coercion_expr)
4321  {
4322  scratch->opcode = EEOP_JUMP;
4323  scratch->d.jump.jumpdone = state->steps_len + 1;
4324  ExprEvalPushStep(state, scratch);
4325  }
4326 
4327  /*
4328  * To handle coercion errors softly, use the following ErrorSaveContext to
4329  * pass to ExecInitExprRec() when initializing the coercion expressions
4330  * and in the EEOP_JSONEXPR_COERCION step.
4331  */
4332  jsestate->escontext.type = T_ErrorSaveContext;
4333 
4334  /*
4335  * Steps to coerce the result value computed by EEOP_JSONEXPR_PATH or the
4336  * NULL returned on NULL input as described above.
4337  */
4338  jsestate->jump_eval_coercion = -1;
4339  if (jsexpr->coercion_expr)
4340  {
4341  Datum *save_innermost_caseval;
4342  bool *save_innermost_casenull;
4343  ErrorSaveContext *save_escontext;
4344 
4345  jsestate->jump_eval_coercion = state->steps_len;
4346 
4347  save_innermost_caseval = state->innermost_caseval;
4348  save_innermost_casenull = state->innermost_casenull;
4349  save_escontext = state->escontext;
4350 
4351  state->innermost_caseval = resv;
4352  state->innermost_casenull = resnull;
4353  state->escontext = escontext;
4354 
4355  ExecInitExprRec((Expr *) jsexpr->coercion_expr, state, resv, resnull);
4356 
4357  state->innermost_caseval = save_innermost_caseval;
4358  state->innermost_casenull = save_innermost_casenull;
4359  state->escontext = save_escontext;
4360  }
4361  else if (jsexpr->use_json_coercion)
4362  {
4363  jsestate->jump_eval_coercion = state->steps_len;
4364 
4365  ExecInitJsonCoercion(state, jsexpr->returning, escontext, resv, resnull);
4366  }
4367  else if (jsexpr->use_io_coercion)
4368  {
4369  /*
4370  * Here we only need to initialize the FunctionCallInfo for the target
4371  * type's input function, which is called by ExecEvalJsonExprPath()
4372  * itself, so no additional step is necessary.
4373  */
4374  Oid typinput;
4375  Oid typioparam;
4376  FmgrInfo *finfo;
4377  FunctionCallInfo fcinfo;
4378 
4379  getTypeInputInfo(jsexpr->returning->typid, &typinput, &typioparam);
4380  finfo = palloc0(sizeof(FmgrInfo));
4381  fcinfo = palloc0(SizeForFunctionCallInfo(3));
4382  fmgr_info(typinput, finfo);
4383  fmgr_info_set_expr((Node *) jsexpr->returning, finfo);
4384  InitFunctionCallInfoData(*fcinfo, finfo, 3, InvalidOid, NULL, NULL);
4385 
4386  /*
4387  * We can preload the second and third arguments for the input
4388  * function, since they're constants.
4389  */
4390  fcinfo->args[1].value = ObjectIdGetDatum(typioparam);
4391  fcinfo->args[1].isnull = false;
4392  fcinfo->args[2].value = Int32GetDatum(jsexpr->returning->typmod);
4393  fcinfo->args[2].isnull = false;
4394  fcinfo->context = (Node *) escontext;
4395 
4396  jsestate->input_fcinfo = fcinfo;
4397  }
4398 
4399  /*
4400  * Add a special step, if needed, to check if the coercion evaluation ran
4401  * into an error but was not thrown because the ON ERROR behavior is not
4402  * ERROR. It will set jsestate->error if an error did occur.
4403  */
4404  if (jsestate->jump_eval_coercion >= 0 && escontext != NULL)
4405  {
4407  scratch->d.jsonexpr.jsestate = jsestate;
4408  ExprEvalPushStep(state, scratch);
4409  }
4410 
4411  jsestate->jump_empty = jsestate->jump_error = -1;
4412 
4413  /*
4414  * Step to check jsestate->error and return the ON ERROR expression if
4415  * there is one. This handles both the errors that occur during jsonpath
4416  * evaluation in EEOP_JSONEXPR_PATH and subsequent coercion evaluation.
4417  */
4418  if (jsexpr->on_error &&
4419  jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR)
4420  {
4421  jsestate->jump_error = state->steps_len;
4422 
4423  /* JUMP to end if false, that is, skip the ON ERROR expression. */
4424  jumps_to_end = lappend_int(jumps_to_end, state->steps_len);
4425  scratch->opcode = EEOP_JUMP_IF_NOT_TRUE;
4426  scratch->resvalue = &jsestate->error.value;
4427  scratch->resnull = &jsestate->error.isnull;
4428  scratch->d.jump.jumpdone = -1; /* set below */
4429  ExprEvalPushStep(state, scratch);
4430 
4431  /* Steps to evaluate the ON ERROR expression */
4432  ExecInitExprRec((Expr *) jsexpr->on_error->expr,
4433  state, resv, resnull);
4434 
4435  /* Step to coerce the ON ERROR expression if needed */
4436  if (jsexpr->on_error->coerce)
4437  ExecInitJsonCoercion(state, jsexpr->returning, escontext, resv,
4438  resnull);
4439 
4440  /* JUMP to end to skip the ON EMPTY steps added below. */
4441  jumps_to_end = lappend_int(jumps_to_end, state->steps_len);
4442  scratch->opcode = EEOP_JUMP;
4443  scratch->d.jump.jumpdone = -1;
4444  ExprEvalPushStep(state, scratch);
4445  }
4446 
4447  /*
4448  * Step to check jsestate->empty and return the ON EMPTY expression if
4449  * there is one.
4450  */
4451  if (jsexpr->on_empty != NULL &&
4452  jsexpr->on_empty->btype != JSON_BEHAVIOR_ERROR)
4453  {
4454  jsestate->jump_empty = state->steps_len;
4455 
4456  /* JUMP to end if false, that is, skip the ON EMPTY expression. */
4457  jumps_to_end = lappend_int(jumps_to_end, state->steps_len);
4458  scratch->opcode = EEOP_JUMP_IF_NOT_TRUE;
4459  scratch->resvalue = &jsestate->empty.value;
4460  scratch->resnull = &jsestate->empty.isnull;
4461  scratch->d.jump.jumpdone = -1; /* set below */
4462  ExprEvalPushStep(state, scratch);
4463 
4464  /* Steps to evaluate the ON EMPTY expression */
4465  ExecInitExprRec((Expr *) jsexpr->on_empty->expr,
4466  state, resv, resnull);
4467 
4468  /* Step to coerce the ON EMPTY expression if needed */
4469  if (jsexpr->on_empty->coerce)
4470  ExecInitJsonCoercion(state, jsexpr->returning, escontext, resv,
4471  resnull);
4472  }
4473 
4474  foreach(lc, jumps_to_end)
4475  {
4476  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4477 
4478  as->d.jump.jumpdone = state->steps_len;
4479  }
4480 
4481  jsestate->jump_end = state->steps_len;
4482 }
static void ExecInitJsonCoercion(ExprState *state, JsonReturning *returning, ErrorSaveContext *escontext, Datum *resv, bool *resnull)
Definition: execExpr.c:4489
@ EEOP_JSONEXPR_PATH
Definition: execExpr.h:243
@ EEOP_JSONEXPR_COERCION_FINISH
Definition: execExpr.h:245
@ EEOP_JUMP_IF_NULL
Definition: execExpr.h:141
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:298
@ JSON_BEHAVIOR_ERROR
Definition: primnodes.h:1762
NodeTag type
Definition: miscnodes.h:45
struct ExprEvalStep::@54::@99 jsonexpr
Node * expr
Definition: primnodes.h:1787
JsonBehaviorType btype
Definition: primnodes.h:1786
int jump_eval_coercion
Definition: execnodes.h:1059
NullableDatum empty
Definition: execnodes.h:1044
FunctionCallInfo input_fcinfo
Definition: execnodes.h:1073
JsonExpr * jsexpr
Definition: execnodes.h:1022
NullableDatum error
Definition: execnodes.h:1041
NullableDatum pathspec
Definition: execnodes.h:1028
ErrorSaveContext escontext
Definition: execnodes.h:1082
NullableDatum formatted_expr
Definition: execnodes.h:1025
List * passing_values
Definition: primnodes.h:1832
JsonBehavior * on_empty
Definition: primnodes.h:1835
List * passing_names
Definition: primnodes.h:1831
Node * path_spec
Definition: primnodes.h:1825
bool use_io_coercion
Definition: primnodes.h:1848
JsonReturning * returning
Definition: primnodes.h:1828
bool use_json_coercion
Definition: primnodes.h:1849
JsonBehavior * on_error
Definition: primnodes.h:1836
Node * coercion_expr
Definition: primnodes.h:1847
Definition: value.h:64
char * sval
Definition: value.h:68

References FunctionCallInfoBaseData::args, JsonExprState::args, JsonBehavior::btype, JsonBehavior::coerce, JsonExpr::coercion_expr, ExprEvalStep::constval, FunctionCallInfoBaseData::context, ExprEvalStep::d, EEOP_CONST, EEOP_JSONEXPR_COERCION_FINISH, EEOP_JSONEXPR_PATH, EEOP_JUMP, EEOP_JUMP_IF_NOT_TRUE, EEOP_JUMP_IF_NULL, JsonExprState::empty, JsonExprState::error, JsonExprState::escontext, ExecInitExprRec(), ExecInitJsonCoercion(), JsonBehavior::expr, ExprEvalPushStep(), exprType(), exprTypmod(), fmgr_info(), fmgr_info_set_expr, forboth, JsonExprState::formatted_expr, JsonExpr::formatted_expr, getTypeInputInfo(), InitFunctionCallInfoData, JsonExprState::input_fcinfo, Int32GetDatum(), InvalidOid, NullableDatum::isnull, JsonPathVariable::isnull, JsonExprState::jsexpr, JSON_BEHAVIOR_ERROR, ExprEvalStep::jsonexpr, ExprEvalStep::jump, JsonExprState::jump_empty, JsonExprState::jump_end, JsonExprState::jump_error, JsonExprState::jump_eval_coercion, lappend(), lappend_int(), lfirst, lfirst_int, lfirst_node, JsonPathVariable::name, NIL, ObjectIdGetDatum(), JsonExpr::on_empty, JsonExpr::on_error, ExprEvalStep::opcode, palloc(), palloc0(), JsonExpr::passing_names, JsonExpr::passing_values, JsonExpr::path_spec, JsonExprState::pathspec, ExprEvalStep::resnull, ExprEvalStep::resvalue, JsonExpr::returning, SizeForFunctionCallInfo, String::sval, ErrorSaveContext::type, JsonReturning::typid, JsonPathVariable::typid, JsonReturning::typmod, JsonPathVariable::typmod, JsonExpr::use_io_coercion, JsonExpr::use_json_coercion, NullableDatum::value, and JsonPathVariable::value.

Referenced by ExecInitExprRec().

◆ ExecInitQual()

ExprState* ExecInitQual ( List qual,
PlanState parent 
)

Definition at line 220 of file execExpr.c.

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

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

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

◆ ExecInitSubscriptingRef()

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

Definition at line 3056 of file execExpr.c.

3058 {
3059  bool isAssignment = (sbsref->refassgnexpr != NULL);
3060  int nupper = list_length(sbsref->refupperindexpr);
3061  int nlower = list_length(sbsref->reflowerindexpr);
3062  const SubscriptRoutines *sbsroutines;
3063  SubscriptingRefState *sbsrefstate;
3064  SubscriptExecSteps methods;
3065  char *ptr;
3066  List *adjust_jumps = NIL;
3067  ListCell *lc;
3068  int i;
3069 
3070  /* Look up the subscripting support methods */
3071  sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype, NULL);
3072  if (!sbsroutines)
3073  ereport(ERROR,
3074  (errcode(ERRCODE_DATATYPE_MISMATCH),
3075  errmsg("cannot subscript type %s because it does not support subscripting",
3076  format_type_be(sbsref->refcontainertype)),
3077  state->parent ?
3078  executor_errposition(state->parent->state,
3079  exprLocation((Node *) sbsref)) : 0));
3080 
3081  /* Allocate sbsrefstate, with enough space for per-subscript arrays too */
3082  sbsrefstate = palloc0(MAXALIGN(sizeof(SubscriptingRefState)) +
3083  (nupper + nlower) * (sizeof(Datum) +
3084  2 * sizeof(bool)));
3085 
3086  /* Fill constant fields of SubscriptingRefState */
3087  sbsrefstate->isassignment = isAssignment;
3088  sbsrefstate->numupper = nupper;
3089  sbsrefstate->numlower = nlower;
3090  /* Set up per-subscript arrays */
3091  ptr = ((char *) sbsrefstate) + MAXALIGN(sizeof(SubscriptingRefState));
3092  sbsrefstate->upperindex = (Datum *) ptr;
3093  ptr += nupper * sizeof(Datum);
3094  sbsrefstate->lowerindex = (Datum *) ptr;
3095  ptr += nlower * sizeof(Datum);
3096  sbsrefstate->upperprovided = (bool *) ptr;
3097  ptr += nupper * sizeof(bool);
3098  sbsrefstate->lowerprovided = (bool *) ptr;
3099  ptr += nlower * sizeof(bool);
3100  sbsrefstate->upperindexnull = (bool *) ptr;
3101  ptr += nupper * sizeof(bool);
3102  sbsrefstate->lowerindexnull = (bool *) ptr;
3103  /* ptr += nlower * sizeof(bool); */
3104 
3105  /*
3106  * Let the container-type-specific code have a chance. It must fill the
3107  * "methods" struct with function pointers for us to possibly use in
3108  * execution steps below; and it can optionally set up some data pointed
3109  * to by the workspace field.
3110  */
3111  memset(&methods, 0, sizeof(methods));
3112  sbsroutines->exec_setup(sbsref, sbsrefstate, &methods);
3113 
3114  /*
3115  * Evaluate array input. It's safe to do so into resv/resnull, because we
3116  * won't use that as target for any of the other subexpressions, and it'll
3117  * be overwritten by the final EEOP_SBSREF_FETCH/ASSIGN step, which is
3118  * pushed last.
3119  */
3120  ExecInitExprRec(sbsref->refexpr, state, resv, resnull);
3121 
3122  /*
3123  * If refexpr yields NULL, and the operation should be strict, then result
3124  * is NULL. We can implement this with just JUMP_IF_NULL, since we
3125  * evaluated the array into the desired target location.
3126  */
3127  if (!isAssignment && sbsroutines->fetch_strict)
3128  {
3129  scratch->opcode = EEOP_JUMP_IF_NULL;
3130  scratch->d.jump.jumpdone = -1; /* adjust later */
3131  ExprEvalPushStep(state, scratch);
3132  adjust_jumps = lappend_int(adjust_jumps,
3133  state->steps_len - 1);
3134  }
3135 
3136  /* Evaluate upper subscripts */
3137  i = 0;
3138  foreach(lc, sbsref->refupperindexpr)
3139  {
3140  Expr *e = (Expr *) lfirst(lc);
3141 
3142  /* When slicing, individual subscript bounds can be omitted */
3143  if (!e)
3144  {
3145  sbsrefstate->upperprovided[i] = false;
3146  sbsrefstate->upperindexnull[i] = true;
3147  }
3148  else
3149  {
3150  sbsrefstate->upperprovided[i] = true;
3151  /* Each subscript is evaluated into appropriate array entry */
3153  &sbsrefstate->upperindex[i],
3154  &sbsrefstate->upperindexnull[i]);
3155  }
3156  i++;
3157  }
3158 
3159  /* Evaluate lower subscripts similarly */
3160  i = 0;
3161  foreach(lc, sbsref->reflowerindexpr)
3162  {
3163  Expr *e = (Expr *) lfirst(lc);
3164 
3165  /* When slicing, individual subscript bounds can be omitted */
3166  if (!e)
3167  {
3168  sbsrefstate->lowerprovided[i] = false;
3169  sbsrefstate->lowerindexnull[i] = true;
3170  }
3171  else
3172  {
3173  sbsrefstate->lowerprovided[i] = true;
3174  /* Each subscript is evaluated into appropriate array entry */
3176  &sbsrefstate->lowerindex[i],
3177  &sbsrefstate->lowerindexnull[i]);
3178  }
3179  i++;
3180  }
3181 
3182  /* SBSREF_SUBSCRIPTS checks and converts all the subscripts at once */
3183  if (methods.sbs_check_subscripts)
3184  {
3185  scratch->opcode = EEOP_SBSREF_SUBSCRIPTS;
3186  scratch->d.sbsref_subscript.subscriptfunc = methods.sbs_check_subscripts;
3187  scratch->d.sbsref_subscript.state = sbsrefstate;
3188  scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */
3189  ExprEvalPushStep(state, scratch);
3190  adjust_jumps = lappend_int(adjust_jumps,
3191  state->steps_len - 1);
3192  }
3193 
3194  if (isAssignment)
3195  {
3196  Datum *save_innermost_caseval;
3197  bool *save_innermost_casenull;
3198 
3199  /* Check for unimplemented methods */
3200  if (!methods.sbs_assign)
3201  ereport(ERROR,
3202  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3203  errmsg("type %s does not support subscripted assignment",
3204  format_type_be(sbsref->refcontainertype))));
3205 
3206  /*
3207  * We might have a nested-assignment situation, in which the
3208  * refassgnexpr is itself a FieldStore or SubscriptingRef that needs
3209  * to obtain and modify the previous value of the array element or
3210  * slice being replaced. If so, we have to extract that value from
3211  * the array and pass it down via the CaseTestExpr mechanism. It's
3212  * safe to reuse the CASE mechanism because there cannot be a CASE
3213  * between here and where the value would be needed, and an array
3214  * assignment can't be within a CASE either. (So saving and restoring
3215  * innermost_caseval is just paranoia, but let's do it anyway.)
3216  *
3217  * Since fetching the old element might be a nontrivial expense, do it
3218  * only if the argument actually needs it.
3219  */
3221  {
3222  if (!methods.sbs_fetch_old)
3223  ereport(ERROR,
3224  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3225  errmsg("type %s does not support subscripted assignment",
3226  format_type_be(sbsref->refcontainertype))));
3227  scratch->opcode = EEOP_SBSREF_OLD;
3228  scratch->d.