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

Typedefs

typedef struct LastAttnumInfo LastAttnumInfo
 

Functions

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

Typedef Documentation

◆ LastAttnumInfo

Function Documentation

◆ ExecBuildAggTrans()

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

Definition at line 3538 of file execExpr.c.

3540 {
3542  PlanState *parent = &aggstate->ss.ps;
3543  ExprEvalStep scratch = {0};
3544  bool isCombine = DO_AGGSPLIT_COMBINE(aggstate->aggsplit);
3545  LastAttnumInfo deform = {0, 0, 0};
3546 
3547  state->expr = (Expr *) aggstate;
3548  state->parent = parent;
3549 
3550  scratch.resvalue = &state->resvalue;
3551  scratch.resnull = &state->resnull;
3552 
3553  /*
3554  * First figure out which slots, and how many columns from each, we're
3555  * going to need.
3556  */
3557  for (int transno = 0; transno < aggstate->numtrans; transno++)
3558  {
3559  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3560 
3562  &deform);
3563  get_last_attnums_walker((Node *) pertrans->aggref->args,
3564  &deform);
3566  &deform);
3568  &deform);
3570  &deform);
3571  }
3572  ExecPushExprSlots(state, &deform);
3573 
3574  /*
3575  * Emit instructions for each transition value / grouping set combination.
3576  */
3577  for (int transno = 0; transno < aggstate->numtrans; transno++)
3578  {
3579  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3580  FunctionCallInfo trans_fcinfo = pertrans->transfn_fcinfo;
3581  List *adjust_bailout = NIL;
3582  NullableDatum *strictargs = NULL;
3583  bool *strictnulls = NULL;
3584  int argno;
3585  ListCell *bail;
3586 
3587  /*
3588  * If filter present, emit. Do so before evaluating the input, to
3589  * avoid potentially unneeded computations, or even worse, unintended
3590  * side-effects. When combining, all the necessary filtering has
3591  * already been done.
3592  */
3593  if (pertrans->aggref->aggfilter && !isCombine)
3594  {
3595  /* evaluate filter expression */
3596  ExecInitExprRec(pertrans->aggref->aggfilter, state,
3597  &state->resvalue, &state->resnull);
3598  /* and jump out if false */
3599  scratch.opcode = EEOP_JUMP_IF_NOT_TRUE;
3600  scratch.d.jump.jumpdone = -1; /* adjust later */
3601  ExprEvalPushStep(state, &scratch);
3602  adjust_bailout = lappend_int(adjust_bailout,
3603  state->steps_len - 1);
3604  }
3605 
3606  /*
3607  * Evaluate arguments to aggregate/combine function.
3608  */
3609  argno = 0;
3610  if (isCombine)
3611  {
3612  /*
3613  * Combining two aggregate transition values. Instead of directly
3614  * coming from a tuple the input is a, potentially deserialized,
3615  * transition value.
3616  */
3617  TargetEntry *source_tle;
3618 
3619  Assert(pertrans->numSortCols == 0);
3620  Assert(list_length(pertrans->aggref->args) == 1);
3621 
3622  strictargs = trans_fcinfo->args + 1;
3623  source_tle = (TargetEntry *) linitial(pertrans->aggref->args);
3624 
3625  /*
3626  * deserialfn_oid will be set if we must deserialize the input
3627  * state before calling the combine function.
3628  */
3629  if (!OidIsValid(pertrans->deserialfn_oid))
3630  {
3631  /*
3632  * Start from 1, since the 0th arg will be the transition
3633  * value
3634  */
3635  ExecInitExprRec(source_tle->expr, state,
3636  &trans_fcinfo->args[argno + 1].value,
3637  &trans_fcinfo->args[argno + 1].isnull);
3638  }
3639  else
3640  {
3641  FunctionCallInfo ds_fcinfo = pertrans->deserialfn_fcinfo;
3642 
3643  /* evaluate argument */
3644  ExecInitExprRec(source_tle->expr, state,
3645  &ds_fcinfo->args[0].value,
3646  &ds_fcinfo->args[0].isnull);
3647 
3648  /* Dummy second argument for type-safety reasons */
3649  ds_fcinfo->args[1].value = PointerGetDatum(NULL);
3650  ds_fcinfo->args[1].isnull = false;
3651 
3652  /*
3653  * Don't call a strict deserialization function with NULL
3654  * input
3655  */
3656  if (pertrans->deserialfn.fn_strict)
3658  else
3659  scratch.opcode = EEOP_AGG_DESERIALIZE;
3660 
3661  scratch.d.agg_deserialize.fcinfo_data = ds_fcinfo;
3662  scratch.d.agg_deserialize.jumpnull = -1; /* adjust later */
3663  scratch.resvalue = &trans_fcinfo->args[argno + 1].value;
3664  scratch.resnull = &trans_fcinfo->args[argno + 1].isnull;
3665 
3666  ExprEvalPushStep(state, &scratch);
3667  /* don't add an adjustment unless the function is strict */
3668  if (pertrans->deserialfn.fn_strict)
3669  adjust_bailout = lappend_int(adjust_bailout,
3670  state->steps_len - 1);
3671 
3672  /* restore normal settings of scratch fields */
3673  scratch.resvalue = &state->resvalue;
3674  scratch.resnull = &state->resnull;
3675  }
3676  argno++;
3677  }
3678  else if (pertrans->numSortCols == 0)
3679  {
3680  ListCell *arg;
3681 
3682  /*
3683  * Normal transition function without ORDER BY / DISTINCT.
3684  */
3685  strictargs = trans_fcinfo->args + 1;
3686 
3687  foreach(arg, pertrans->aggref->args)
3688  {
3689  TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3690 
3691  /*
3692  * Start from 1, since the 0th arg will be the transition
3693  * value
3694  */
3695  ExecInitExprRec(source_tle->expr, state,
3696  &trans_fcinfo->args[argno + 1].value,
3697  &trans_fcinfo->args[argno + 1].isnull);
3698  argno++;
3699  }
3700  }
3701  else if (pertrans->numInputs == 1)
3702  {
3703  /*
3704  * DISTINCT and/or ORDER BY case, with a single column sorted on.
3705  */
3706  TargetEntry *source_tle =
3707  (TargetEntry *) linitial(pertrans->aggref->args);
3708 
3709  Assert(list_length(pertrans->aggref->args) == 1);
3710 
3711  ExecInitExprRec(source_tle->expr, state,
3712  &state->resvalue,
3713  &state->resnull);
3714  strictnulls = &state->resnull;
3715  argno++;
3716  }
3717  else
3718  {
3719  /*
3720  * DISTINCT and/or ORDER BY case, with multiple columns sorted on.
3721  */
3722  Datum *values = pertrans->sortslot->tts_values;
3723  bool *nulls = pertrans->sortslot->tts_isnull;
3724  ListCell *arg;
3725 
3726  strictnulls = nulls;
3727 
3728  foreach(arg, pertrans->aggref->args)
3729  {
3730  TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3731 
3732  ExecInitExprRec(source_tle->expr, state,
3733  &values[argno], &nulls[argno]);
3734  argno++;
3735  }
3736  }
3737  Assert(pertrans->numInputs == argno);
3738 
3739  /*
3740  * For a strict transfn, nothing happens when there's a NULL input; we
3741  * just keep the prior transValue. This is true for both plain and
3742  * sorted/distinct aggregates.
3743  */
3744  if (trans_fcinfo->flinfo->fn_strict && pertrans->numTransInputs > 0)
3745  {
3746  if (strictnulls)
3748  else
3750  scratch.d.agg_strict_input_check.nulls = strictnulls;
3751  scratch.d.agg_strict_input_check.args = strictargs;
3752  scratch.d.agg_strict_input_check.jumpnull = -1; /* adjust later */
3753  scratch.d.agg_strict_input_check.nargs = pertrans->numTransInputs;
3754  ExprEvalPushStep(state, &scratch);
3755  adjust_bailout = lappend_int(adjust_bailout,
3756  state->steps_len - 1);
3757  }
3758 
3759  /*
3760  * Call transition function (once for each concurrently evaluated
3761  * grouping set). Do so for both sort and hash based computations, as
3762  * applicable.
3763  */
3764  if (doSort)
3765  {
3766  int processGroupingSets = Max(phase->numsets, 1);
3767  int setoff = 0;
3768 
3769  for (int setno = 0; setno < processGroupingSets; setno++)
3770  {
3771  ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3772  pertrans, transno, setno, setoff, false,
3773  nullcheck);
3774  setoff++;
3775  }
3776  }
3777 
3778  if (doHash)
3779  {
3780  int numHashes = aggstate->num_hashes;
3781  int setoff;
3782 
3783  /* in MIXED mode, there'll be preceding transition values */
3784  if (aggstate->aggstrategy != AGG_HASHED)
3785  setoff = aggstate->maxsets;
3786  else
3787  setoff = 0;
3788 
3789  for (int setno = 0; setno < numHashes; setno++)
3790  {
3791  ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3792  pertrans, transno, setno, setoff, true,
3793  nullcheck);
3794  setoff++;
3795  }
3796  }
3797 
3798  /* adjust early bail out jump target(s) */
3799  foreach(bail, adjust_bailout)
3800  {
3801  ExprEvalStep *as = &state->steps[lfirst_int(bail)];
3802 
3803  if (as->opcode == EEOP_JUMP_IF_NOT_TRUE)
3804  {
3805  Assert(as->d.jump.jumpdone == -1);
3806  as->d.jump.jumpdone = state->steps_len;
3807  }
3808  else if (as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_ARGS ||
3810  {
3811  Assert(as->d.agg_strict_input_check.jumpnull == -1);
3812  as->d.agg_strict_input_check.jumpnull = state->steps_len;
3813  }
3814  else if (as->opcode == EEOP_AGG_STRICT_DESERIALIZE)
3815  {
3816  Assert(as->d.agg_deserialize.jumpnull == -1);
3817  as->d.agg_deserialize.jumpnull = state->steps_len;
3818  }
3819  else
3820  Assert(false);
3821  }
3822  }
3823 
3824  scratch.resvalue = NULL;
3825  scratch.resnull = NULL;
3826  scratch.opcode = EEOP_DONE;
3827  ExprEvalPushStep(state, &scratch);
3828 
3830 
3831  return state;
3832 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define Max(x, y)
Definition: c.h:991
#define OidIsValid(objectId)
Definition: c.h:721
static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info)
Definition: execExpr.c:2886
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:900
static void ExecBuildAggTransCall(ExprState *state, AggState *aggstate, ExprEvalStep *scratch, FunctionCallInfo fcinfo, AggStatePerTrans pertrans, int transno, int setno, int setoff, bool ishash, bool nullcheck)
Definition: execExpr.c:3840
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2693
static void ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
Definition: execExpr.c:2842
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:883
@ EEOP_AGG_STRICT_DESERIALIZE
Definition: execExpr.h:248
@ EEOP_DONE
Definition: execExpr.h:68
@ EEOP_AGG_STRICT_INPUT_CHECK_NULLS
Definition: execExpr.h:251
@ EEOP_AGG_STRICT_INPUT_CHECK_ARGS
Definition: execExpr.h:250
@ EEOP_AGG_DESERIALIZE
Definition: execExpr.h:249
@ EEOP_JUMP_IF_NOT_TRUE
Definition: execExpr.h:142
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend_int(List *list, int datum)
Definition: list.c:354
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:838
@ AGG_HASHED
Definition: nodes.h:809
#define makeNode(_type_)
Definition: nodes.h:621
void * arg
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
#define NIL
Definition: pg_list.h:65
#define lfirst_int(lc)
Definition: pg_list.h:170
#define linitial(l)
Definition: pg_list.h:174
uintptr_t Datum
Definition: postgres.h:411
#define PointerGetDatum(X)
Definition: postgres.h:600
TupleTableSlot * sortslot
Definition: nodeAgg.h:136
Aggref * aggref
Definition: nodeAgg.h:44
FmgrInfo deserialfn
Definition: nodeAgg.h:87
FunctionCallInfo deserialfn_fcinfo
Definition: nodeAgg.h:167
FunctionCallInfo transfn_fcinfo
Definition: nodeAgg.h:162
ScanState ss
Definition: execnodes.h:2326
AggStatePerTrans pertrans
Definition: execnodes.h:2336
AggStrategy aggstrategy
Definition: execnodes.h:2330
int numtrans
Definition: execnodes.h:2329
AggSplit aggsplit
Definition: execnodes.h:2331
int num_hashes
Definition: execnodes.h:2367
int maxsets
Definition: execnodes.h:2356
List * aggdistinct
Definition: primnodes.h:341
List * aggdirectargs
Definition: primnodes.h:338
List * args
Definition: primnodes.h:339
Expr * aggfilter
Definition: primnodes.h:342
List * aggorder
Definition: primnodes.h:340
struct ExprEvalStep::@52::@62 jump
intptr_t opcode
Definition: execExpr.h:274
Datum * resvalue
Definition: execExpr.h:277
union ExprEvalStep::@52 d
struct ExprEvalStep::@52::@90 agg_deserialize
bool * resnull
Definition: execExpr.h:278
struct ExprEvalStep::@52::@91 agg_strict_input_check
bool fn_strict
Definition: fmgr.h:61
FmgrInfo * flinfo
Definition: fmgr.h:87
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
Definition: pg_list.h:51
Definition: nodes.h:574
Datum value
Definition: postgres.h:422
PlanState ps
Definition: execnodes.h:1423
Expr * expr
Definition: primnodes.h:1716
bool * tts_isnull
Definition: tuptable.h:128
Datum * tts_values
Definition: tuptable.h:126
Definition: regguts.h:318

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

Referenced by ExecInitAgg(), and hashagg_recompile_expressions().

◆ ExecBuildAggTransCall()

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

Definition at line 3840 of file execExpr.c.

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

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

Referenced by ExecBuildAggTrans().

◆ ExecBuildGroupingEqual()

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

Definition at line 3956 of file execExpr.c.

3963 {
3965  ExprEvalStep scratch = {0};
3966  int maxatt = -1;
3967  List *adjust_jumps = NIL;
3968  ListCell *lc;
3969 
3970  /*
3971  * When no columns are actually compared, the result's always true. See
3972  * special case in ExecQual().
3973  */
3974  if (numCols == 0)
3975  return NULL;
3976 
3977  state->expr = NULL;
3978  state->flags = EEO_FLAG_IS_QUAL;
3979  state->parent = parent;
3980 
3981  scratch.resvalue = &state->resvalue;
3982  scratch.resnull = &state->resnull;
3983 
3984  /* compute max needed attribute */
3985  for (int natt = 0; natt < numCols; natt++)
3986  {
3987  int attno = keyColIdx[natt];
3988 
3989  if (attno > maxatt)
3990  maxatt = attno;
3991  }
3992  Assert(maxatt >= 0);
3993 
3994  /* push deform steps */
3995  scratch.opcode = EEOP_INNER_FETCHSOME;
3996  scratch.d.fetch.last_var = maxatt;
3997  scratch.d.fetch.fixed = false;
3998  scratch.d.fetch.known_desc = ldesc;
3999  scratch.d.fetch.kind = lops;
4000  if (ExecComputeSlotInfo(state, &scratch))
4001  ExprEvalPushStep(state, &scratch);
4002 
4003  scratch.opcode = EEOP_OUTER_FETCHSOME;
4004  scratch.d.fetch.last_var = maxatt;
4005  scratch.d.fetch.fixed = false;
4006  scratch.d.fetch.known_desc = rdesc;
4007  scratch.d.fetch.kind = rops;
4008  if (ExecComputeSlotInfo(state, &scratch))
4009  ExprEvalPushStep(state, &scratch);
4010 
4011  /*
4012  * Start comparing at the last field (least significant sort key). That's
4013  * the most likely to be different if we are dealing with sorted input.
4014  */
4015  for (int natt = numCols; --natt >= 0;)
4016  {
4017  int attno = keyColIdx[natt];
4018  Form_pg_attribute latt = TupleDescAttr(ldesc, attno - 1);
4019  Form_pg_attribute ratt = TupleDescAttr(rdesc, attno - 1);
4020  Oid foid = eqfunctions[natt];
4021  Oid collid = collations[natt];
4022  FmgrInfo *finfo;
4023  FunctionCallInfo fcinfo;
4024  AclResult aclresult;
4025 
4026  /* Check permission to call function */
4027  aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
4028  if (aclresult != ACLCHECK_OK)
4029  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
4030 
4032 
4033  /* Set up the primary fmgr lookup information */
4034  finfo = palloc0(sizeof(FmgrInfo));
4035  fcinfo = palloc0(SizeForFunctionCallInfo(2));
4036  fmgr_info(foid, finfo);
4037  fmgr_info_set_expr(NULL, finfo);
4038  InitFunctionCallInfoData(*fcinfo, finfo, 2,
4039  collid, NULL, NULL);
4040 
4041  /* left arg */
4042  scratch.opcode = EEOP_INNER_VAR;
4043  scratch.d.var.attnum = attno - 1;
4044  scratch.d.var.vartype = latt->atttypid;
4045  scratch.resvalue = &fcinfo->args[0].value;
4046  scratch.resnull = &fcinfo->args[0].isnull;
4047  ExprEvalPushStep(state, &scratch);
4048 
4049  /* right arg */
4050  scratch.opcode = EEOP_OUTER_VAR;
4051  scratch.d.var.attnum = attno - 1;
4052  scratch.d.var.vartype = ratt->atttypid;
4053  scratch.resvalue = &fcinfo->args[1].value;
4054  scratch.resnull = &fcinfo->args[1].isnull;
4055  ExprEvalPushStep(state, &scratch);
4056 
4057  /* evaluate distinctness */
4058  scratch.opcode = EEOP_NOT_DISTINCT;
4059  scratch.d.func.finfo = finfo;
4060  scratch.d.func.fcinfo_data = fcinfo;
4061  scratch.d.func.fn_addr = finfo->fn_addr;
4062  scratch.d.func.nargs = 2;
4063  scratch.resvalue = &state->resvalue;
4064  scratch.resnull = &state->resnull;
4065  ExprEvalPushStep(state, &scratch);
4066 
4067  /* then emit EEOP_QUAL to detect if result is false (or null) */
4068  scratch.opcode = EEOP_QUAL;
4069  scratch.d.qualexpr.jumpdone = -1;
4070  scratch.resvalue = &state->resvalue;
4071  scratch.resnull = &state->resnull;
4072  ExprEvalPushStep(state, &scratch);
4073  adjust_jumps = lappend_int(adjust_jumps,
4074  state->steps_len - 1);
4075  }
4076 
4077  /* adjust jump targets */
4078  foreach(lc, adjust_jumps)
4079  {
4080  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4081 
4082  Assert(as->opcode == EEOP_QUAL);
4083  Assert(as->d.qualexpr.jumpdone == -1);
4084  as->d.qualexpr.jumpdone = state->steps_len;
4085  }
4086 
4087  scratch.resvalue = NULL;
4088  scratch.resnull = NULL;
4089  scratch.opcode = EEOP_DONE;
4090  ExprEvalPushStep(state, &scratch);
4091 
4093 
4094  return state;
4095 }
AclResult
Definition: acl.h:181
@ ACLCHECK_OK
Definition: acl.h:182
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3512
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:5071
static bool ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op)
Definition: execExpr.c:2940
@ EEOP_NOT_DISTINCT
Definition: execExpr.h:172
@ EEOP_INNER_VAR
Definition: execExpr.h:76
@ EEOP_QUAL
Definition: execExpr.h:134
@ EEOP_INNER_FETCHSOME
Definition: execExpr.h:71
@ EEOP_OUTER_FETCHSOME
Definition: execExpr.h:72
@ EEOP_OUTER_VAR
Definition: execExpr.h:77
#define EEO_FLAG_IS_QUAL
Definition: execnodes.h:60
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1589
void * palloc0(Size size)
Definition: mcxt.c:1099
Oid GetUserId(void)
Definition: miscinit.c:492
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:211
@ OBJECT_FUNCTION
Definition: parsenodes.h:2153
#define ACL_EXECUTE
Definition: parsenodes.h:89
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
unsigned int Oid
Definition: postgres_ext.h:31
struct ExprEvalStep::@52::@53 fetch
struct ExprEvalStep::@52::@59 func
struct ExprEvalStep::@52::@61 qualexpr
struct ExprEvalStep::@52::@54 var
Definition: fmgr.h:57
PGFunction fn_addr
Definition: fmgr.h:58
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

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

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

◆ ExecBuildParamSetEqual()

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

Definition at line 4113 of file execExpr.c.

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

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

Referenced by ExecInitMemoize().

◆ ExecBuildProjectionInfo()

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

Definition at line 353 of file execExpr.c.

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

References ExprEvalStep::assign_tmp, ExprEvalStep::assign_var, attnum, ExprEvalStep::d, EEOP_ASSIGN_INNER_VAR, EEOP_ASSIGN_OUTER_VAR, EEOP_ASSIGN_SCAN_VAR, EEOP_ASSIGN_TMP, EEOP_ASSIGN_TMP_MAKE_RO, EEOP_DONE, ExecInitExprRec(), ExecInitExprSlots(), ExecReadyExpr(), TargetEntry::expr, ExprEvalPushStep(), exprType(), get_typlen(), if(), INNER_VAR, IsA, lfirst_node, makeNode, ExprEvalStep::opcode, OUTER_VAR, ProjectionInfo::pi_exprContext, ProjectionInfo::pi_state, TargetEntry::resno, T_ExprState, TupleDescAttr, and ExprState::type.

Referenced by ExecAssignProjectionInfo(), ExecInitInsertProjection(), 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 513 of file execExpr.c.

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

References Assert(), ExprEvalStep::assign_tmp, ExprEvalStep::assign_var, attnum, bms_add_member(), bms_is_member(), ExprEvalStep::constval, ExprEvalStep::d, EEOP_ASSIGN_OUTER_VAR, EEOP_ASSIGN_SCAN_VAR, EEOP_ASSIGN_TMP, EEOP_CONST, EEOP_DONE, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, ExecInitExprRec(), ExecPushExprSlots(), ExecReadyExpr(), TargetEntry::expr, ExprEvalPushStep(), exprType(), for_each_cell, forboth, format_type_be(), get_last_attnums_walker(), LastAttnumInfo::last_outer, LastAttnumInfo::last_scan, lfirst_int, lfirst_node, list_length(), makeNode, TupleDescData::natts, ExprEvalStep::opcode, ProjectionInfo::pi_exprContext, ProjectionInfo::pi_state, TargetEntry::resjunk, ExprEvalStep::resnull, ExprEvalStep::resvalue, T_ExprState, TupleDescAttr, and ExprState::type.

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

◆ ExecCheck()

bool ExecCheck ( ExprState state,
ExprContext econtext 
)

Definition at line 853 of file execExpr.c.

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

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

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

◆ ExecComputeSlotInfo()

static bool ExecComputeSlotInfo ( ExprState state,
ExprEvalStep op 
)
static

Definition at line 2940 of file execExpr.c.

2941 {
2942  PlanState *parent = state->parent;
2943  TupleDesc desc = NULL;
2944  const TupleTableSlotOps *tts_ops = NULL;
2945  bool isfixed = false;
2946  ExprEvalOp opcode = op->opcode;
2947 
2948  Assert(opcode == EEOP_INNER_FETCHSOME ||
2949  opcode == EEOP_OUTER_FETCHSOME ||
2950  opcode == EEOP_SCAN_FETCHSOME);
2951 
2952  if (op->d.fetch.known_desc != NULL)
2953  {
2954  desc = op->d.fetch.known_desc;
2955  tts_ops = op->d.fetch.kind;
2956  isfixed = op->d.fetch.kind != NULL;
2957  }
2958  else if (!parent)
2959  {
2960  isfixed = false;
2961  }
2962  else if (opcode == EEOP_INNER_FETCHSOME)
2963  {
2964  PlanState *is = innerPlanState(parent);
2965 
2966  if (parent->inneropsset && !parent->inneropsfixed)
2967  {
2968  isfixed = false;
2969  }
2970  else if (parent->inneropsset && parent->innerops)
2971  {
2972  isfixed = true;
2973  tts_ops = parent->innerops;
2974  desc = ExecGetResultType(is);
2975  }
2976  else if (is)
2977  {
2978  tts_ops = ExecGetResultSlotOps(is, &isfixed);
2979  desc = ExecGetResultType(is);
2980  }
2981  }
2982  else if (opcode == EEOP_OUTER_FETCHSOME)
2983  {
2984  PlanState *os = outerPlanState(parent);
2985 
2986  if (parent->outeropsset && !parent->outeropsfixed)
2987  {
2988  isfixed = false;
2989  }
2990  else if (parent->outeropsset && parent->outerops)
2991  {
2992  isfixed = true;
2993  tts_ops = parent->outerops;
2994  desc = ExecGetResultType(os);
2995  }
2996  else if (os)
2997  {
2998  tts_ops = ExecGetResultSlotOps(os, &isfixed);
2999  desc = ExecGetResultType(os);
3000  }
3001  }
3002  else if (opcode == EEOP_SCAN_FETCHSOME)
3003  {
3004  desc = parent->scandesc;
3005 
3006  if (parent->scanops)
3007  tts_ops = parent->scanops;
3008 
3009  if (parent->scanopsset)
3010  isfixed = parent->scanopsfixed;
3011  }
3012 
3013  if (isfixed && desc != NULL && tts_ops != NULL)
3014  {
3015  op->d.fetch.fixed = true;
3016  op->d.fetch.kind = tts_ops;
3017  op->d.fetch.known_desc = desc;
3018  }
3019  else
3020  {
3021  op->d.fetch.fixed = false;
3022  op->d.fetch.kind = NULL;
3023  op->d.fetch.known_desc = NULL;
3024  }
3025 
3026  /* if the slot is known to always virtual we never need to deform */
3027  if (op->d.fetch.fixed && op->d.fetch.kind == &TTSOpsVirtual)
3028  return false;
3029 
3030  return true;
3031 }
ExprEvalOp
Definition: execExpr.h:66
@ EEOP_SCAN_FETCHSOME
Definition: execExpr.h:73
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:490
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:499
#define outerPlanState(node)
Definition: execnodes.h:1094
#define innerPlanState(node)
Definition: execnodes.h:1093
bool inneropsset
Definition: execnodes.h:1082
bool outeropsset
Definition: execnodes.h:1081
const TupleTableSlotOps * outerops
Definition: execnodes.h:1073
const TupleTableSlotOps * innerops
Definition: execnodes.h:1074
const TupleTableSlotOps * scanops
Definition: execnodes.h:1072
bool outeropsfixed
Definition: execnodes.h:1077
bool scanopsset
Definition: execnodes.h:1080
TupleDesc scandesc
Definition: execnodes.h:1047
bool scanopsfixed
Definition: execnodes.h:1076
bool inneropsfixed
Definition: execnodes.h:1078

References Assert(), ExprEvalStep::d, EEOP_INNER_FETCHSOME, EEOP_OUTER_FETCHSOME, EEOP_SCAN_FETCHSOME, ExecGetResultSlotOps(), ExecGetResultType(), ExprEvalStep::fetch, PlanState::innerops, PlanState::inneropsfixed, PlanState::inneropsset, innerPlanState, ExprEvalStep::opcode, PlanState::outerops, PlanState::outeropsfixed, PlanState::outeropsset, outerPlanState, PlanState::scandesc, PlanState::scanops, PlanState::scanopsfixed, PlanState::scanopsset, and TTSOpsVirtual.

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

◆ ExecInitCheck()

ExprState* ExecInitCheck ( List qual,
PlanState parent 
)

Definition at line 298 of file execExpr.c.

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

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

3386 {
3387  DomainConstraintRef *constraint_ref;
3388  Datum *domainval = NULL;
3389  bool *domainnull = NULL;
3390  ListCell *l;
3391 
3392  scratch->d.domaincheck.resulttype = ctest->resulttype;
3393  /* we'll allocate workspace only if needed */
3394  scratch->d.domaincheck.checkvalue = NULL;
3395  scratch->d.domaincheck.checknull = NULL;
3396 
3397  /*
3398  * Evaluate argument - it's fine to directly store it into resv/resnull,
3399  * if there's constraint failures there'll be errors, otherwise it's what
3400  * needs to be returned.
3401  */
3402  ExecInitExprRec(ctest->arg, state, resv, resnull);
3403 
3404  /*
3405  * Note: if the argument is of varlena type, it could be a R/W expanded
3406  * object. We want to return the R/W pointer as the final result, but we
3407  * have to pass a R/O pointer as the value to be tested by any functions
3408  * in check expressions. We don't bother to emit a MAKE_READONLY step
3409  * unless there's actually at least one check expression, though. Until
3410  * we've tested that, domainval/domainnull are NULL.
3411  */
3412 
3413  /*
3414  * Collect the constraints associated with the domain.
3415  *
3416  * Note: before PG v10 we'd recheck the set of constraints during each
3417  * evaluation of the expression. Now we bake them into the ExprState
3418  * during executor initialization. That means we don't need typcache.c to
3419  * provide compiled exprs.
3420  */
3421  constraint_ref = (DomainConstraintRef *)
3422  palloc(sizeof(DomainConstraintRef));
3424  constraint_ref,
3426  false);
3427 
3428  /*
3429  * Compile code to check each domain constraint. NOTNULL constraints can
3430  * just be applied on the resv/resnull value, but for CHECK constraints we
3431  * need more pushups.
3432  */
3433  foreach(l, constraint_ref->constraints)
3434  {
3436  Datum *save_innermost_domainval;
3437  bool *save_innermost_domainnull;
3438 
3439  scratch->d.domaincheck.constraintname = con->name;
3440 
3441  switch (con->constrainttype)
3442  {
3444  scratch->opcode = EEOP_DOMAIN_NOTNULL;
3445  ExprEvalPushStep(state, scratch);
3446  break;
3447  case DOM_CONSTRAINT_CHECK:
3448  /* Allocate workspace for CHECK output if we didn't yet */
3449  if (scratch->d.domaincheck.checkvalue == NULL)
3450  {
3451  scratch->d.domaincheck.checkvalue =
3452  (Datum *) palloc(sizeof(Datum));
3453  scratch->d.domaincheck.checknull =
3454  (bool *) palloc(sizeof(bool));
3455  }
3456 
3457  /*
3458  * If first time through, determine where CoerceToDomainValue
3459  * nodes should read from.
3460  */
3461  if (domainval == NULL)
3462  {
3463  /*
3464  * Since value might be read multiple times, force to R/O
3465  * - but only if it could be an expanded datum.
3466  */
3467  if (get_typlen(ctest->resulttype) == -1)
3468  {
3469  ExprEvalStep scratch2 = {0};
3470 
3471  /* Yes, so make output workspace for MAKE_READONLY */
3472  domainval = (Datum *) palloc(sizeof(Datum));
3473  domainnull = (bool *) palloc(sizeof(bool));
3474 
3475  /* Emit MAKE_READONLY */
3476  scratch2.opcode = EEOP_MAKE_READONLY;
3477  scratch2.resvalue = domainval;
3478  scratch2.resnull = domainnull;
3479  scratch2.d.make_readonly.value = resv;
3480  scratch2.d.make_readonly.isnull = resnull;
3481  ExprEvalPushStep(state, &scratch2);
3482  }
3483  else
3484  {
3485  /* No, so it's fine to read from resv/resnull */
3486  domainval = resv;
3487  domainnull = resnull;
3488  }
3489  }
3490 
3491  /*
3492  * Set up value to be returned by CoerceToDomainValue nodes.
3493  * We must save and restore innermost_domainval/null fields,
3494  * in case this node is itself within a check expression for
3495  * another domain.
3496  */
3497  save_innermost_domainval = state->innermost_domainval;
3498  save_innermost_domainnull = state->innermost_domainnull;
3499  state->innermost_domainval = domainval;
3500  state->innermost_domainnull = domainnull;
3501 
3502  /* evaluate check expression value */
3504  scratch->d.domaincheck.checkvalue,
3505  scratch->d.domaincheck.checknull);
3506 
3507  state->innermost_domainval = save_innermost_domainval;
3508  state->innermost_domainnull = save_innermost_domainnull;
3509 
3510  /* now test result */
3511  scratch->opcode = EEOP_DOMAIN_CHECK;
3512  ExprEvalPushStep(state, scratch);
3513 
3514  break;
3515  default:
3516  elog(ERROR, "unrecognized constraint type: %d",
3517  (int) con->constrainttype);
3518  break;
3519  }
3520  }
3521 }
@ EEOP_DOMAIN_CHECK
Definition: execExpr.h:232
@ EEOP_DOMAIN_NOTNULL
Definition: execExpr.h:229
@ EEOP_MAKE_READONLY
Definition: execExpr.h:167
@ DOM_CONSTRAINT_CHECK
Definition: execnodes.h:956
@ DOM_CONSTRAINT_NOTNULL
Definition: execnodes.h:955
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
void * palloc(Size size)
Definition: mcxt.c:1068
DomainConstraintType constrainttype
Definition: execnodes.h:962
struct ExprEvalStep::@52::@81 domaincheck
struct ExprEvalStep::@52::@67 make_readonly
void InitDomainConstraintRef(Oid type_id, DomainConstraintRef *ref, MemoryContext refctx, bool need_exprstate)
Definition: typcache.c:1305

References CoerceToDomain::arg, DomainConstraintState::check_expr, DomainConstraintRef::constraints, DomainConstraintState::constrainttype, CurrentMemoryContext, ExprEvalStep::d, DOM_CONSTRAINT_CHECK, DOM_CONSTRAINT_NOTNULL, ExprEvalStep::domaincheck, EEOP_DOMAIN_CHECK, EEOP_DOMAIN_NOTNULL, EEOP_MAKE_READONLY, elog, ERROR, ExecInitExprRec(), ExprEvalPushStep(), get_typlen(), InitDomainConstraintRef(), lfirst, ExprEvalStep::make_readonly, DomainConstraintState::name, ExprEvalStep::opcode, palloc(), ExprEvalStep::resnull, CoerceToDomain::resulttype, and ExprEvalStep::resvalue.

Referenced by ExecInitExprRec().

◆ ExecInitExpr()

◆ ExecInitExprInternal()

static ExprState* ExecInitExprInternal ( Expr node,
PlanState parent,
ParamListInfo  ext_params,
Datum caseval,
bool casenull 
)
static

Definition at line 92 of file execExpr.c.

94 {
96  ExprEvalStep scratch = {0};
97 
98  /* Special case: NULL expression produces a NULL ExprState pointer */
99  if (node == NULL)
100  return NULL;
101 
102  /* Initialize ExprState with empty step list */
104  state->expr = node;
105  state->parent = parent;
106  state->ext_params = ext_params;
107  state->innermost_caseval = caseval;
108  state->innermost_casenull = casenull;
109 
110  /* Insert EEOP_*_FETCHSOME steps as needed */
111  ExecInitExprSlots(state, (Node *) node);
112 
113  /* Compile the expression proper */
114  ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
115 
116  /* Finally, append a DONE step */
117  scratch.opcode = EEOP_DONE;
118  ExprEvalPushStep(state, &scratch);
119 
121 
122  return state;
123 }

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

Referenced by ExecInitExpr(), ExecInitExprWithCaseValue(), and ExecInitExprWithParams().

◆ ExecInitExprList()

List* ExecInitExprList ( List nodes,
PlanState parent 
)

Definition at line 318 of file execExpr.c.

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

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

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

◆ ExecInitExprRec()

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

Definition at line 900 of file execExpr.c.

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

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, WindowFuncExprState::aggfilter, WindowFunc::aggfilter, Aggref::aggno, ExprEvalStep::aggref, AggState::aggs, AND_EXPR, arg, FieldSelect::arg, FieldStore::arg, RelabelType::arg, CoerceViaIO::arg, ArrayCoerceExpr::arg, CaseExpr::arg, NullTest::arg, BooleanTest::arg, NullTest::argisrow, 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, check_stack_depth(), TypeCacheEntry::cmp_proc, JsonConstructorExpr::coercion, JsonExpr::coercions, RowExpr::colnames, GroupingFunc::cols, Const::constisnull, ExprEvalStep::constval, Const::constvalue, convert(), ExprEvalStep::convert_rowtype, ExprEvalStep::d, JsonBehavior::default_expr, CaseExpr::defresult, JsonPathVariableEvalContext::econtext, 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_IS_JSON, EEOP_JSON_CONSTRUCTOR, EEOP_JSONEXPR, EEOP_JUMP, EEOP_JUMP_IF_NOT_NULL, EEOP_JUMP_IF_NOT_TRUE, EEOP_MAKE_READONLY, EEOP_MINMAX, EEOP_NEXTVALUEEXPR, EEOP_NULLIF, EEOP_NULLTEST_ISNOTNULL, EEOP_NULLTEST_ISNULL, EEOP_NULLTEST_ROWISNOTNULL, EEOP_NULLTEST_ROWISNULL, EEOP_OUTER_SYSVAR, EEOP_OUTER_VAR, EEOP_PARAM_EXEC, EEOP_PARAM_EXTERN, EEOP_ROW, EEOP_ROWCOMPARE_FINAL, EEOP_ROWCOMPARE_STEP, EEOP_SCALARARRAYOP, EEOP_SCAN_SYSVAR, EEOP_SCAN_VAR, EEOP_SQLVALUEFUNCTION, EEOP_SUBPLAN, EEOP_WINDOW_FUNC, EEOP_XMLEXPR, ArrayExpr::element_typeid, ArrayExpr::elements, ArrayCoerceExpr::elemexpr, elog, ereport, errcode(), errmsg(), ERROR, JsonPathVariableEvalContext::estate, JsonPathVariableEvalContext::evaluated, ExecInitCoerceToDomain(), ExecInitExpr(), ExecInitExprList(), ExecInitExprWithCaseValue(), ExecInitFunc(), ExecInitSubPlan(), ExecInitSubscriptingRef(), ExecInitWholeRowVar(), ExecReadyExpr(), ExecTypeFromExprList(), ExecTypeSetColNames(), ExprState::expr, JsonIsPredicate::expr, JsonCoercion::expr, ExprEvalPushStep(), exprType(), exprTypmod(), ExprState::ext_params, FieldSelect::fieldnum, FieldStore::fieldnums, 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, ScalarArrayOpExpr::hashfuncid, i, InitFunctionCallInfoData, INNER_VAR, ExprState::innermost_casenull, ExprState::innermost_caseval, FuncExpr::inputcollid, OpExpr::inputcollid, ScalarArrayOpExpr::inputcollid, MinMaxExpr::inputcollid, RowCompareExpr::inputcollids, Int32GetDatum, InvalidAttrNumber, InvalidOid, InvokeFunctionExecuteHook, ExprEvalStep::iocoerce, IS_FALSE, ExprEvalStep::is_json, IS_NOT_FALSE, IS_NOT_NULL, IS_NOT_TRUE, IS_NOT_UNKNOWN, IS_NULL, IS_TRUE, IS_UNKNOWN, IsA, NullableDatum::isnull, JsonPathVariableEvalContext::isnull, JS_FORMAT_JSONB, JSCTOR_JSON_PARSE, JSCTOR_JSON_SCALAR, JSCTOR_JSON_SERIALIZE, json_categorize_type(), ExprEvalStep::json_constructor, jsonb_categorize_type(), ExprEvalStep::jsonexpr, ExprEvalStep::jump, lappend(), lappend_int(), RowCompareExpr::largs, lfirst, lfirst_int, lfirst_node, lfirst_oid, linitial, list_length(), lookup_rowtype_tupdesc(), lookup_rowtype_tupdesc_copy(), lookup_type_cache(), lsecond, ExprEvalStep::make_readonly, makeNode, makeNullConst(), Max, JsonPathVariableEvalContext::mcxt, ExprEvalStep::minmax, MinMaxExpr::minmaxtype, ArrayExpr::multidims, JsonPathVariableEvalContext::name, XmlExpr::named_args, TupleDescData::natts, ScalarArrayOpExpr::negfuncid, FieldStore::newvals, ExprEvalStep::nextvalueexpr, NIL, nodeTag, NOT_EXPR, JsonItemCoercions::null, ExprEvalStep::nulltest_row, NullTest::nulltesttype, WindowAggState::numaggs, WindowAggState::numfuncs, OBJECT_FUNCTION, ObjectIdGetDatum, OidIsValid, JsonExpr::omit_quotes, JsonExpr::on_empty, JsonExpr::on_error, MinMaxExpr::op, ExprEvalStep::opcode, RowCompareExpr::opfamilies, OpExpr::opfuncid, ScalarArrayOpExpr::opfuncid, RowCompareExpr::opnos, OR_EXPR, OUTER_VAR, palloc(), palloc0(), ExprEvalStep::param, PARAM_EXEC, PARAM_EXTERN, ParamListInfoData::paramCompile, Param::paramid, Param::paramkind, Param::paramtype, ExprState::parent, JsonExpr::passing_names, JsonExpr::passing_values, JsonExpr::path_spec, pg_proc_aclcheck(), pstrdup(), RowCompareExpr::rargs, JsonValueExpr::raw_expr, RowCompareExpr::rctype, ReleaseTupleDesc, ExprEvalStep::resnull, ExprState::resnull, JsonExpr::result_coercion, FieldSelect::resulttype, FieldStore::resulttype, CoerceViaIO::resulttype, ArrayCoerceExpr::resulttype, ExprEvalStep::resvalue, ExprState::resvalue, JsonConstructorExpr::returning, JsonExpr::returning, ExprEvalStep::row, RowExpr::row_typeid, ExprEvalStep::rowcompare_final, ExprEvalStep::rowcompare_step, ExprEvalStep::scalararrayop, NextValueExpr::seqid, SizeForFunctionCallInfo, ExprEvalStep::sqlvaluefunction, ExprState::steps, ExprState::steps_len, ExprEvalStep::subplan, String::sval, T_Aggref, T_ArrayCoerceExpr, T_ArrayExpr, T_BooleanTest, T_BoolExpr, T_CaseExpr, T_CaseTestExpr, T_CoalesceExpr, T_CoerceToDomain, T_CoerceToDomainValue, T_CoerceViaIO, T_Const, T_ConvertRowtypeExpr, T_CurrentOfExpr, T_DistinctExpr, T_FieldSelect, T_FieldStore, T_FuncExpr, T_GroupingFunc, T_JsonConstructorExpr, T_JsonExpr, T_JsonIsPredicate, T_JsonValueExpr, T_MinMaxExpr, T_NextValueExpr, T_NullIfExpr, T_NullTest, T_OpExpr, T_Param, T_RelabelType, T_RowCompareExpr, T_RowExpr, T_ScalarArrayOpExpr, T_SQLValueFunction, T_SubPlan, T_SubscriptingRef, T_Var, T_WindowFunc, T_XmlExpr, TupleDescAttr, JsonConstructorExpr::type, TYPECACHE_CMP_PROC, NextValueExpr::typeId, JsonReturning::typid, JsonPathVariableEvalContext::typid, JsonPathVariableEvalContext::typmod, JsonConstructorExpr::unique, ScalarArrayOpExpr::useOr, NullableDatum::value, JsonPathVariableEvalContext::value, values, ExprEvalStep::var, JsonCoercion::via_io, WindowFuncExprState::wfunc, WindowFunc::winagg, ExprEvalStep::window_func, and ExprEvalStep::xmlexpr.

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

◆ ExecInitExprSlots()

static void ExecInitExprSlots ( ExprState state,
Node node 
)
static

Definition at line 2824 of file execExpr.c.

2825 {
2826  LastAttnumInfo info = {0, 0, 0};
2827 
2828  /*
2829  * Figure out which attributes we're going to need.
2830  */
2831  get_last_attnums_walker(node, &info);
2832 
2833  ExecPushExprSlots(state, &info);
2834 }

References ExecPushExprSlots(), and get_last_attnums_walker().

Referenced by ExecBuildProjectionInfo(), ExecInitExprInternal(), and ExecInitQual().

◆ ExecInitExprWithCaseValue()

ExprState* ExecInitExprWithCaseValue ( Expr node,
PlanState parent,
Datum caseval,
bool casenull 
)

Definition at line 184 of file execExpr.c.

186 {
187  return ExecInitExprInternal(node, parent, NULL, caseval, casenull);
188 }

References ExecInitExprInternal().

Referenced by ExecInitExprRec(), and JsonTableInitOpaque().

◆ ExecInitExprWithParams()

ExprState* ExecInitExprWithParams ( Expr node,
ParamListInfo  ext_params 
)

Definition at line 172 of file execExpr.c.

173 {
174  return ExecInitExprInternal(node, NULL, ext_params, NULL, NULL);
175 }

References ExecInitExprInternal().

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

2721 {
2722  int nargs = list_length(args);
2723  AclResult aclresult;
2724  FmgrInfo *flinfo;
2725  FunctionCallInfo fcinfo;
2726  int argno;
2727  ListCell *lc;
2728 
2729  /* Check permission to call function */
2730  aclresult = pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE);
2731  if (aclresult != ACLCHECK_OK)
2732  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(funcid));
2733  InvokeFunctionExecuteHook(funcid);
2734 
2735  /*
2736  * Safety check on nargs. Under normal circumstances this should never
2737  * fail, as parser should check sooner. But possibly it might fail if
2738  * server has been compiled with FUNC_MAX_ARGS smaller than some functions
2739  * declared in pg_proc?
2740  */
2741  if (nargs > FUNC_MAX_ARGS)
2742  ereport(ERROR,
2743  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2744  errmsg_plural("cannot pass more than %d argument to a function",
2745  "cannot pass more than %d arguments to a function",
2746  FUNC_MAX_ARGS,
2747  FUNC_MAX_ARGS)));
2748 
2749  /* Allocate function lookup data and parameter workspace for this call */
2750  scratch->d.func.finfo = palloc0(sizeof(FmgrInfo));
2751  scratch->d.func.fcinfo_data = palloc0(SizeForFunctionCallInfo(nargs));
2752  flinfo = scratch->d.func.finfo;
2753  fcinfo = scratch->d.func.fcinfo_data;
2754 
2755  /* Set up the primary fmgr lookup information */
2756  fmgr_info(funcid, flinfo);
2757  fmgr_info_set_expr((Node *) node, flinfo);
2758 
2759  /* Initialize function call parameter structure too */
2760  InitFunctionCallInfoData(*fcinfo, flinfo,
2761  nargs, inputcollid, NULL, NULL);
2762 
2763  /* Keep extra copies of this info to save an indirection at runtime */
2764  scratch->d.func.fn_addr = flinfo->fn_addr;
2765  scratch->d.func.nargs = nargs;
2766 
2767  /* We only support non-set functions here */
2768  if (flinfo->fn_retset)
2769  ereport(ERROR,
2770  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2771  errmsg("set-valued function called in context that cannot accept a set"),
2772  state->parent ?
2773  executor_errposition(state->parent->state,
2774  exprLocation((Node *) node)) : 0));
2775 
2776  /* Build code to evaluate arguments directly into the fcinfo struct */
2777  argno = 0;
2778  foreach(lc, args)
2779  {
2780  Expr *arg = (Expr *) lfirst(lc);
2781 
2782  if (IsA(arg, Const))
2783  {
2784  /*
2785  * Don't evaluate const arguments every round; especially
2786  * interesting for constants in comparisons.
2787  */
2788  Const *con = (Const *) arg;
2789 
2790  fcinfo->args[argno].value = con->constvalue;
2791  fcinfo->args[argno].isnull = con->constisnull;
2792  }
2793  else
2794  {
2796  &fcinfo->args[argno].value,
2797  &fcinfo->args[argno].isnull);
2798  }
2799  argno++;
2800  }
2801 
2802  /* Insert appropriate opcode depending on strictness and stats level */
2803  if (pgstat_track_functions <= flinfo->fn_stats)
2804  {
2805  if (flinfo->fn_strict && nargs > 0)
2806  scratch->opcode = EEOP_FUNCEXPR_STRICT;
2807  else
2808  scratch->opcode = EEOP_FUNCEXPR;
2809  }
2810  else
2811  {
2812  if (flinfo->fn_strict && nargs > 0)
2814  else
2815  scratch->opcode = EEOP_FUNCEXPR_FUSAGE;
2816  }
2817 }
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1014
@ EEOP_FUNCEXPR_STRICT_FUSAGE
Definition: execExpr.h:113
@ EEOP_FUNCEXPR_STRICT
Definition: execExpr.h:111
@ EEOP_FUNCEXPR
Definition: execExpr.h:110
@ EEOP_FUNCEXPR_FUSAGE
Definition: execExpr.h:112
int executor_errposition(EState *estate, int location)
Definition: execUtils.c:898
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1343
#define FUNC_MAX_ARGS
bool fn_retset
Definition: fmgr.h:62

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, arg, generate_unaccent_rules::args, FunctionCallInfoBaseData::args, Const::constisnull, Const::constvalue, ExprEvalStep::d, EEOP_FUNCEXPR, EEOP_FUNCEXPR_FUSAGE, EEOP_FUNCEXPR_STRICT, EEOP_FUNCEXPR_STRICT_FUSAGE, ereport, errcode(), errmsg(), errmsg_plural(), ERROR, ExecInitExprRec(), executor_errposition(), exprLocation(), fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_addr, FmgrInfo::fn_retset, FmgrInfo::fn_strict, ExprEvalStep::func, FUNC_MAX_ARGS, get_func_name(), GetUserId(), InitFunctionCallInfoData, InvokeFunctionExecuteHook, IsA, NullableDatum::isnull, lfirst, list_length(), OBJECT_FUNCTION, ExprEvalStep::opcode, palloc0(), pg_proc_aclcheck(), SizeForFunctionCallInfo, and NullableDatum::value.

Referenced by ExecInitExprRec().

◆ ExecInitQual()

ExprState* ExecInitQual ( List qual,
PlanState parent 
)

Definition at line 209 of file execExpr.c.

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

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

Referenced by CopyFrom(), ExecInitAgg(), ExecInitBitmapHeapScan(), ExecInitCteScan(), ExecInitCustomScan(), ExecInitForeignScan(), ExecInitFunctionScan(), ExecInitGroup(), ExecInitHashJoin(), ExecInitIndexOnlyScan(), ExecInitIndexScan(), 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 3111 of file execExpr.c.

3113 {
3114  bool isAssignment = (sbsref->refassgnexpr != NULL);
3115  int nupper = list_length(sbsref->refupperindexpr);
3116  int nlower = list_length(sbsref->reflowerindexpr);
3117  const SubscriptRoutines *sbsroutines;
3118  SubscriptingRefState *sbsrefstate;
3119  SubscriptExecSteps methods;
3120  char *ptr;
3121  List *adjust_jumps = NIL;
3122  ListCell *lc;
3123  int i;
3124 
3125  /* Look up the subscripting support methods */
3126  sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype, NULL);
3127  if (!sbsroutines)
3128  ereport(ERROR,
3129  (errcode(ERRCODE_DATATYPE_MISMATCH),
3130  errmsg("cannot subscript type %s because it does not support subscripting",
3131  format_type_be(sbsref->refcontainertype)),
3132  state->parent ?
3133  executor_errposition(state->parent->state,
3134  exprLocation((Node *) sbsref)) : 0));
3135 
3136  /* Allocate sbsrefstate, with enough space for per-subscript arrays too */
3137  sbsrefstate = palloc0(MAXALIGN(sizeof(SubscriptingRefState)) +
3138  (nupper + nlower) * (sizeof(Datum) +
3139  2 * sizeof(bool)));
3140 
3141  /* Fill constant fields of SubscriptingRefState */
3142  sbsrefstate->isassignment = isAssignment;
3143  sbsrefstate->numupper = nupper;
3144  sbsrefstate->numlower = nlower;
3145  /* Set up per-subscript arrays */
3146  ptr = ((char *) sbsrefstate) + MAXALIGN(sizeof(SubscriptingRefState));
3147  sbsrefstate->upperindex = (Datum *) ptr;
3148  ptr += nupper * sizeof(Datum);
3149  sbsrefstate->lowerindex = (Datum *) ptr;
3150  ptr += nlower * sizeof(Datum);
3151  sbsrefstate->upperprovided = (bool *) ptr;
3152  ptr += nupper * sizeof(bool);
3153  sbsrefstate->lowerprovided = (bool *) ptr;
3154  ptr += nlower * sizeof(bool);
3155  sbsrefstate->upperindexnull = (bool *) ptr;
3156  ptr += nupper * sizeof(bool);
3157  sbsrefstate->lowerindexnull = (bool *) ptr;
3158  /* ptr += nlower * sizeof(bool); */
3159 
3160  /*
3161  * Let the container-type-specific code have a chance. It must fill the
3162  * "methods" struct with function pointers for us to possibly use in
3163  * execution steps below; and it can optionally set up some data pointed
3164  * to by the workspace field.
3165  */
3166  memset(&methods, 0, sizeof(methods));
3167  sbsroutines->exec_setup(sbsref, sbsrefstate, &methods);
3168 
3169  /*
3170  * Evaluate array input. It's safe to do so into resv/resnull, because we
3171  * won't use that as target for any of the other subexpressions, and it'll
3172  * be overwritten by the final EEOP_SBSREF_FETCH/ASSIGN step, which is
3173  * pushed last.
3174  */
3175  ExecInitExprRec(sbsref->refexpr, state, resv, resnull);
3176 
3177  /*
3178  * If refexpr yields NULL, and the operation should be strict, then result
3179  * is NULL. We can implement this with just JUMP_IF_NULL, since we
3180  * evaluated the array into the desired target location.
3181  */
3182  if (!isAssignment && sbsroutines->fetch_strict)
3183  {
3184  scratch->opcode = EEOP_JUMP_IF_NULL;
3185  scratch->d.jump.jumpdone = -1; /* adjust later */
3186  ExprEvalPushStep(state, scratch);
3187  adjust_jumps = lappend_int(adjust_jumps,
3188  state->steps_len - 1);
3189  }
3190 
3191  /* Evaluate upper subscripts */
3192  i = 0;
3193  foreach(lc, sbsref->refupperindexpr)
3194  {
3195  Expr *e = (Expr *) lfirst(lc);
3196 
3197  /* When slicing, individual subscript bounds can be omitted */
3198  if (!e)
3199  {
3200  sbsrefstate->upperprovided[i] = false;
3201  sbsrefstate->upperindexnull[i] = true;
3202  }
3203  else
3204  {
3205  sbsrefstate->upperprovided[i] = true;
3206  /* Each subscript is evaluated into appropriate array entry */
3208  &sbsrefstate->upperindex[i],
3209  &sbsrefstate->upperindexnull[i]);
3210  }
3211  i++;
3212  }
3213 
3214  /* Evaluate lower subscripts similarly */
3215  i = 0;
3216  foreach(lc, sbsref->reflowerindexpr)
3217  {
3218  Expr *e = (Expr *) lfirst(lc);
3219 
3220  /* When slicing, individual subscript bounds can be omitted */
3221  if (!e)
3222  {
3223  sbsrefstate->lowerprovided[i] = false;
3224  sbsrefstate->lowerindexnull[i] = true;
3225  }
3226  else
3227  {
3228  sbsrefstate->lowerprovided[i] = true;
3229  /* Each subscript is evaluated into appropriate array entry */
3231  &sbsrefstate->lowerindex[i],
3232  &sbsrefstate->lowerindexnull[i]);
3233  }
3234  i++;
3235  }
3236 
3237  /* SBSREF_SUBSCRIPTS checks and converts all the subscripts at once */
3238  if (methods.sbs_check_subscripts)
3239  {
3240  scratch->opcode = EEOP_SBSREF_SUBSCRIPTS;
3241  scratch->d.sbsref_subscript.subscriptfunc = methods.sbs_check_subscripts;
3242  scratch->d.sbsref_subscript.state = sbsrefstate;
3243  scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */
3244  ExprEvalPushStep(state, scratch);
3245  adjust_jumps = lappend_int(adjust_jumps,
3246  state->steps_len - 1);
3247  }
3248 
3249  if (isAssignment)
3250  {
3251  Datum *save_innermost_caseval;
3252  bool *save_innermost_casenull;
3253 
3254  /* Check for unimplemented methods */
3255  if (!methods.sbs_assign)
3256  ereport(ERROR,
3257  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3258  errmsg("type %s does not support subscripted assignment",
3259  format_type_be(sbsref->refcontainertype))));
3260 
3261  /*
3262  * We might have a nested-assignment situation, in which the
3263  * refassgnexpr is itself a FieldStore or SubscriptingRef that needs
3264  * to obtain and modify the previous value of the array element or
3265  * slice being replaced. If so, we have to extract that value from
3266  * the array and pass it down via the CaseTestExpr mechanism. It's
3267  * safe to reuse the CASE mechanism because there cannot be a CASE
3268  * between here and where the value would be needed, and an array
3269  * assignment can't be within a CASE either. (So saving and restoring
3270  * innermost_caseval is just paranoia, but let's do it anyway.)
3271  *
3272  * Since fetching the old element might be a nontrivial expense, do it
3273  * only if the argument actually needs it.
3274  */
3276  {
3277  if (!methods.sbs_fetch_old)
3278  ereport(ERROR,
3279  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3280  errmsg("type %s does not support subscripted assignment",
3281  format_type_be(sbsref->refcontainertype))));
3282  scratch->opcode = EEOP_SBSREF_OLD;
3283  scratch->d.sbsref.subscriptfunc = methods.sbs_fetch_old;
3284  scratch->d.sbsref.state = sbsrefstate;
3285  ExprEvalPushStep(state, scratch);
3286  }
3287 
3288  /* SBSREF_OLD puts extracted value into prevvalue/prevnull */
3289  save_innermost_caseval = state->innermost_caseval;
3290  save_innermost_casenull = state->innermost_casenull;
3291  state->innermost_caseval = &sbsrefstate->prevvalue;
3292  state->innermost_casenull = &sbsrefstate->prevnull;
3293 
3294  /* evaluate replacement value into replacevalue/replacenull */
3296  &sbsrefstate->replacevalue, &sbsrefstate->replacenull);
3297 
3298  state->innermost_caseval = save_innermost_caseval;
3299  state->innermost_casenull = save_innermost_casenull;
3300 
3301  /* and perform the assignment */
3302  scratch->opcode = EEOP_SBSREF_ASSIGN;
3303  scratch->d.sbsref.subscriptfunc = methods.sbs_assign;
3304  scratch->d.sbsref.state = sbsrefstate;
3305  ExprEvalPushStep(state, scratch);
3306  }
3307  else
3308  {
3309  /* array fetch is much simpler */
3310  scratch->opcode = EEOP_SBSREF_FETCH;
3311  scratch->d.sbsref.subscriptfunc = methods.sbs_fetch;
3312  scratch->d.sbsref.state = sbsrefstate;
3313  ExprEvalPushStep(state, scratch);
3314  }
3315 
3316  /* adjust jump targets */
3317  foreach(lc, adjust_jumps)
3318  {
3319  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
3320 
3321  if (as->opcode == EEOP_SBSREF_SUBSCRIPTS)
3322  {
3323  Assert(as->d.sbsref_subscript.jumpdone == -1);
3324  as->d.sbsref_subscript.jumpdone = state->steps_len;
3325  }
3326  else
3327  {
3329  Assert(as->d.jump.jumpdone == -1);
3330  as->d.jump.jumpdone = state->steps_len;
3331  }
3332  }
3333 }
#define MAXALIGN(LEN)
Definition: c.h:768
unsigned char bool
Definition: c.h:402
static bool isAssignmentIndirectionExpr(Expr *expr)
Definition: execExpr.c:3353
@ EEOP_SBSREF_SUBSCRIPTS
Definition: execExpr.h:210
@ EEOP_SBSREF_FETCH
Definition: execExpr.h:223
@ EEOP_SBSREF_ASSIGN
Definition: execExpr.h:220
@ EEOP_SBSREF_OLD
Definition: execExpr.h:217
@ EEOP_JUMP_IF_NULL
Definition: execExpr.h:140
const struct SubscriptRoutines * getSubscriptingRoutines(Oid typid, Oid *typelemp)
Definition: lsyscache.c:3087
struct ExprEvalStep::@52::@79 sbsref_subscript
struct ExprEvalStep::@52::@80 sbsref
ExecEvalSubroutine sbs_fetch_old
Definition: execExpr.h:782
ExecEvalBoolSubroutine sbs_check_subscripts
Definition: execExpr.h:779
ExecEvalSubroutine sbs_assign
Definition: execExpr.h:781
ExecEvalSubroutine sbs_fetch
Definition: execExpr.h:780
SubscriptExecSetup exec_setup
Definition: subscripting.h:161