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 "optimizer/optimizer.h"
#include "pgstat.h"
#include "utils/acl.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/typcache.h"
Include dependency graph for execExpr.c:

Go to the source code of this file.

Data Structures

struct  LastAttnumInfo
 

Typedefs

typedef struct LastAttnumInfo LastAttnumInfo
 

Functions

static void ExecReadyExpr (ExprState *state)
 
static void ExecInitExprRec (Expr *node, ExprState *state, Datum *resv, bool *resnull)
 
static void ExecInitFunc (ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, Oid inputcollid, ExprState *state)
 
static void ExecInitExprSlots (ExprState *state, Node *node)
 
static void ExecPushExprSlots (ExprState *state, LastAttnumInfo *info)
 
static bool get_last_attnums_walker (Node *node, LastAttnumInfo *info)
 
static bool ExecComputeSlotInfo (ExprState *state, ExprEvalStep *op)
 
static void ExecInitWholeRowVar (ExprEvalStep *scratch, Var *variable, ExprState *state)
 
static void ExecInitSubscriptingRef (ExprEvalStep *scratch, SubscriptingRef *sbsref, ExprState *state, Datum *resv, bool *resnull)
 
static bool isAssignmentIndirectionExpr (Expr *expr)
 
static void ExecInitCoerceToDomain (ExprEvalStep *scratch, CoerceToDomain *ctest, ExprState *state, Datum *resv, bool *resnull)
 
static void ExecBuildAggTransCall (ExprState *state, AggState *aggstate, ExprEvalStep *scratch, FunctionCallInfo fcinfo, AggStatePerTrans pertrans, int transno, int setno, int setoff, bool ishash, bool nullcheck)
 
ExprStateExecInitExpr (Expr *node, PlanState *parent)
 
ExprStateExecInitExprWithParams (Expr *node, ParamListInfo ext_params)
 
ExprStateExecInitQual (List *qual, PlanState *parent)
 
ExprStateExecInitCheck (List *qual, PlanState *parent)
 
ListExecInitExprList (List *nodes, PlanState *parent)
 
ProjectionInfoExecBuildProjectionInfo (List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
 
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)
 

Typedef Documentation

◆ LastAttnumInfo

Function Documentation

◆ ExecBuildAggTrans()

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

Definition at line 2913 of file execExpr.c.

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

Referenced by ExecInitAgg(), and hashagg_recompile_expressions().

2915 {
2917  PlanState *parent = &aggstate->ss.ps;
2918  ExprEvalStep scratch = {0};
2919  bool isCombine = DO_AGGSPLIT_COMBINE(aggstate->aggsplit);
2920  LastAttnumInfo deform = {0, 0, 0};
2921 
2922  state->expr = (Expr *) aggstate;
2923  state->parent = parent;
2924 
2925  scratch.resvalue = &state->resvalue;
2926  scratch.resnull = &state->resnull;
2927 
2928  /*
2929  * First figure out which slots, and how many columns from each, we're
2930  * going to need.
2931  */
2932  for (int transno = 0; transno < aggstate->numtrans; transno++)
2933  {
2934  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
2935 
2937  &deform);
2938  get_last_attnums_walker((Node *) pertrans->aggref->args,
2939  &deform);
2941  &deform);
2943  &deform);
2945  &deform);
2946  }
2947  ExecPushExprSlots(state, &deform);
2948 
2949  /*
2950  * Emit instructions for each transition value / grouping set combination.
2951  */
2952  for (int transno = 0; transno < aggstate->numtrans; transno++)
2953  {
2954  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
2955  FunctionCallInfo trans_fcinfo = pertrans->transfn_fcinfo;
2956  List *adjust_bailout = NIL;
2957  NullableDatum *strictargs = NULL;
2958  bool *strictnulls = NULL;
2959  int argno;
2960  ListCell *bail;
2961 
2962  /*
2963  * If filter present, emit. Do so before evaluating the input, to
2964  * avoid potentially unneeded computations, or even worse, unintended
2965  * side-effects. When combining, all the necessary filtering has
2966  * already been done.
2967  */
2968  if (pertrans->aggref->aggfilter && !isCombine)
2969  {
2970  /* evaluate filter expression */
2971  ExecInitExprRec(pertrans->aggref->aggfilter, state,
2972  &state->resvalue, &state->resnull);
2973  /* and jump out if false */
2974  scratch.opcode = EEOP_JUMP_IF_NOT_TRUE;
2975  scratch.d.jump.jumpdone = -1; /* adjust later */
2976  ExprEvalPushStep(state, &scratch);
2977  adjust_bailout = lappend_int(adjust_bailout,
2978  state->steps_len - 1);
2979  }
2980 
2981  /*
2982  * Evaluate arguments to aggregate/combine function.
2983  */
2984  argno = 0;
2985  if (isCombine)
2986  {
2987  /*
2988  * Combining two aggregate transition values. Instead of directly
2989  * coming from a tuple the input is a, potentially deserialized,
2990  * transition value.
2991  */
2992  TargetEntry *source_tle;
2993 
2994  Assert(pertrans->numSortCols == 0);
2995  Assert(list_length(pertrans->aggref->args) == 1);
2996 
2997  strictargs = trans_fcinfo->args + 1;
2998  source_tle = (TargetEntry *) linitial(pertrans->aggref->args);
2999 
3000  /*
3001  * deserialfn_oid will be set if we must deserialize the input
3002  * state before calling the combine function.
3003  */
3004  if (!OidIsValid(pertrans->deserialfn_oid))
3005  {
3006  /*
3007  * Start from 1, since the 0th arg will be the transition
3008  * value
3009  */
3010  ExecInitExprRec(source_tle->expr, state,
3011  &trans_fcinfo->args[argno + 1].value,
3012  &trans_fcinfo->args[argno + 1].isnull);
3013  }
3014  else
3015  {
3016  FunctionCallInfo ds_fcinfo = pertrans->deserialfn_fcinfo;
3017 
3018  /* evaluate argument */
3019  ExecInitExprRec(source_tle->expr, state,
3020  &ds_fcinfo->args[0].value,
3021  &ds_fcinfo->args[0].isnull);
3022 
3023  /* Dummy second argument for type-safety reasons */
3024  ds_fcinfo->args[1].value = PointerGetDatum(NULL);
3025  ds_fcinfo->args[1].isnull = false;
3026 
3027  /*
3028  * Don't call a strict deserialization function with NULL
3029  * input
3030  */
3031  if (pertrans->deserialfn.fn_strict)
3033  else
3034  scratch.opcode = EEOP_AGG_DESERIALIZE;
3035 
3036  scratch.d.agg_deserialize.fcinfo_data = ds_fcinfo;
3037  scratch.d.agg_deserialize.jumpnull = -1; /* adjust later */
3038  scratch.resvalue = &trans_fcinfo->args[argno + 1].value;
3039  scratch.resnull = &trans_fcinfo->args[argno + 1].isnull;
3040 
3041  ExprEvalPushStep(state, &scratch);
3042  adjust_bailout = lappend_int(adjust_bailout,
3043  state->steps_len - 1);
3044 
3045  /* restore normal settings of scratch fields */
3046  scratch.resvalue = &state->resvalue;
3047  scratch.resnull = &state->resnull;
3048  }
3049  argno++;
3050  }
3051  else if (pertrans->numSortCols == 0)
3052  {
3053  ListCell *arg;
3054 
3055  /*
3056  * Normal transition function without ORDER BY / DISTINCT.
3057  */
3058  strictargs = trans_fcinfo->args + 1;
3059 
3060  foreach(arg, pertrans->aggref->args)
3061  {
3062  TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3063 
3064  /*
3065  * Start from 1, since the 0th arg will be the transition
3066  * value
3067  */
3068  ExecInitExprRec(source_tle->expr, state,
3069  &trans_fcinfo->args[argno + 1].value,
3070  &trans_fcinfo->args[argno + 1].isnull);
3071  argno++;
3072  }
3073  }
3074  else if (pertrans->numInputs == 1)
3075  {
3076  /*
3077  * DISTINCT and/or ORDER BY case, with a single column sorted on.
3078  */
3079  TargetEntry *source_tle =
3080  (TargetEntry *) linitial(pertrans->aggref->args);
3081 
3082  Assert(list_length(pertrans->aggref->args) == 1);
3083 
3084  ExecInitExprRec(source_tle->expr, state,
3085  &state->resvalue,
3086  &state->resnull);
3087  strictnulls = &state->resnull;
3088  argno++;
3089  }
3090  else
3091  {
3092  /*
3093  * DISTINCT and/or ORDER BY case, with multiple columns sorted on.
3094  */
3095  Datum *values = pertrans->sortslot->tts_values;
3096  bool *nulls = pertrans->sortslot->tts_isnull;
3097  ListCell *arg;
3098 
3099  strictnulls = nulls;
3100 
3101  foreach(arg, pertrans->aggref->args)
3102  {
3103  TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3104 
3105  ExecInitExprRec(source_tle->expr, state,
3106  &values[argno], &nulls[argno]);
3107  argno++;
3108  }
3109  }
3110  Assert(pertrans->numInputs == argno);
3111 
3112  /*
3113  * For a strict transfn, nothing happens when there's a NULL input; we
3114  * just keep the prior transValue. This is true for both plain and
3115  * sorted/distinct aggregates.
3116  */
3117  if (trans_fcinfo->flinfo->fn_strict && pertrans->numTransInputs > 0)
3118  {
3119  if (strictnulls)
3121  else
3123  scratch.d.agg_strict_input_check.nulls = strictnulls;
3124  scratch.d.agg_strict_input_check.args = strictargs;
3125  scratch.d.agg_strict_input_check.jumpnull = -1; /* adjust later */
3126  scratch.d.agg_strict_input_check.nargs = pertrans->numTransInputs;
3127  ExprEvalPushStep(state, &scratch);
3128  adjust_bailout = lappend_int(adjust_bailout,
3129  state->steps_len - 1);
3130  }
3131 
3132  /*
3133  * Call transition function (once for each concurrently evaluated
3134  * grouping set). Do so for both sort and hash based computations, as
3135  * applicable.
3136  */
3137  if (doSort)
3138  {
3139  int processGroupingSets = Max(phase->numsets, 1);
3140  int setoff = 0;
3141 
3142  for (int setno = 0; setno < processGroupingSets; setno++)
3143  {
3144  ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3145  pertrans, transno, setno, setoff, false,
3146  nullcheck);
3147  setoff++;
3148  }
3149  }
3150 
3151  if (doHash)
3152  {
3153  int numHashes = aggstate->num_hashes;
3154  int setoff;
3155 
3156  /* in MIXED mode, there'll be preceding transition values */
3157  if (aggstate->aggstrategy != AGG_HASHED)
3158  setoff = aggstate->maxsets;
3159  else
3160  setoff = 0;
3161 
3162  for (int setno = 0; setno < numHashes; setno++)
3163  {
3164  ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3165  pertrans, transno, setno, setoff, true,
3166  nullcheck);
3167  setoff++;
3168  }
3169  }
3170 
3171  /* adjust early bail out jump target(s) */
3172  foreach(bail, adjust_bailout)
3173  {
3174  ExprEvalStep *as = &state->steps[lfirst_int(bail)];
3175 
3176  if (as->opcode == EEOP_JUMP_IF_NOT_TRUE)
3177  {
3178  Assert(as->d.jump.jumpdone == -1);
3179  as->d.jump.jumpdone = state->steps_len;
3180  }
3181  else if (as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_ARGS ||
3183  {
3184  Assert(as->d.agg_strict_input_check.jumpnull == -1);
3185  as->d.agg_strict_input_check.jumpnull = state->steps_len;
3186  }
3187  else if (as->opcode == EEOP_AGG_STRICT_DESERIALIZE)
3188  {
3189  Assert(as->d.agg_deserialize.jumpnull == -1);
3190  as->d.agg_deserialize.jumpnull = state->steps_len;
3191  }
3192  else
3193  Assert(false);
3194  }
3195  }
3196 
3197  scratch.resvalue = NULL;
3198  scratch.resnull = NULL;
3199  scratch.opcode = EEOP_DONE;
3200  ExprEvalPushStep(state, &scratch);
3201 
3202  ExecReadyExpr(state);
3203 
3204  return state;
3205 }
List * aggdistinct
Definition: primnodes.h:327
#define NIL
Definition: pg_list.h:65
struct ExprEvalStep::@51::@89 agg_strict_input_check
struct PlanState * parent
Definition: execnodes.h:107
Datum * resvalue
Definition: execExpr.h:252
#define PointerGetDatum(X)
Definition: postgres.h:556
struct ExprEvalStep * steps
Definition: execnodes.h:84
ScanState ss
Definition: execnodes.h:2132
bool * resnull
Definition: execExpr.h:253
Definition: nodes.h:527
AggSplit aggsplit
Definition: execnodes.h:2137
List * args
Definition: primnodes.h:325
Datum * tts_values
Definition: tuptable.h:126
AggStatePerTrans pertrans
Definition: execnodes.h:2142
#define OidIsValid(objectId)
Definition: c.h:706
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:789
FunctionCallInfo transfn_fcinfo
Definition: nodeAgg.h:162
int numtrans
Definition: execnodes.h:2135
Aggref * aggref
Definition: nodeAgg.h:44
PlanState ps
Definition: execnodes.h:1317
int maxsets
Definition: execnodes.h:2162
#define linitial(l)
Definition: pg_list.h:174
AggStrategy aggstrategy
Definition: execnodes.h:2136
bool fn_strict
Definition: fmgr.h:61
bool resnull
Definition: execnodes.h:71
Expr * expr
Definition: execnodes.h:93
#define lfirst_int(lc)
Definition: pg_list.h:170
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
bool * tts_isnull
Definition: tuptable.h:128
List * aggorder
Definition: primnodes.h:326
List * aggdirectargs
Definition: primnodes.h:324
Datum value
Definition: postgres.h:378
List * lappend_int(List *list, int datum)
Definition: list.c:339
union ExprEvalStep::@51 d
static void ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
Definition: execExpr.c:2253
int num_hashes
Definition: execnodes.h:2173
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:645
uintptr_t Datum
Definition: postgres.h:367
FmgrInfo * flinfo
Definition: fmgr.h:87
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2104
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:628
FmgrInfo deserialfn
Definition: nodeAgg.h:87
#define Max(x, y)
Definition: c.h:976
#define makeNode(_type_)
Definition: nodes.h:575
#define Assert(condition)
Definition: c.h:800
#define lfirst(lc)
Definition: pg_list.h:169
FunctionCallInfo deserialfn_fcinfo
Definition: nodeAgg.h:167
Definition: regguts.h:298
intptr_t opcode
Definition: execExpr.h:249
Expr * expr
Definition: primnodes.h:1422
static int list_length(const List *l)
Definition: pg_list.h:149
Expr * aggfilter
Definition: primnodes.h:328
struct ExprEvalStep::@51::@88 agg_deserialize
static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info)
Definition: execExpr.c:2297
static Datum values[MAXATTR]
Definition: bootstrap.c:165
int steps_len
Definition: execnodes.h:103
void * arg
struct ExprEvalStep::@51::@61 jump
TupleTableSlot * sortslot
Definition: nodeAgg.h:136
Definition: pg_list.h:50
Datum resvalue
Definition: execnodes.h:73
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:3213

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

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

Referenced by ExecBuildAggTrans().

3218 {
3219  ExprContext *aggcontext;
3220  int adjust_jumpnull = -1;
3221 
3222  if (ishash)
3223  aggcontext = aggstate->hashcontext;
3224  else
3225  aggcontext = aggstate->aggcontexts[setno];
3226 
3227  /* add check for NULL pointer? */
3228  if (nullcheck)
3229  {
3231  scratch->d.agg_plain_pergroup_nullcheck.setoff = setoff;
3232  /* adjust later */
3233  scratch->d.agg_plain_pergroup_nullcheck.jumpnull = -1;
3234  ExprEvalPushStep(state, scratch);
3235  adjust_jumpnull = state->steps_len - 1;
3236  }
3237 
3238  /*
3239  * Determine appropriate transition implementation.
3240  *
3241  * For non-ordered aggregates:
3242  *
3243  * If the initial value for the transition state doesn't exist in the
3244  * pg_aggregate table then we will let the first non-NULL value returned
3245  * from the outer procNode become the initial value. (This is useful for
3246  * aggregates like max() and min().) The noTransValue flag signals that we
3247  * need to do so. If true, generate a
3248  * EEOP_AGG_INIT_STRICT_PLAIN_TRANS{,_BYVAL} step. This step also needs to
3249  * do the work described next:
3250  *
3251  * If the function is strict, but does have an initial value, choose
3252  * EEOP_AGG_STRICT_PLAIN_TRANS{,_BYVAL}, which skips the transition
3253  * function if the transition value has become NULL (because a previous
3254  * transition function returned NULL). This step also needs to do the work
3255  * described next:
3256  *
3257  * Otherwise we call EEOP_AGG_PLAIN_TRANS{,_BYVAL}, which does not have to
3258  * perform either of the above checks.
3259  *
3260  * Having steps with overlapping responsibilities is not nice, but
3261  * aggregations are very performance sensitive, making this worthwhile.
3262  *
3263  * For ordered aggregates:
3264  *
3265  * Only need to choose between the faster path for a single ordered
3266  * column, and the one between multiple columns. Checking strictness etc
3267  * is done when finalizing the aggregate. See
3268  * process_ordered_aggregate_{single, multi} and
3269  * advance_transition_function.
3270  */
3271  if (pertrans->numSortCols == 0)
3272  {
3273  if (pertrans->transtypeByVal)
3274  {
3275  if (fcinfo->flinfo->fn_strict &&
3276  pertrans->initValueIsNull)
3278  else if (fcinfo->flinfo->fn_strict)
3280  else
3282  }
3283  else
3284  {
3285  if (fcinfo->flinfo->fn_strict &&
3286  pertrans->initValueIsNull)
3288  else if (fcinfo->flinfo->fn_strict)
3290  else
3292  }
3293  }
3294  else if (pertrans->numInputs == 1)
3296  else
3298 
3299  scratch->d.agg_trans.pertrans = pertrans;
3300  scratch->d.agg_trans.setno = setno;
3301  scratch->d.agg_trans.setoff = setoff;
3302  scratch->d.agg_trans.transno = transno;
3303  scratch->d.agg_trans.aggcontext = aggcontext;
3304  ExprEvalPushStep(state, scratch);
3305 
3306  /* fix up jumpnull */
3307  if (adjust_jumpnull != -1)
3308  {
3309  ExprEvalStep *as = &state->steps[adjust_jumpnull];
3310 
3312  Assert(as->d.agg_plain_pergroup_nullcheck.jumpnull == -1);
3313  as->d.agg_plain_pergroup_nullcheck.jumpnull = state->steps_len;
3314  }
3315 }
struct ExprEvalStep * steps
Definition: execnodes.h:84
struct ExprEvalStep::@51::@91 agg_trans
struct ExprEvalStep::@51::@90 agg_plain_pergroup_nullcheck
bool fn_strict
Definition: fmgr.h:61
union ExprEvalStep::@51 d
ExprContext * hashcontext
Definition: execnodes.h:2143
FmgrInfo * flinfo
Definition: fmgr.h:87
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2104
ExprContext ** aggcontexts
Definition: execnodes.h:2144
#define Assert(condition)
Definition: c.h:800
intptr_t opcode
Definition: execExpr.h:249
int steps_len
Definition: execnodes.h:103

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

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

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

3336 {
3338  ExprEvalStep scratch = {0};
3339  int maxatt = -1;
3340  List *adjust_jumps = NIL;
3341  ListCell *lc;
3342 
3343  /*
3344  * When no columns are actually compared, the result's always true. See
3345  * special case in ExecQual().
3346  */
3347  if (numCols == 0)
3348  return NULL;
3349 
3350  state->expr = NULL;
3351  state->flags = EEO_FLAG_IS_QUAL;
3352  state->parent = parent;
3353 
3354  scratch.resvalue = &state->resvalue;
3355  scratch.resnull = &state->resnull;
3356 
3357  /* compute max needed attribute */
3358  for (int natt = 0; natt < numCols; natt++)
3359  {
3360  int attno = keyColIdx[natt];
3361 
3362  if (attno > maxatt)
3363  maxatt = attno;
3364  }
3365  Assert(maxatt >= 0);
3366 
3367  /* push deform steps */
3368  scratch.opcode = EEOP_INNER_FETCHSOME;
3369  scratch.d.fetch.last_var = maxatt;
3370  scratch.d.fetch.fixed = false;
3371  scratch.d.fetch.known_desc = ldesc;
3372  scratch.d.fetch.kind = lops;
3373  if (ExecComputeSlotInfo(state, &scratch))
3374  ExprEvalPushStep(state, &scratch);
3375 
3376  scratch.opcode = EEOP_OUTER_FETCHSOME;
3377  scratch.d.fetch.last_var = maxatt;
3378  scratch.d.fetch.fixed = false;
3379  scratch.d.fetch.known_desc = rdesc;
3380  scratch.d.fetch.kind = rops;
3381  if (ExecComputeSlotInfo(state, &scratch))
3382  ExprEvalPushStep(state, &scratch);
3383 
3384  /*
3385  * Start comparing at the last field (least significant sort key). That's
3386  * the most likely to be different if we are dealing with sorted input.
3387  */
3388  for (int natt = numCols; --natt >= 0;)
3389  {
3390  int attno = keyColIdx[natt];
3391  Form_pg_attribute latt = TupleDescAttr(ldesc, attno - 1);
3392  Form_pg_attribute ratt = TupleDescAttr(rdesc, attno - 1);
3393  Oid foid = eqfunctions[natt];
3394  Oid collid = collations[natt];
3395  FmgrInfo *finfo;
3396  FunctionCallInfo fcinfo;
3397  AclResult aclresult;
3398 
3399  /* Check permission to call function */
3400  aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
3401  if (aclresult != ACLCHECK_OK)
3402  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
3403 
3405 
3406  /* Set up the primary fmgr lookup information */
3407  finfo = palloc0(sizeof(FmgrInfo));
3408  fcinfo = palloc0(SizeForFunctionCallInfo(2));
3409  fmgr_info(foid, finfo);
3410  fmgr_info_set_expr(NULL, finfo);
3411  InitFunctionCallInfoData(*fcinfo, finfo, 2,
3412  collid, NULL, NULL);
3413 
3414  /* left arg */
3415  scratch.opcode = EEOP_INNER_VAR;
3416  scratch.d.var.attnum = attno - 1;
3417  scratch.d.var.vartype = latt->atttypid;
3418  scratch.resvalue = &fcinfo->args[0].value;
3419  scratch.resnull = &fcinfo->args[0].isnull;
3420  ExprEvalPushStep(state, &scratch);
3421 
3422  /* right arg */
3423  scratch.opcode = EEOP_OUTER_VAR;
3424  scratch.d.var.attnum = attno - 1;
3425  scratch.d.var.vartype = ratt->atttypid;
3426  scratch.resvalue = &fcinfo->args[1].value;
3427  scratch.resnull = &fcinfo->args[1].isnull;
3428  ExprEvalPushStep(state, &scratch);
3429 
3430  /* evaluate distinctness */
3431  scratch.opcode = EEOP_NOT_DISTINCT;
3432  scratch.d.func.finfo = finfo;
3433  scratch.d.func.fcinfo_data = fcinfo;
3434  scratch.d.func.fn_addr = finfo->fn_addr;
3435  scratch.d.func.nargs = 2;
3436  scratch.resvalue = &state->resvalue;
3437  scratch.resnull = &state->resnull;
3438  ExprEvalPushStep(state, &scratch);
3439 
3440  /* then emit EEOP_QUAL to detect if result is false (or null) */
3441  scratch.opcode = EEOP_QUAL;
3442  scratch.d.qualexpr.jumpdone = -1;
3443  scratch.resvalue = &state->resvalue;
3444  scratch.resnull = &state->resnull;
3445  ExprEvalPushStep(state, &scratch);
3446  adjust_jumps = lappend_int(adjust_jumps,
3447  state->steps_len - 1);
3448  }
3449 
3450  /* adjust jump targets */
3451  foreach(lc, adjust_jumps)
3452  {
3453  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
3454 
3455  Assert(as->opcode == EEOP_QUAL);
3456  Assert(as->d.qualexpr.jumpdone == -1);
3457  as->d.qualexpr.jumpdone = state->steps_len;
3458  }
3459 
3460  scratch.resvalue = NULL;
3461  scratch.resnull = NULL;
3462  scratch.opcode = EEOP_DONE;
3463  ExprEvalPushStep(state, &scratch);
3464 
3465  ExecReadyExpr(state);
3466 
3467  return state;
3468 }
#define NIL
Definition: pg_list.h:65
Definition: fmgr.h:56
struct PlanState * parent
Definition: execnodes.h:107
Datum * resvalue
Definition: execExpr.h:252
Oid GetUserId(void)
Definition: miscinit.c:476
PGFunction fn_addr
Definition: fmgr.h:58
struct ExprEvalStep * steps
Definition: execnodes.h:84
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
struct ExprEvalStep::@51::@52 fetch
bool * resnull
Definition: execExpr.h:253
unsigned int Oid
Definition: postgres_ext.h:31
struct ExprEvalStep::@51::@58 func
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
bool resnull
Definition: execnodes.h:71
Expr * expr
Definition: execnodes.h:93
#define lfirst_int(lc)
Definition: pg_list.h:170
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1525
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
#define EEO_FLAG_IS_QUAL
Definition: execnodes.h:58
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
Datum value
Definition: postgres.h:378
List * lappend_int(List *list, int datum)
Definition: list.c:339
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:191
union ExprEvalStep::@51 d
void * palloc0(Size size)
Definition: mcxt.c:981
AclResult
Definition: acl.h:177
static bool ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op)
Definition: execExpr.c:2351
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2104
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:628
struct ExprEvalStep::@51::@53 var
#define makeNode(_type_)
Definition: nodes.h:575
#define Assert(condition)
Definition: c.h:800
Definition: regguts.h:298
intptr_t opcode
Definition: execExpr.h:249
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
int steps_len
Definition: execnodes.h:103
#define ACL_EXECUTE
Definition: parsenodes.h:81
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4587
uint8 flags
Definition: execnodes.h:64
Definition: pg_list.h:50
Datum resvalue
Definition: execnodes.h:73
struct ExprEvalStep::@51::@60 qualexpr

◆ ExecBuildProjectionInfo()

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

Definition at line 352 of file execExpr.c.

References ExprEvalStep::assign_tmp, ExprEvalStep::assign_var, attnum, ExprEvalStep::d, EEOP_ASSIGN_INNER_VAR, EEOP_ASSIGN_OUTER_VAR, EEOP_ASSIGN_SCAN_VAR, EEOP_ASSIGN_TMP, EEOP_ASSIGN_TMP_MAKE_RO, EEOP_DONE, ExecInitExprRec(), ExecInitExprSlots(), ExecReadyExpr(), ExprState::expr, TargetEntry::expr, ExprEvalPushStep(), exprType(), ExprState::ext_params, get_typlen(), INNER_VAR, IsA, lfirst_node, makeNode, ExprEvalStep::opcode, OUTER_VAR, ExprState::parent, ProjectionInfo::pi_exprContext, ProjectionInfo::pi_state, TargetEntry::resno, ExprState::resnull, ExprState::resultslot, ExprState::resvalue, T_ExprState, ExprState::tag, TupleDescAttr, Var::varattno, Var::varno, and Var::vartype.

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

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

◆ ExecCheck()

bool ExecCheck ( ExprState state,
ExprContext econtext 
)

Definition at line 598 of file execExpr.c.

References Assert, DatumGetBool, EEO_FLAG_IS_QUAL, ExecEvalExprSwitchContext(), and ExprState::flags.

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

599 {
600  Datum ret;
601  bool isnull;
602 
603  /* short-circuit (here and in ExecInitCheck) for empty restriction list */
604  if (state == NULL)
605  return true;
606 
607  /* verify that expression was not compiled using ExecInitQual */
608  Assert(!(state->flags & EEO_FLAG_IS_QUAL));
609 
610  ret = ExecEvalExprSwitchContext(state, econtext, &isnull);
611 
612  if (isnull)
613  return true;
614 
615  return DatumGetBool(ret);
616 }
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:307
#define EEO_FLAG_IS_QUAL
Definition: execnodes.h:58
#define DatumGetBool(X)
Definition: postgres.h:393
uintptr_t Datum
Definition: postgres.h:367
#define Assert(condition)
Definition: c.h:800
uint8 flags
Definition: execnodes.h:64

◆ ExecComputeSlotInfo()

static bool ExecComputeSlotInfo ( ExprState state,
ExprEvalStep op 
)
static

Definition at line 2351 of file execExpr.c.

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

Referenced by ExecBuildGroupingEqual(), and ExecPushExprSlots().

2352 {
2353  PlanState *parent = state->parent;
2354  TupleDesc desc = NULL;
2355  const TupleTableSlotOps *tts_ops = NULL;
2356  bool isfixed = false;
2357  ExprEvalOp opcode = op->opcode;
2358 
2359  Assert(opcode == EEOP_INNER_FETCHSOME ||
2360  opcode == EEOP_OUTER_FETCHSOME ||
2361  opcode == EEOP_SCAN_FETCHSOME);
2362 
2363  if (op->d.fetch.known_desc != NULL)
2364  {
2365  desc = op->d.fetch.known_desc;
2366  tts_ops = op->d.fetch.kind;
2367  isfixed = op->d.fetch.kind != NULL;
2368  }
2369  else if (!parent)
2370  {
2371  isfixed = false;
2372  }
2373  else if (opcode == EEOP_INNER_FETCHSOME)
2374  {
2375  PlanState *is = innerPlanState(parent);
2376 
2377  if (parent->inneropsset && !parent->inneropsfixed)
2378  {
2379  isfixed = false;
2380  }
2381  else if (parent->inneropsset && parent->innerops)
2382  {
2383  isfixed = true;
2384  tts_ops = parent->innerops;
2385  desc = ExecGetResultType(is);
2386  }
2387  else if (is)
2388  {
2389  tts_ops = ExecGetResultSlotOps(is, &isfixed);
2390  desc = ExecGetResultType(is);
2391  }
2392  }
2393  else if (opcode == EEOP_OUTER_FETCHSOME)
2394  {
2395  PlanState *os = outerPlanState(parent);
2396 
2397  if (parent->outeropsset && !parent->outeropsfixed)
2398  {
2399  isfixed = false;
2400  }
2401  else if (parent->outeropsset && parent->outerops)
2402  {
2403  isfixed = true;
2404  tts_ops = parent->outerops;
2405  desc = ExecGetResultType(os);
2406  }
2407  else if (os)
2408  {
2409  tts_ops = ExecGetResultSlotOps(os, &isfixed);
2410  desc = ExecGetResultType(os);
2411  }
2412  }
2413  else if (opcode == EEOP_SCAN_FETCHSOME)
2414  {
2415  desc = parent->scandesc;
2416 
2417  if (parent->scanops)
2418  tts_ops = parent->scanops;
2419 
2420  if (parent->scanopsset)
2421  isfixed = parent->scanopsfixed;
2422  }
2423 
2424  if (isfixed && desc != NULL && tts_ops != NULL)
2425  {
2426  op->d.fetch.fixed = true;
2427  op->d.fetch.kind = tts_ops;
2428  op->d.fetch.known_desc = desc;
2429  }
2430  else
2431  {
2432  op->d.fetch.fixed = false;
2433  op->d.fetch.kind = NULL;
2434  op->d.fetch.known_desc = NULL;
2435  }
2436 
2437  /* if the slot is known to always virtual we never need to deform */
2438  if (op->d.fetch.fixed && op->d.fetch.kind == &TTSOpsVirtual)
2439  return false;
2440 
2441  return true;
2442 }
const TupleTableSlotOps * innerops
Definition: execnodes.h:1002
struct PlanState * parent
Definition: execnodes.h:107
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:498
bool inneropsset
Definition: execnodes.h:1010
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
struct ExprEvalStep::@51::@52 fetch
ExprEvalOp
Definition: execExpr.h:44
bool inneropsfixed
Definition: execnodes.h:1006
#define outerPlanState(node)
Definition: execnodes.h:1022
const TupleTableSlotOps * scanops
Definition: execnodes.h:1000
bool outeropsset
Definition: execnodes.h:1009
union ExprEvalStep::@51 d
TupleDesc scandesc
Definition: execnodes.h:975
bool scanopsfixed
Definition: execnodes.h:1004
#define Assert(condition)
Definition: c.h:800
intptr_t opcode
Definition: execExpr.h:249
bool outeropsfixed
Definition: execnodes.h:1005
bool scanopsset
Definition: execnodes.h:1008
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:489
#define innerPlanState(node)
Definition: execnodes.h:1021
const TupleTableSlotOps * outerops
Definition: execnodes.h:1001

◆ ExecInitCheck()

ExprState* ExecInitCheck ( List qual,
PlanState parent 
)

Definition at line 297 of file execExpr.c.

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

Referenced by ExecPrepareCheck(), and ExecProcNode().

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

◆ ExecInitCoerceToDomain()

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

Definition at line 2759 of file execExpr.c.

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

Referenced by ExecInitExprRec().

2761 {
2762  DomainConstraintRef *constraint_ref;
2763  ListCell *l;
2764 
2765  scratch->d.domaincheck.resulttype = ctest->resulttype;
2766  /* we'll allocate workspace only if needed */
2767  scratch->d.domaincheck.checkvalue = NULL;
2768  scratch->d.domaincheck.checknull = NULL;
2769 
2770  /*
2771  * Evaluate argument - it's fine to directly store it into resv/resnull,
2772  * if there's constraint failures there'll be errors, otherwise it's what
2773  * needs to be returned.
2774  */
2775  ExecInitExprRec(ctest->arg, state, resv, resnull);
2776 
2777  /*
2778  * Note: if the argument is of varlena type, it could be a R/W expanded
2779  * object. We want to return the R/W pointer as the final result, but we
2780  * have to pass a R/O pointer as the value to be tested by any functions
2781  * in check expressions. We don't bother to emit a MAKE_READONLY step
2782  * unless there's actually at least one check expression, though. Until
2783  * we've tested that, domainval/domainnull are NULL.
2784  */
2785 
2786  /*
2787  * Collect the constraints associated with the domain.
2788  *
2789  * Note: before PG v10 we'd recheck the set of constraints during each
2790  * evaluation of the expression. Now we bake them into the ExprState
2791  * during executor initialization. That means we don't need typcache.c to
2792  * provide compiled exprs.
2793  */
2794  constraint_ref = (DomainConstraintRef *)
2795  palloc(sizeof(DomainConstraintRef));
2797  constraint_ref,
2799  false);
2800 
2801  /*
2802  * Compile code to check each domain constraint. NOTNULL constraints can
2803  * just be applied on the resv/resnull value, but for CHECK constraints we
2804  * need more pushups.
2805  */
2806  foreach(l, constraint_ref->constraints)
2807  {
2809  Datum *domainval = NULL;
2810  bool *domainnull = NULL;
2811  Datum *save_innermost_domainval;
2812  bool *save_innermost_domainnull;
2813 
2814  scratch->d.domaincheck.constraintname = con->name;
2815 
2816  switch (con->constrainttype)
2817  {
2819  scratch->opcode = EEOP_DOMAIN_NOTNULL;
2820  ExprEvalPushStep(state, scratch);
2821  break;
2822  case DOM_CONSTRAINT_CHECK:
2823  /* Allocate workspace for CHECK output if we didn't yet */
2824  if (scratch->d.domaincheck.checkvalue == NULL)
2825  {
2826  scratch->d.domaincheck.checkvalue =
2827  (Datum *) palloc(sizeof(Datum));
2828  scratch->d.domaincheck.checknull =
2829  (bool *) palloc(sizeof(bool));
2830  }
2831 
2832  /*
2833  * If first time through, determine where CoerceToDomainValue
2834  * nodes should read from.
2835  */
2836  if (domainval == NULL)
2837  {
2838  /*
2839  * Since value might be read multiple times, force to R/O
2840  * - but only if it could be an expanded datum.
2841  */
2842  if (get_typlen(ctest->resulttype) == -1)
2843  {
2844  ExprEvalStep scratch2 = {0};
2845 
2846  /* Yes, so make output workspace for MAKE_READONLY */
2847  domainval = (Datum *) palloc(sizeof(Datum));
2848  domainnull = (bool *) palloc(sizeof(bool));
2849 
2850  /* Emit MAKE_READONLY */
2851  scratch2.opcode = EEOP_MAKE_READONLY;
2852  scratch2.resvalue = domainval;
2853  scratch2.resnull = domainnull;
2854  scratch2.d.make_readonly.value = resv;
2855  scratch2.d.make_readonly.isnull = resnull;
2856  ExprEvalPushStep(state, &scratch2);
2857  }
2858  else
2859  {
2860  /* No, so it's fine to read from resv/resnull */
2861  domainval = resv;
2862  domainnull = resnull;
2863  }
2864  }
2865 
2866  /*
2867  * Set up value to be returned by CoerceToDomainValue nodes.
2868  * We must save and restore innermost_domainval/null fields,
2869  * in case this node is itself within a check expression for
2870  * another domain.
2871  */
2872  save_innermost_domainval = state->innermost_domainval;
2873  save_innermost_domainnull = state->innermost_domainnull;
2874  state->innermost_domainval = domainval;
2875  state->innermost_domainnull = domainnull;
2876 
2877  /* evaluate check expression value */
2878  ExecInitExprRec(con->check_expr, state,
2879  scratch->d.domaincheck.checkvalue,
2880  scratch->d.domaincheck.checknull);
2881 
2882  state->innermost_domainval = save_innermost_domainval;
2883  state->innermost_domainnull = save_innermost_domainnull;
2884 
2885  /* now test result */
2886  scratch->opcode = EEOP_DOMAIN_CHECK;
2887  ExprEvalPushStep(state, scratch);
2888 
2889  break;
2890  default:
2891  elog(ERROR, "unrecognized constraint type: %d",
2892  (int) con->constrainttype);
2893  break;
2894  }
2895  }
2896 }
Datum * resvalue
Definition: execExpr.h:252
DomainConstraintType constrainttype
Definition: execnodes.h:892
struct ExprEvalStep::@51::@80 domaincheck
bool * resnull
Definition: execExpr.h:253
Datum * innermost_domainval
Definition: execnodes.h:113
bool * innermost_domainnull
Definition: execnodes.h:114
#define ERROR
Definition: elog.h:43
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
union ExprEvalStep::@51 d
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:645
struct ExprEvalStep::@51::@66 make_readonly
uintptr_t Datum
Definition: postgres.h:367
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2104
#define lfirst(lc)
Definition: pg_list.h:169
intptr_t opcode
Definition: execExpr.h:249
void InitDomainConstraintRef(Oid type_id, DomainConstraintRef *ref, MemoryContext refctx, bool need_exprstate)
Definition: typcache.c:1259
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2090
void * palloc(Size size)
Definition: mcxt.c:950
#define elog(elevel,...)
Definition: elog.h:228

◆ ExecInitExpr()

ExprState* ExecInitExpr ( Expr node,
PlanState parent 
)

Definition at line 122 of file execExpr.c.

References EEOP_DONE, ExecInitExprRec(), ExecInitExprSlots(), ExecReadyExpr(), ExprState::expr, ExprEvalPushStep(), ExprState::ext_params, makeNode, ExprEvalStep::opcode, ExprState::parent, ExprState::resnull, and ExprState::resvalue.

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

123 {
124  ExprState *state;
125  ExprEvalStep scratch = {0};
126 
127  /* Special case: NULL expression produces a NULL ExprState pointer */
128  if (node == NULL)
129  return NULL;
130 
131  /* Initialize ExprState with empty step list */
132  state = makeNode(ExprState);
133  state->expr = node;
134  state->parent = parent;
135  state->ext_params = NULL;
136 
137  /* Insert EEOP_*_FETCHSOME steps as needed */
138  ExecInitExprSlots(state, (Node *) node);
139 
140  /* Compile the expression proper */
141  ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
142 
143  /* Finally, append a DONE step */
144  scratch.opcode = EEOP_DONE;
145  ExprEvalPushStep(state, &scratch);
146 
147  ExecReadyExpr(state);
148 
149  return state;
150 }
struct PlanState * parent
Definition: execnodes.h:107
ParamListInfo ext_params
Definition: execnodes.h:108
Definition: nodes.h:527
bool resnull
Definition: execnodes.h:71
Expr * expr
Definition: execnodes.h:93
static void ExecInitExprSlots(ExprState *state, Node *node)
Definition: execExpr.c:2235
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:645
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2104
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:628
#define makeNode(_type_)
Definition: nodes.h:575
Definition: regguts.h:298
intptr_t opcode
Definition: execExpr.h:249
Datum resvalue
Definition: execnodes.h:73

◆ ExecInitExprList()

List* ExecInitExprList ( List nodes,
PlanState parent 
)

Definition at line 317 of file execExpr.c.

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

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

318 {
319  List *result = NIL;
320  ListCell *lc;
321 
322  foreach(lc, nodes)
323  {
324  Expr *e = lfirst(lc);
325 
326  result = lappend(result, ExecInitExpr(e, parent));
327  }
328 
329  return result;
330 }
#define NIL
Definition: pg_list.h:65
List * lappend(List *list, void *datum)
Definition: list.c:321
#define lfirst(lc)
Definition: pg_list.h:169
e
Definition: preproc-init.c:82
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:122
Definition: pg_list.h:50

◆ ExecInitExprRec()

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

Definition at line 645 of file execExpr.c.

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, WindowFunc::aggfilter, WindowFuncExprState::aggfilter, Aggref::aggno, ExprEvalStep::aggref, AggState::aggs, AND_EXPR, arg, FieldSelect::arg, FieldStore::arg, RelabelType::arg, CoerceViaIO::arg, ArrayCoerceExpr::arg, ConvertRowtypeExpr::arg, CaseExpr::arg, NullTest::arg, BooleanTest::arg, NullTest::argisrow, FunctionCallInfoBaseData::args, WindowFunc::args, FuncExpr::args, OpExpr::args, ScalarArrayOpExpr::args, BoolExpr::args, WindowFuncExprState::args, CaseExpr::args, RowExpr::args, CoalesceExpr::args, MinMaxExpr::args, XmlExpr::args, ExprEvalStep::arraycoerce, ExprEvalStep::arrayexpr, Assert, BlessTupleDesc(), ExprEvalStep::boolexpr, BoolExpr::boolop, BooleanTest::booltesttype, BTORDER_PROC, ExprEvalStep::casetest, check_stack_depth(), TypeCacheEntry::cmp_proc, RowExpr::colnames, GroupingFunc::cols, Const::constisnull, ExprEvalStep::constval, Const::constvalue, convert(), ExprEvalStep::convert_rowtype, ExprEvalStep::d, DecrTupleDescRefCount(), CaseExpr::defresult, EEOP_AGGREF, EEOP_ARRAYCOERCE, EEOP_ARRAYEXPR, EEOP_BOOL_AND_STEP, EEOP_BOOL_AND_STEP_FIRST, EEOP_BOOL_AND_STEP_LAST, EEOP_BOOL_NOT_STEP, EEOP_BOOL_OR_STEP, EEOP_BOOL_OR_STEP_FIRST, EEOP_BOOL_OR_STEP_LAST, EEOP_BOOLTEST_IS_FALSE, EEOP_BOOLTEST_IS_NOT_FALSE, EEOP_BOOLTEST_IS_NOT_TRUE, EEOP_BOOLTEST_IS_TRUE, EEOP_CASE_TESTVAL, EEOP_CONST, EEOP_CONVERT_ROWTYPE, EEOP_CURRENTOFEXPR, EEOP_DISTINCT, EEOP_DOMAIN_TESTVAL, EEOP_DONE, EEOP_FIELDSELECT, EEOP_FIELDSTORE_DEFORM, EEOP_FIELDSTORE_FORM, EEOP_GROUPING_FUNC, EEOP_INNER_SYSVAR, EEOP_INNER_VAR, EEOP_IOCOERCE, EEOP_JUMP, EEOP_JUMP_IF_NOT_NULL, EEOP_JUMP_IF_NOT_TRUE, EEOP_MAKE_READONLY, EEOP_MINMAX, EEOP_NEXTVALUEEXPR, EEOP_NULLIF, EEOP_NULLTEST_ISNOTNULL, EEOP_NULLTEST_ISNULL, EEOP_NULLTEST_ROWISNOTNULL, EEOP_NULLTEST_ROWISNULL, EEOP_OUTER_SYSVAR, EEOP_OUTER_VAR, EEOP_PARAM_EXEC, EEOP_PARAM_EXTERN, EEOP_ROW, EEOP_ROWCOMPARE_FINAL, EEOP_ROWCOMPARE_STEP, EEOP_SCALARARRAYOP, EEOP_SCAN_SYSVAR, EEOP_SCAN_VAR, EEOP_SQLVALUEFUNCTION, EEOP_SUBPLAN, EEOP_WINDOW_FUNC, EEOP_XMLEXPR, ArrayExpr::element_typeid, ArrayExpr::elements, ArrayCoerceExpr::elemexpr, elog, ereport, errcode(), errmsg(), ERROR, EState::es_param_list_info, ExecInitCoerceToDomain(), ExecInitExpr(), ExecInitExprList(), ExecInitFunc(), ExecInitSubPlan(), ExecInitSubscriptingRef(), ExecInitWholeRowVar(), ExecReadyExpr(), ExecTypeFromExprList(), ExecTypeSetColNames(), ExprState::expr, CaseWhen::expr, ExprEvalPushStep(), exprType(), ExprState::ext_params, FieldSelect::fieldnum, FieldStore::fieldnums, ExprEvalStep::fieldselect, ExprEvalStep::fieldstore, fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_addr, forboth, forfive, format_type_be(), FuncExpr::funcid, WindowAggState::funcs, get_element_type(), get_func_name(), get_op_opfamily_properties(), get_opfamily_proc(), get_typlen(), get_typlenbyvalalign(), getTypeInputInfo(), getTypeOutputInfo(), GetUserId(), ExprEvalStep::grouping_func, Agg::groupingSets, i, InitFunctionCallInfoData, INNER_VAR, ExprState::innermost_casenull, ExprState::innermost_caseval, ExprState::innermost_domainnull, ExprState::innermost_domainval, FuncExpr::inputcollid, OpExpr::inputcollid, ScalarArrayOpExpr::inputcollid, MinMaxExpr::inputcollid, RowCompareExpr::inputcollids, Int32GetDatum, InvalidAttrNumber, InvalidOid, InvokeFunctionExecuteHook, ExprEvalStep::iocoerce, IS_FALSE, IS_NOT_FALSE, IS_NOT_NULL, IS_NOT_TRUE, IS_NOT_UNKNOWN, IS_NULL, IS_TRUE, IS_UNKNOWN, IsA, NullableDatum::isnull, ExprEvalStep::jump, lappend(), lappend_int(), RowCompareExpr::largs, lfirst, lfirst_int, lfirst_oid, linitial, list_length(), lookup_rowtype_tupdesc(), lookup_rowtype_tupdesc_copy(), lookup_type_cache(), lsecond, ExprEvalStep::make_readonly, makeNode, makeNullConst(), Max, ExprEvalStep::minmax, MinMaxExpr::minmaxtype, ArrayExpr::multidims, XmlExpr::named_args, TupleDescData::natts, FieldStore::newvals, ExprEvalStep::nextvalueexpr, NIL, nodeTag, NOT_EXPR, ExprEvalStep::nulltest_row, NullTest::nulltesttype, WindowAggState::numaggs, WindowAggState::numfuncs, OBJECT_FUNCTION, ObjectIdGetDatum, OidIsValid, MinMaxExpr::op, ExprEvalStep::opcode, RowCompareExpr::opfamilies, OpExpr::opfuncid, ScalarArrayOpExpr::opfuncid, RowCompareExpr::opnos, OR_EXPR, OUTER_VAR, palloc(), palloc0(), ExprEvalStep::param, PARAM_EXEC, PARAM_EXTERN, ParamListInfoData::paramCompile, Param::paramid, Param::paramkind, Param::paramtype, ExprState::parent, pg_proc_aclcheck(), PlanState::plan, RowCompareExpr::rargs, RowCompareExpr::rctype, ExprState::resnull, ExprEvalStep::resnull, CaseWhen::result, FieldSelect::resulttype, FieldStore::resulttype, CoerceViaIO::resulttype, ArrayCoerceExpr::resulttype, ExprState::resvalue, ExprEvalStep::resvalue, ExprEvalStep::row, RowExpr::row_typeid, ExprEvalStep::rowcompare_final, ExprEvalStep::rowcompare_step, ExprEvalStep::scalararrayop, NextValueExpr::seqid, SizeForFunctionCallInfo, ExprEvalStep::sqlvaluefunction, PlanState::state, ExprState::steps, ExprState::steps_len, ExprEvalStep::subplan, PlanState::subPlan, T_Aggref, T_ArrayCoerceExpr, T_ArrayExpr, T_BooleanTest, T_BoolExpr, T_CaseExpr, T_CaseTestExpr, T_CoalesceExpr, T_CoerceToDomain, T_CoerceToDomainValue, T_CoerceViaIO, T_Const, T_ConvertRowtypeExpr, T_CurrentOfExpr, T_DistinctExpr, T_FieldSelect, T_FieldStore, T_FuncExpr, T_GroupingFunc, T_MinMaxExpr, T_NextValueExpr, T_NullIfExpr, T_NullTest, T_OpExpr, T_Param, T_RelabelType, T_RowCompareExpr, T_RowExpr, T_ScalarArrayOpExpr, T_SQLValueFunction, T_SubPlan, T_SubscriptingRef, T_Var, T_WindowFunc, T_XmlExpr, TupleDescAttr, TYPECACHE_CMP_PROC, NextValueExpr::typeId, ScalarArrayOpExpr::useOr, NullableDatum::value, values, ExprEvalStep::var, Var::varattno, Var::varno, Var::vartype, WindowFuncExprState::wfunc, WindowFunc::winagg, ExprEvalStep::window_func, and ExprEvalStep::xmlexpr.

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

647 {
648  ExprEvalStep scratch = {0};
649 
650  /* Guard against stack overflow due to overly complex expressions */
652 
653  /* Step's output location is always what the caller gave us */
654  Assert(resv != NULL && resnull != NULL);
655  scratch.resvalue = resv;
656  scratch.resnull = resnull;
657 
658  /* cases should be ordered as they are in enum NodeTag */
659  switch (nodeTag(node))
660  {
661  case T_Var:
662  {
663  Var *variable = (Var *) node;
664 
665  if (variable->varattno == InvalidAttrNumber)
666  {
667  /* whole-row Var */
668  ExecInitWholeRowVar(&scratch, variable, state);
669  }
670  else if (variable->varattno <= 0)
671  {
672  /* system column */
673  scratch.d.var.attnum = variable->varattno;
674  scratch.d.var.vartype = variable->vartype;
675  switch (variable->varno)
676  {
677  case INNER_VAR:
678  scratch.opcode = EEOP_INNER_SYSVAR;
679  break;
680  case OUTER_VAR:
681  scratch.opcode = EEOP_OUTER_SYSVAR;
682  break;
683 
684  /* INDEX_VAR is handled by default case */
685 
686  default:
687  scratch.opcode = EEOP_SCAN_SYSVAR;
688  break;
689  }
690  }
691  else
692  {
693  /* regular user column */
694  scratch.d.var.attnum = variable->varattno - 1;
695  scratch.d.var.vartype = variable->vartype;
696  switch (variable->varno)
697  {
698  case INNER_VAR:
699  scratch.opcode = EEOP_INNER_VAR;
700  break;
701  case OUTER_VAR:
702  scratch.opcode = EEOP_OUTER_VAR;
703  break;
704 
705  /* INDEX_VAR is handled by default case */
706 
707  default:
708  scratch.opcode = EEOP_SCAN_VAR;
709  break;
710  }
711  }
712 
713  ExprEvalPushStep(state, &scratch);
714  break;
715  }
716 
717  case T_Const:
718  {
719  Const *con = (Const *) node;
720 
721  scratch.opcode = EEOP_CONST;
722  scratch.d.constval.value = con->constvalue;
723  scratch.d.constval.isnull = con->constisnull;
724 
725  ExprEvalPushStep(state, &scratch);
726  break;
727  }
728 
729  case T_Param:
730  {
731  Param *param = (Param *) node;
732  ParamListInfo params;
733 
734  switch (param->paramkind)
735  {
736  case PARAM_EXEC:
737  scratch.opcode = EEOP_PARAM_EXEC;
738  scratch.d.param.paramid = param->paramid;
739  scratch.d.param.paramtype = param->paramtype;
740  ExprEvalPushStep(state, &scratch);
741  break;
742  case PARAM_EXTERN:
743 
744  /*
745  * If we have a relevant ParamCompileHook, use it;
746  * otherwise compile a standard EEOP_PARAM_EXTERN
747  * step. ext_params, if supplied, takes precedence
748  * over info from the parent node's EState (if any).
749  */
750  if (state->ext_params)
751  params = state->ext_params;
752  else if (state->parent &&
753  state->parent->state)
754  params = state->parent->state->es_param_list_info;
755  else
756  params = NULL;
757  if (params && params->paramCompile)
758  {
759  params->paramCompile(params, param, state,
760  resv, resnull);
761  }
762  else
763  {
764  scratch.opcode = EEOP_PARAM_EXTERN;
765  scratch.d.param.paramid = param->paramid;
766  scratch.d.param.paramtype = param->paramtype;
767  ExprEvalPushStep(state, &scratch);
768  }
769  break;
770  default:
771  elog(ERROR, "unrecognized paramkind: %d",
772  (int) param->paramkind);
773  break;
774  }
775  break;
776  }
777 
778  case T_Aggref:
779  {
780  Aggref *aggref = (Aggref *) node;
781 
782  scratch.opcode = EEOP_AGGREF;
783  scratch.d.aggref.aggno = aggref->aggno;
784 
785  if (state->parent && IsA(state->parent, AggState))
786  {
787  AggState *aggstate = (AggState *) state->parent;
788 
789  aggstate->aggs = lappend(aggstate->aggs, aggref);
790  }
791  else
792  {
793  /* planner messed up */
794  elog(ERROR, "Aggref found in non-Agg plan node");
795  }
796 
797  ExprEvalPushStep(state, &scratch);
798  break;
799  }
800 
801  case T_GroupingFunc:
802  {
803  GroupingFunc *grp_node = (GroupingFunc *) node;
804  Agg *agg;
805 
806  if (!state->parent || !IsA(state->parent, AggState) ||
807  !IsA(state->parent->plan, Agg))
808  elog(ERROR, "GroupingFunc found in non-Agg plan node");
809 
810  scratch.opcode = EEOP_GROUPING_FUNC;
811 
812  agg = (Agg *) (state->parent->plan);
813 
814  if (agg->groupingSets)
815  scratch.d.grouping_func.clauses = grp_node->cols;
816  else
817  scratch.d.grouping_func.clauses = NIL;
818 
819  ExprEvalPushStep(state, &scratch);
820  break;
821  }
822 
823  case T_WindowFunc:
824  {
825  WindowFunc *wfunc = (WindowFunc *) node;
827 
828  wfstate->wfunc = wfunc;
829 
830  if (state->parent && IsA(state->parent, WindowAggState))
831  {
832  WindowAggState *winstate = (WindowAggState *) state->parent;
833  int nfuncs;
834 
835  winstate->funcs = lappend(winstate->funcs, wfstate);
836  nfuncs = ++winstate->numfuncs;
837  if (wfunc->winagg)
838  winstate->numaggs++;
839 
840  /* for now initialize agg using old style expressions */
841  wfstate->args = ExecInitExprList(wfunc->args,
842  state->parent);
843  wfstate->aggfilter = ExecInitExpr(wfunc->aggfilter,
844  state->parent);
845 
846  /*
847  * Complain if the windowfunc's arguments contain any
848  * windowfuncs; nested window functions are semantically
849  * nonsensical. (This should have been caught earlier,
850  * but we defend against it here anyway.)
851  */
852  if (nfuncs != winstate->numfuncs)
853  ereport(ERROR,
854  (errcode(ERRCODE_WINDOWING_ERROR),
855  errmsg("window function calls cannot be nested")));
856  }
857  else
858  {
859  /* planner messed up */
860  elog(ERROR, "WindowFunc found in non-WindowAgg plan node");
861  }
862 
863  scratch.opcode = EEOP_WINDOW_FUNC;
864  scratch.d.window_func.wfstate = wfstate;
865  ExprEvalPushStep(state, &scratch);
866  break;
867  }
868 
869  case T_SubscriptingRef:
870  {
871  SubscriptingRef *sbsref = (SubscriptingRef *) node;
872 
873  ExecInitSubscriptingRef(&scratch, sbsref, state, resv, resnull);
874  break;
875  }
876 
877  case T_FuncExpr:
878  {
879  FuncExpr *func = (FuncExpr *) node;
880 
881  ExecInitFunc(&scratch, node,
882  func->args, func->funcid, func->inputcollid,
883  state);
884  ExprEvalPushStep(state, &scratch);
885  break;
886  }
887 
888  case T_OpExpr:
889  {
890  OpExpr *op = (OpExpr *) node;
891 
892  ExecInitFunc(&scratch, node,
893  op->args, op->opfuncid, op->inputcollid,
894  state);
895  ExprEvalPushStep(state, &scratch);
896  break;
897  }
898 
899  case T_DistinctExpr:
900  {
901  DistinctExpr *op = (DistinctExpr *) node;
902 
903  ExecInitFunc(&scratch, node,
904  op->args, op->opfuncid, op->inputcollid,
905  state);
906 
907  /*
908  * Change opcode of call instruction to EEOP_DISTINCT.
909  *
910  * XXX: historically we've not called the function usage
911  * pgstat infrastructure - that seems inconsistent given that
912  * we do so for normal function *and* operator evaluation. If
913  * we decided to do that here, we'd probably want separate
914  * opcodes for FUSAGE or not.
915  */
916  scratch.opcode = EEOP_DISTINCT;
917  ExprEvalPushStep(state, &scratch);
918  break;
919  }
920 
921  case T_NullIfExpr:
922  {
923  NullIfExpr *op = (NullIfExpr *) node;
924 
925  ExecInitFunc(&scratch, node,
926  op->args, op->opfuncid, op->inputcollid,
927  state);
928 
929  /*
930  * Change opcode of call instruction to EEOP_NULLIF.
931  *
932  * XXX: historically we've not called the function usage
933  * pgstat infrastructure - that seems inconsistent given that
934  * we do so for normal function *and* operator evaluation. If
935  * we decided to do that here, we'd probably want separate
936  * opcodes for FUSAGE or not.
937  */
938  scratch.opcode = EEOP_NULLIF;
939  ExprEvalPushStep(state, &scratch);
940  break;
941  }
942 
943  case T_ScalarArrayOpExpr:
944  {
945  ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
946  Expr *scalararg;
947  Expr *arrayarg;
948  FmgrInfo *finfo;
949  FunctionCallInfo fcinfo;
950  AclResult aclresult;
951 
952  Assert(list_length(opexpr->args) == 2);
953  scalararg = (Expr *) linitial(opexpr->args);
954  arrayarg = (Expr *) lsecond(opexpr->args);
955 
956  /* Check permission to call function */
957  aclresult = pg_proc_aclcheck(opexpr->opfuncid,
958  GetUserId(),
959  ACL_EXECUTE);
960  if (aclresult != ACLCHECK_OK)
961  aclcheck_error(aclresult, OBJECT_FUNCTION,
962  get_func_name(opexpr->opfuncid));
964 
965  /* Set up the primary fmgr lookup information */
966  finfo = palloc0(sizeof(FmgrInfo));
967  fcinfo = palloc0(SizeForFunctionCallInfo(2));
968  fmgr_info(opexpr->opfuncid, finfo);
969  fmgr_info_set_expr((Node *) node, finfo);
970  InitFunctionCallInfoData(*fcinfo, finfo, 2,
971  opexpr->inputcollid, NULL, NULL);
972 
973  /* Evaluate scalar directly into left function argument */
974  ExecInitExprRec(scalararg, state,
975  &fcinfo->args[0].value, &fcinfo->args[0].isnull);
976 
977  /*
978  * Evaluate array argument into our return value. There's no
979  * danger in that, because the return value is guaranteed to
980  * be overwritten by EEOP_SCALARARRAYOP, and will not be
981  * passed to any other expression.
982  */
983  ExecInitExprRec(arrayarg, state, resv, resnull);
984 
985  /* And perform the operation */
986  scratch.opcode = EEOP_SCALARARRAYOP;
987  scratch.d.scalararrayop.element_type = InvalidOid;
988  scratch.d.scalararrayop.useOr = opexpr->useOr;
989  scratch.d.scalararrayop.finfo = finfo;
990  scratch.d.scalararrayop.fcinfo_data = fcinfo;
991  scratch.d.scalararrayop.fn_addr = finfo->fn_addr;
992  ExprEvalPushStep(state, &scratch);
993  break;
994  }
995 
996  case T_BoolExpr:
997  {
998  BoolExpr *boolexpr = (BoolExpr *) node;
999  int nargs = list_length(boolexpr->args);
1000  List *adjust_jumps = NIL;
1001  int off;
1002  ListCell *lc;
1003 
1004  /* allocate scratch memory used by all steps of AND/OR */
1005  if (boolexpr->boolop != NOT_EXPR)
1006  scratch.d.boolexpr.anynull = (bool *) palloc(sizeof(bool));
1007 
1008  /*
1009  * For each argument evaluate the argument itself, then
1010  * perform the bool operation's appropriate handling.
1011  *
1012  * We can evaluate each argument into our result area, since
1013  * the short-circuiting logic means we only need to remember
1014  * previous NULL values.
1015  *
1016  * AND/OR is split into separate STEP_FIRST (one) / STEP (zero
1017  * or more) / STEP_LAST (one) steps, as each of those has to
1018  * perform different work. The FIRST/LAST split is valid
1019  * because AND/OR have at least two arguments.
1020  */
1021  off = 0;
1022  foreach(lc, boolexpr->args)
1023  {
1024  Expr *arg = (Expr *) lfirst(lc);
1025 
1026  /* Evaluate argument into our output variable */
1027  ExecInitExprRec(arg, state, resv, resnull);
1028 
1029  /* Perform the appropriate step type */
1030  switch (boolexpr->boolop)
1031  {
1032  case AND_EXPR:
1033  Assert(nargs >= 2);
1034 
1035  if (off == 0)
1036  scratch.opcode = EEOP_BOOL_AND_STEP_FIRST;
1037  else if (off + 1 == nargs)
1038  scratch.opcode = EEOP_BOOL_AND_STEP_LAST;
1039  else
1040  scratch.opcode = EEOP_BOOL_AND_STEP;
1041  break;
1042  case OR_EXPR:
1043  Assert(nargs >= 2);
1044 
1045  if (off == 0)
1046  scratch.opcode = EEOP_BOOL_OR_STEP_FIRST;
1047  else if (off + 1 == nargs)
1048  scratch.opcode = EEOP_BOOL_OR_STEP_LAST;
1049  else
1050  scratch.opcode = EEOP_BOOL_OR_STEP;
1051  break;
1052  case NOT_EXPR:
1053  Assert(nargs == 1);
1054 
1055  scratch.opcode = EEOP_BOOL_NOT_STEP;
1056  break;
1057  default:
1058  elog(ERROR, "unrecognized boolop: %d",
1059  (int) boolexpr->boolop);
1060  break;
1061  }
1062 
1063  scratch.d.boolexpr.jumpdone = -1;
1064  ExprEvalPushStep(state, &scratch);
1065  adjust_jumps = lappend_int(adjust_jumps,
1066  state->steps_len - 1);
1067  off++;
1068  }
1069 
1070  /* adjust jump targets */
1071  foreach(lc, adjust_jumps)
1072  {
1073  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
1074 
1075  Assert(as->d.boolexpr.jumpdone == -1);
1076  as->d.boolexpr.jumpdone = state->steps_len;
1077  }
1078 
1079  break;
1080  }
1081 
1082  case T_SubPlan:
1083  {
1084  SubPlan *subplan = (SubPlan *) node;
1085  SubPlanState *sstate;
1086 
1087  if (!state->parent)
1088  elog(ERROR, "SubPlan found with no parent plan");
1089 
1090  sstate = ExecInitSubPlan(subplan, state->parent);
1091 
1092  /* add SubPlanState nodes to state->parent->subPlan */
1093  state->parent->subPlan = lappend(state->parent->subPlan,
1094  sstate);
1095 
1096  scratch.opcode = EEOP_SUBPLAN;
1097  scratch.d.subplan.sstate = sstate;
1098 
1099  ExprEvalPushStep(state, &scratch);
1100  break;
1101  }
1102 
1103  case T_FieldSelect:
1104  {
1105  FieldSelect *fselect = (FieldSelect *) node;
1106 
1107  /* evaluate row/record argument into result area */
1108  ExecInitExprRec(fselect->arg, state, resv, resnull);
1109 
1110  /* and extract field */
1111  scratch.opcode = EEOP_FIELDSELECT;
1112  scratch.d.fieldselect.fieldnum = fselect->fieldnum;
1113  scratch.d.fieldselect.resulttype = fselect->resulttype;
1114  scratch.d.fieldselect.argdesc = NULL;
1115 
1116  ExprEvalPushStep(state, &scratch);
1117  break;
1118  }
1119 
1120  case T_FieldStore:
1121  {
1122  FieldStore *fstore = (FieldStore *) node;
1123  TupleDesc tupDesc;
1124  TupleDesc *descp;
1125  Datum *values;
1126  bool *nulls;
1127  int ncolumns;
1128  ListCell *l1,
1129  *l2;
1130 
1131  /* find out the number of columns in the composite type */
1132  tupDesc = lookup_rowtype_tupdesc(fstore->resulttype, -1);
1133  ncolumns = tupDesc->natts;
1134  DecrTupleDescRefCount(tupDesc);
1135 
1136  /* create workspace for column values */
1137  values = (Datum *) palloc(sizeof(Datum) * ncolumns);
1138  nulls = (bool *) palloc(sizeof(bool) * ncolumns);
1139 
1140  /* create workspace for runtime tupdesc cache */
1141  descp = (TupleDesc *) palloc(sizeof(TupleDesc));
1142  *descp = NULL;
1143 
1144  /* emit code to evaluate the composite input value */
1145  ExecInitExprRec(fstore->arg, state, resv, resnull);
1146 
1147  /* next, deform the input tuple into our workspace */
1148  scratch.opcode = EEOP_FIELDSTORE_DEFORM;
1149  scratch.d.fieldstore.fstore = fstore;
1150  scratch.d.fieldstore.argdesc = descp;
1151  scratch.d.fieldstore.values = values;
1152  scratch.d.fieldstore.nulls = nulls;
1153  scratch.d.fieldstore.ncolumns = ncolumns;
1154  ExprEvalPushStep(state, &scratch);
1155 
1156  /* evaluate new field values, store in workspace columns */
1157  forboth(l1, fstore->newvals, l2, fstore->fieldnums)
1158  {
1159  Expr *e = (Expr *) lfirst(l1);
1160  AttrNumber fieldnum = lfirst_int(l2);
1161  Datum *save_innermost_caseval;
1162  bool *save_innermost_casenull;
1163 
1164  if (fieldnum <= 0 || fieldnum > ncolumns)
1165  elog(ERROR, "field number %d is out of range in FieldStore",
1166  fieldnum);
1167 
1168  /*
1169  * Use the CaseTestExpr mechanism to pass down the old
1170  * value of the field being replaced; this is needed in
1171  * case the newval is itself a FieldStore or
1172  * SubscriptingRef that has to obtain and modify the old
1173  * value. It's safe to reuse the CASE mechanism because
1174  * there cannot be a CASE between here and where the value
1175  * would be needed, and a field assignment can't be within
1176  * a CASE either. (So saving and restoring
1177  * innermost_caseval is just paranoia, but let's do it
1178  * anyway.)
1179  *
1180  * Another non-obvious point is that it's safe to use the
1181  * field's values[]/nulls[] entries as both the caseval
1182  * source and the result address for this subexpression.
1183  * That's okay only because (1) both FieldStore and
1184  * SubscriptingRef evaluate their arg or refexpr inputs
1185  * first, and (2) any such CaseTestExpr is directly the
1186  * arg or refexpr input. So any read of the caseval will
1187  * occur before there's a chance to overwrite it. Also,
1188  * if multiple entries in the newvals/fieldnums lists
1189  * target the same field, they'll effectively be applied
1190  * left-to-right which is what we want.
1191  */
1192  save_innermost_caseval = state->innermost_caseval;
1193  save_innermost_casenull = state->innermost_casenull;
1194  state->innermost_caseval = &values[fieldnum - 1];
1195  state->innermost_casenull = &nulls[fieldnum - 1];
1196 
1197  ExecInitExprRec(e, state,
1198  &values[fieldnum - 1],
1199  &nulls[fieldnum - 1]);
1200 
1201  state->innermost_caseval = save_innermost_caseval;
1202  state->innermost_casenull = save_innermost_casenull;
1203  }
1204 
1205  /* finally, form result tuple */
1206  scratch.opcode = EEOP_FIELDSTORE_FORM;
1207  scratch.d.fieldstore.fstore = fstore;
1208  scratch.d.fieldstore.argdesc = descp;
1209  scratch.d.fieldstore.values = values;
1210  scratch.d.fieldstore.nulls = nulls;
1211  scratch.d.fieldstore.ncolumns = ncolumns;
1212  ExprEvalPushStep(state, &scratch);
1213  break;
1214  }
1215 
1216  case T_RelabelType:
1217  {
1218  /* relabel doesn't need to do anything at runtime */
1219  RelabelType *relabel = (RelabelType *) node;
1220 
1221  ExecInitExprRec(relabel->arg, state, resv, resnull);
1222  break;
1223  }
1224 
1225  case T_CoerceViaIO:
1226  {
1227  CoerceViaIO *iocoerce = (CoerceViaIO *) node;
1228  Oid iofunc;
1229  bool typisvarlena;
1230  Oid typioparam;
1231  FunctionCallInfo fcinfo_in;
1232 
1233  /* evaluate argument into step's result area */
1234  ExecInitExprRec(iocoerce->arg, state, resv, resnull);
1235 
1236  /*
1237  * Prepare both output and input function calls, to be
1238  * evaluated inside a single evaluation step for speed - this
1239  * can be a very common operation.
1240  *
1241  * We don't check permissions here as a type's input/output
1242  * function are assumed to be executable by everyone.
1243  */
1244  scratch.opcode = EEOP_IOCOERCE;
1245 
1246  /* lookup the source type's output function */
1247  scratch.d.iocoerce.finfo_out = palloc0(sizeof(FmgrInfo));
1248  scratch.d.iocoerce.fcinfo_data_out = palloc0(SizeForFunctionCallInfo(1));
1249 
1250  getTypeOutputInfo(exprType((Node *) iocoerce->arg),
1251  &iofunc, &typisvarlena);
1252  fmgr_info(iofunc, scratch.d.iocoerce.finfo_out);
1253  fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_out);
1254  InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_out,
1255  scratch.d.iocoerce.finfo_out,
1256  1, InvalidOid, NULL, NULL);
1257 
1258  /* lookup the result type's input function */
1259  scratch.d.iocoerce.finfo_in = palloc0(sizeof(FmgrInfo));
1260  scratch.d.iocoerce.fcinfo_data_in = palloc0(SizeForFunctionCallInfo(3));
1261 
1262  getTypeInputInfo(iocoerce->resulttype,
1263  &iofunc, &typioparam);
1264  fmgr_info(iofunc, scratch.d.iocoerce.finfo_in);
1265  fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_in);
1266  InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_in,
1267  scratch.d.iocoerce.finfo_in,
1268  3, InvalidOid, NULL, NULL);
1269 
1270  /*
1271  * We can preload the second and third arguments for the input
1272  * function, since they're constants.
1273  */
1274  fcinfo_in = scratch.d.iocoerce.fcinfo_data_in;
1275  fcinfo_in->args[1].value = ObjectIdGetDatum(typioparam);
1276  fcinfo_in->args[1].isnull = false;
1277  fcinfo_in->args[2].value = Int32GetDatum(-1);
1278  fcinfo_in->args[2].isnull = false;
1279 
1280  ExprEvalPushStep(state, &scratch);
1281  break;
1282  }
1283 
1284  case T_ArrayCoerceExpr:
1285  {
1286  ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
1287  Oid resultelemtype;
1288  ExprState *elemstate;
1289 
1290  /* evaluate argument into step's result area */
1291  ExecInitExprRec(acoerce->arg, state, resv, resnull);
1292 
1293  resultelemtype = get_element_type(acoerce->resulttype);
1294  if (!OidIsValid(resultelemtype))
1295  ereport(ERROR,
1296  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1297  errmsg("target type is not an array")));
1298 
1299  /*
1300  * Construct a sub-expression for the per-element expression;
1301  * but don't ready it until after we check it for triviality.
1302  * We assume it hasn't any Var references, but does have a
1303  * CaseTestExpr representing the source array element values.
1304  */
1305  elemstate = makeNode(ExprState);
1306  elemstate->expr = acoerce->elemexpr;
1307  elemstate->parent = state->parent;
1308  elemstate->ext_params = state->ext_params;
1309 
1310  elemstate->innermost_caseval = (Datum *) palloc(sizeof(Datum));
1311  elemstate->innermost_casenull = (bool *) palloc(sizeof(bool));
1312 
1313  ExecInitExprRec(acoerce->elemexpr, elemstate,
1314  &elemstate->resvalue, &elemstate->resnull);
1315 
1316  if (elemstate->steps_len == 1 &&
1317  elemstate->steps[0].opcode == EEOP_CASE_TESTVAL)
1318  {
1319  /* Trivial, so we need no per-element work at runtime */
1320  elemstate = NULL;
1321  }
1322  else
1323  {
1324  /* Not trivial, so append a DONE step */
1325  scratch.opcode = EEOP_DONE;
1326  ExprEvalPushStep(elemstate, &scratch);
1327  /* and ready the subexpression */
1328  ExecReadyExpr(elemstate);
1329  }
1330 
1331  scratch.opcode = EEOP_ARRAYCOERCE;
1332  scratch.d.arraycoerce.elemexprstate = elemstate;
1333  scratch.d.arraycoerce.resultelemtype = resultelemtype;
1334 
1335  if (elemstate)
1336  {
1337  /* Set up workspace for array_map */
1338  scratch.d.arraycoerce.amstate =
1339  (ArrayMapState *) palloc0(sizeof(ArrayMapState));
1340  }
1341  else
1342  {
1343  /* Don't need workspace if there's no subexpression */
1344  scratch.d.arraycoerce.amstate = NULL;
1345  }
1346 
1347  ExprEvalPushStep(state, &scratch);
1348  break;
1349  }
1350 
1351  case T_ConvertRowtypeExpr:
1352  {
1354 
1355  /* evaluate argument into step's result area */
1356  ExecInitExprRec(convert->arg, state, resv, resnull);
1357 
1358  /* and push conversion step */
1359  scratch.opcode = EEOP_CONVERT_ROWTYPE;
1360  scratch.d.convert_rowtype.convert = convert;
1361  scratch.d.convert_rowtype.indesc = NULL;
1362  scratch.d.convert_rowtype.outdesc = NULL;
1363  scratch.d.convert_rowtype.map = NULL;
1364  scratch.d.convert_rowtype.initialized = false;
1365 
1366  ExprEvalPushStep(state, &scratch);
1367  break;
1368  }
1369 
1370  /* note that CaseWhen expressions are handled within this block */
1371  case T_CaseExpr:
1372  {
1373  CaseExpr *caseExpr = (CaseExpr *) node;
1374  List *adjust_jumps = NIL;
1375  Datum *caseval = NULL;
1376  bool *casenull = NULL;
1377  ListCell *lc;
1378 
1379  /*
1380  * If there's a test expression, we have to evaluate it and
1381  * save the value where the CaseTestExpr placeholders can find
1382  * it.
1383  */
1384  if (caseExpr->arg != NULL)
1385  {
1386  /* Evaluate testexpr into caseval/casenull workspace */
1387  caseval = palloc(sizeof(Datum));
1388  casenull = palloc(sizeof(bool));
1389 
1390  ExecInitExprRec(caseExpr->arg, state,
1391  caseval, casenull);
1392 
1393  /*
1394  * Since value might be read multiple times, force to R/O
1395  * - but only if it could be an expanded datum.
1396  */
1397  if (get_typlen(exprType((Node *) caseExpr->arg)) == -1)
1398  {
1399  /* change caseval in-place */
1400  scratch.opcode = EEOP_MAKE_READONLY;
1401  scratch.resvalue = caseval;
1402  scratch.resnull = casenull;
1403  scratch.d.make_readonly.value = caseval;
1404  scratch.d.make_readonly.isnull = casenull;
1405  ExprEvalPushStep(state, &scratch);
1406  /* restore normal settings of scratch fields */
1407  scratch.resvalue = resv;
1408  scratch.resnull = resnull;
1409  }
1410  }
1411 
1412  /*
1413  * Prepare to evaluate each of the WHEN clauses in turn; as
1414  * soon as one is true we return the value of the
1415  * corresponding THEN clause. If none are true then we return
1416  * the value of the ELSE clause, or NULL if there is none.
1417  */
1418  foreach(lc, caseExpr->args)
1419  {
1420  CaseWhen *when = (CaseWhen *) lfirst(lc);
1421  Datum *save_innermost_caseval;
1422  bool *save_innermost_casenull;
1423  int whenstep;
1424 
1425  /*
1426  * Make testexpr result available to CaseTestExpr nodes
1427  * within the condition. We must save and restore prior
1428  * setting of innermost_caseval fields, in case this node
1429  * is itself within a larger CASE.
1430  *
1431  * If there's no test expression, we don't actually need
1432  * to save and restore these fields; but it's less code to
1433  * just do so unconditionally.
1434  */
1435  save_innermost_caseval = state->innermost_caseval;
1436  save_innermost_casenull = state->innermost_casenull;
1437  state->innermost_caseval = caseval;
1438  state->innermost_casenull = casenull;
1439 
1440  /* evaluate condition into CASE's result variables */
1441  ExecInitExprRec(when->expr, state, resv, resnull);
1442 
1443  state->innermost_caseval = save_innermost_caseval;
1444  state->innermost_casenull = save_innermost_casenull;
1445 
1446  /* If WHEN result isn't true, jump to next CASE arm */
1447  scratch.opcode = EEOP_JUMP_IF_NOT_TRUE;
1448  scratch.d.jump.jumpdone = -1; /* computed later */
1449  ExprEvalPushStep(state, &scratch);
1450  whenstep = state->steps_len - 1;
1451 
1452  /*
1453  * If WHEN result is true, evaluate THEN result, storing
1454  * it into the CASE's result variables.
1455  */
1456  ExecInitExprRec(when->result, state, resv, resnull);
1457 
1458  /* Emit JUMP step to jump to end of CASE's code */
1459  scratch.opcode = EEOP_JUMP;
1460  scratch.d.jump.jumpdone = -1; /* computed later */
1461  ExprEvalPushStep(state, &scratch);
1462 
1463  /*
1464  * Don't know address for that jump yet, compute once the
1465  * whole CASE expression is built.
1466  */
1467  adjust_jumps = lappend_int(adjust_jumps,
1468  state->steps_len - 1);
1469 
1470  /*
1471  * But we can set WHEN test's jump target now, to make it
1472  * jump to the next WHEN subexpression or the ELSE.
1473  */
1474  state->steps[whenstep].d.jump.jumpdone = state->steps_len;
1475  }
1476 
1477  /* transformCaseExpr always adds a default */
1478  Assert(caseExpr->defresult);
1479 
1480  /* evaluate ELSE expr into CASE's result variables */
1481  ExecInitExprRec(caseExpr->defresult, state,
1482  resv, resnull);
1483 
1484  /* adjust jump targets */
1485  foreach(lc, adjust_jumps)
1486  {
1487  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
1488 
1489  Assert(as->opcode == EEOP_JUMP);
1490  Assert(as->d.jump.jumpdone == -1);
1491  as->d.jump.jumpdone = state->steps_len;
1492  }
1493 
1494  break;
1495  }
1496 
1497  case T_CaseTestExpr:
1498  {
1499  /*
1500  * Read from location identified by innermost_caseval. Note
1501  * that innermost_caseval could be NULL, if this node isn't
1502  * actually within a CaseExpr, ArrayCoerceExpr, etc structure.
1503  * That can happen because some parts of the system abuse
1504  * CaseTestExpr to cause a read of a value externally supplied
1505  * in econtext->caseValue_datum. We'll take care of that
1506  * scenario at runtime.
1507  */
1508  scratch.opcode = EEOP_CASE_TESTVAL;
1509  scratch.d.casetest.value = state->innermost_caseval;
1510  scratch.d.casetest.isnull = state->innermost_casenull;
1511 
1512  ExprEvalPushStep(state, &scratch);
1513  break;
1514  }
1515 
1516  case T_ArrayExpr:
1517  {
1518  ArrayExpr *arrayexpr = (ArrayExpr *) node;
1519  int nelems = list_length(arrayexpr->elements);
1520  ListCell *lc;
1521  int elemoff;
1522 
1523  /*
1524  * Evaluate by computing each element, and then forming the
1525  * array. Elements are computed into scratch arrays
1526  * associated with the ARRAYEXPR step.
1527  */
1528  scratch.opcode = EEOP_ARRAYEXPR;
1529  scratch.d.arrayexpr.elemvalues =
1530  (Datum *) palloc(sizeof(Datum) * nelems);
1531  scratch.d.arrayexpr.elemnulls =
1532  (bool *) palloc(sizeof(bool) * nelems);
1533  scratch.d.arrayexpr.nelems = nelems;
1534 
1535  /* fill remaining fields of step */
1536  scratch.d.arrayexpr.multidims = arrayexpr->multidims;
1537  scratch.d.arrayexpr.elemtype = arrayexpr->element_typeid;
1538 
1539  /* do one-time catalog lookup for type info */
1541  &scratch.d.arrayexpr.elemlength,
1542  &scratch.d.arrayexpr.elembyval,
1543  &scratch.d.arrayexpr.elemalign);
1544 
1545  /* prepare to evaluate all arguments */
1546  elemoff = 0;
1547  foreach(lc, arrayexpr->elements)
1548  {
1549  Expr *e = (Expr *) lfirst(lc);
1550 
1551  ExecInitExprRec(e, state,
1552  &scratch.d.arrayexpr.elemvalues[elemoff],
1553  &scratch.d.arrayexpr.elemnulls[elemoff]);
1554  elemoff++;
1555  }
1556 
1557  /* and then collect all into an array */
1558  ExprEvalPushStep(state, &scratch);
1559  break;
1560  }
1561 
1562  case T_RowExpr:
1563  {
1564  RowExpr *rowexpr = (RowExpr *) node;
1565  int nelems = list_length(rowexpr->args);
1566  TupleDesc tupdesc;
1567  int i;
1568  ListCell *l;
1569 
1570  /* Build tupdesc to describe result tuples */
1571  if (rowexpr->row_typeid == RECORDOID)
1572  {
1573  /* generic record, use types of given expressions */
1574  tupdesc = ExecTypeFromExprList(rowexpr->args);
1575  }
1576  else
1577  {
1578  /* it's been cast to a named type, use that */
1579  tupdesc = lookup_rowtype_tupdesc_copy(rowexpr->row_typeid, -1);
1580  }
1581  /* In either case, adopt RowExpr's column aliases */
1582  ExecTypeSetColNames(tupdesc, rowexpr->colnames);
1583  /* Bless the tupdesc in case it's now of type RECORD */
1584  BlessTupleDesc(tupdesc);
1585 
1586  /*
1587  * In the named-type case, the tupdesc could have more columns
1588  * than are in the args list, since the type might have had
1589  * columns added since the ROW() was parsed. We want those
1590  * extra columns to go to nulls, so we make sure that the
1591  * workspace arrays are large enough and then initialize any
1592  * extra columns to read as NULLs.
1593  */
1594  Assert(nelems <= tupdesc->natts);
1595  nelems = Max(nelems, tupdesc->natts);
1596 
1597  /*
1598  * Evaluate by first building datums for each field, and then
1599  * a final step forming the composite datum.
1600  */
1601  scratch.opcode = EEOP_ROW;
1602  scratch.d.row.tupdesc = tupdesc;
1603 
1604  /* space for the individual field datums */
1605  scratch.d.row.elemvalues =
1606  (Datum *) palloc(sizeof(Datum) * nelems);
1607  scratch.d.row.elemnulls =
1608  (bool *) palloc(sizeof(bool) * nelems);
1609  /* as explained above, make sure any extra columns are null */
1610  memset(scratch.d.row.elemnulls, true, sizeof(bool) * nelems);
1611 
1612  /* Set up evaluation, skipping any deleted columns */
1613  i = 0;
1614  foreach(l, rowexpr->args)
1615  {
1616  Form_pg_attribute att = TupleDescAttr(tupdesc, i);
1617  Expr *e = (Expr *) lfirst(l);
1618 
1619  if (!att->attisdropped)
1620  {
1621  /*
1622  * Guard against ALTER COLUMN TYPE on rowtype since
1623  * the RowExpr was created. XXX should we check
1624  * typmod too? Not sure we can be sure it'll be the
1625  * same.
1626  */
1627  if (exprType((Node *) e) != att->atttypid)
1628  ereport(ERROR,
1629  (errcode(ERRCODE_DATATYPE_MISMATCH),
1630  errmsg("ROW() column has type %s instead of type %s",
1631  format_type_be(exprType((Node *) e)),
1632  format_type_be(att->atttypid))));
1633  }
1634  else
1635  {
1636  /*
1637  * Ignore original expression and insert a NULL. We
1638  * don't really care what type of NULL it is, so
1639  * always make an int4 NULL.
1640  */
1641  e = (Expr *) makeNullConst(INT4OID, -1, InvalidOid);
1642  }
1643 
1644  /* Evaluate column expr into appropriate workspace slot */
1645  ExecInitExprRec(e, state,
1646  &scratch.d.row.elemvalues[i],
1647  &scratch.d.row.elemnulls[i]);
1648  i++;
1649  }
1650 
1651  /* And finally build the row value */
1652  ExprEvalPushStep(state, &scratch);
1653  break;
1654  }
1655 
1656  case T_RowCompareExpr:
1657  {
1658  RowCompareExpr *rcexpr = (RowCompareExpr *) node;
1659  int nopers = list_length(rcexpr->opnos);
1660  List *adjust_jumps = NIL;
1661  ListCell *l_left_expr,
1662  *l_right_expr,
1663  *l_opno,
1664  *l_opfamily,
1665  *l_inputcollid;
1666  ListCell *lc;
1667 
1668  /*
1669  * Iterate over each field, prepare comparisons. To handle
1670  * NULL results, prepare jumps to after the expression. If a
1671  * comparison yields a != 0 result, jump to the final step.
1672  */
1673  Assert(list_length(rcexpr->largs) == nopers);
1674  Assert(list_length(rcexpr->rargs) == nopers);
1675  Assert(list_length(rcexpr->opfamilies) == nopers);
1676  Assert(list_length(rcexpr->inputcollids) == nopers);
1677 
1678  forfive(l_left_expr, rcexpr->largs,
1679  l_right_expr, rcexpr->rargs,
1680  l_opno, rcexpr->opnos,
1681  l_opfamily, rcexpr->opfamilies,
1682  l_inputcollid, rcexpr->inputcollids)
1683  {
1684  Expr *left_expr = (Expr *) lfirst(l_left_expr);
1685  Expr *right_expr = (Expr *) lfirst(l_right_expr);
1686  Oid opno = lfirst_oid(l_opno);
1687  Oid opfamily = lfirst_oid(l_opfamily);
1688  Oid inputcollid = lfirst_oid(l_inputcollid);
1689  int strategy;
1690  Oid lefttype;
1691  Oid righttype;
1692  Oid proc;
1693  FmgrInfo *finfo;
1694  FunctionCallInfo fcinfo;
1695 
1696  get_op_opfamily_properties(opno, opfamily, false,
1697  &strategy,
1698  &lefttype,
1699  &righttype);
1700  proc = get_opfamily_proc(opfamily,
1701  lefttype,
1702  righttype,
1703  BTORDER_PROC);
1704  if (!OidIsValid(proc))
1705  elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
1706  BTORDER_PROC, lefttype, righttype, opfamily);
1707 
1708  /* Set up the primary fmgr lookup information */
1709  finfo = palloc0(sizeof(FmgrInfo));
1710  fcinfo = palloc0(SizeForFunctionCallInfo(2));
1711  fmgr_info(proc, finfo);
1712  fmgr_info_set_expr((Node *) node, finfo);
1713  InitFunctionCallInfoData(*fcinfo, finfo, 2,
1714  inputcollid, NULL, NULL);
1715 
1716  /*
1717  * If we enforced permissions checks on index support
1718  * functions, we'd need to make a check here. But the
1719  * index support machinery doesn't do that, and thus
1720  * neither does this code.
1721  */
1722 
1723  /* evaluate left and right args directly into fcinfo */
1724  ExecInitExprRec(left_expr, state,
1725  &fcinfo->args[0].value, &fcinfo->args[0].isnull);
1726  ExecInitExprRec(right_expr, state,
1727  &fcinfo->args[1].value, &fcinfo->args[1].isnull);
1728 
1729  scratch.opcode = EEOP_ROWCOMPARE_STEP;
1730  scratch.d.rowcompare_step.finfo = finfo;
1731  scratch.d.rowcompare_step.fcinfo_data = fcinfo;
1732  scratch.d.rowcompare_step.fn_addr = finfo->fn_addr;
1733  /* jump targets filled below */
1734  scratch.d.rowcompare_step.jumpnull = -1;
1735  scratch.d.rowcompare_step.jumpdone = -1;
1736 
1737  ExprEvalPushStep(state, &scratch);
1738  adjust_jumps = lappend_int(adjust_jumps,
1739  state->steps_len - 1);
1740  }
1741 
1742  /*
1743  * We could have a zero-column rowtype, in which case the rows
1744  * necessarily compare equal.
1745  */
1746  if (nopers == 0)
1747  {
1748  scratch.opcode = EEOP_CONST;
1749  scratch.d.constval.value = Int32GetDatum(0);
1750  scratch.d.constval.isnull = false;
1751  ExprEvalPushStep(state, &scratch);
1752  }
1753 
1754  /* Finally, examine the last comparison result */
1755  scratch.opcode = EEOP_ROWCOMPARE_FINAL;
1756  scratch.d.rowcompare_final.rctype = rcexpr->rctype;
1757  ExprEvalPushStep(state, &scratch);
1758 
1759  /* adjust jump targets */
1760  foreach(lc, adjust_jumps)
1761  {
1762  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
1763 
1765  Assert(as->d.rowcompare_step.jumpdone == -1);
1766  Assert(as->d.rowcompare_step.jumpnull == -1);
1767 
1768  /* jump to comparison evaluation */
1769  as->d.rowcompare_step.jumpdone = state->steps_len - 1;
1770  /* jump to the following expression */
1771  as->d.rowcompare_step.jumpnull = state->steps_len;
1772  }
1773 
1774  break;
1775  }
1776 
1777  case T_CoalesceExpr:
1778  {
1779  CoalesceExpr *coalesce = (CoalesceExpr *) node;
1780  List *adjust_jumps = NIL;
1781  ListCell *lc;
1782 
1783  /* We assume there's at least one arg */
1784  Assert(coalesce->args != NIL);
1785 
1786  /*
1787  * Prepare evaluation of all coalesced arguments, after each
1788  * one push a step that short-circuits if not null.
1789  */
1790  foreach(lc, coalesce->args)
1791  {
1792  Expr *e = (Expr *) lfirst(lc);
1793 
1794  /* evaluate argument, directly into result datum */
1795  ExecInitExprRec(e, state, resv, resnull);
1796 
1797  /* if it's not null, skip to end of COALESCE expr */
1798  scratch.opcode = EEOP_JUMP_IF_NOT_NULL;
1799  scratch.d.jump.jumpdone = -1; /* adjust later */
1800  ExprEvalPushStep(state, &scratch);
1801 
1802  adjust_jumps = lappend_int(adjust_jumps,
1803  state->steps_len - 1);
1804  }
1805 
1806  /*
1807  * No need to add a constant NULL return - we only can get to
1808  * the end of the expression if a NULL already is being
1809  * returned.
1810  */
1811 
1812  /* adjust jump targets */
1813  foreach(lc, adjust_jumps)
1814  {
1815  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
1816 
1818  Assert(as->d.jump.jumpdone == -1);
1819  as->d.jump.jumpdone = state->steps_len;
1820  }
1821 
1822  break;
1823  }
1824 
1825  case T_MinMaxExpr:
1826  {
1827  MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
1828  int nelems = list_length(minmaxexpr->args);
1829  TypeCacheEntry *typentry;
1830  FmgrInfo *finfo;
1831  FunctionCallInfo fcinfo;
1832  ListCell *lc;
1833  int off;
1834 
1835  /* Look up the btree comparison function for the datatype */
1836  typentry = lookup_type_cache(minmaxexpr->minmaxtype,
1838  if (!OidIsValid(typentry->cmp_proc))
1839  ereport(ERROR,
1840  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1841  errmsg("could not identify a comparison function for type %s",
1842  format_type_be(minmaxexpr->minmaxtype))));
1843 
1844  /*
1845  * If we enforced permissions checks on index support
1846  * functions, we'd need to make a check here. But the index
1847  * support machinery doesn't do that, and thus neither does
1848  * this code.
1849  */
1850 
1851  /* Perform function lookup */
1852  finfo = palloc0(sizeof(FmgrInfo));
1853  fcinfo = palloc0(SizeForFunctionCallInfo(2));
1854  fmgr_info(typentry->cmp_proc, finfo);
1855  fmgr_info_set_expr((Node *) node, finfo);
1856  InitFunctionCallInfoData(*fcinfo, finfo, 2,
1857  minmaxexpr->inputcollid, NULL, NULL);
1858 
1859  scratch.opcode = EEOP_MINMAX;
1860  /* allocate space to store arguments */
1861  scratch.d.minmax.values =
1862  (Datum *) palloc(sizeof(Datum) * nelems);
1863  scratch.d.minmax.nulls =
1864  (bool *) palloc(sizeof(bool) * nelems);
1865  scratch.d.minmax.nelems = nelems;
1866 
1867  scratch.d.minmax.op = minmaxexpr->op;
1868  scratch.d.minmax.finfo = finfo;
1869  scratch.d.minmax.fcinfo_data = fcinfo;
1870 
1871  /* evaluate expressions into minmax->values/nulls */
1872  off = 0;
1873  foreach(lc, minmaxexpr->args)
1874  {
1875  Expr *e = (Expr *) lfirst(lc);
1876 
1877  ExecInitExprRec(e, state,
1878  &scratch.d.minmax.values[off],
1879  &scratch.d.minmax.nulls[off]);
1880  off++;
1881  }
1882 
1883  /* and push the final comparison */
1884  ExprEvalPushStep(state, &scratch);
1885  break;
1886  }
1887 
1888  case T_SQLValueFunction:
1889  {
1890  SQLValueFunction *svf = (SQLValueFunction *) node;
1891 
1892  scratch.opcode = EEOP_SQLVALUEFUNCTION;
1893  scratch.d.sqlvaluefunction.svf = svf;
1894 
1895  ExprEvalPushStep(state, &scratch);
1896  break;
1897  }
1898 
1899  case T_XmlExpr:
1900  {
1901  XmlExpr *xexpr = (XmlExpr *) node;
1902  int nnamed = list_length(xexpr->named_args);
1903  int nargs = list_length(xexpr->args);
1904  int off;
1905  ListCell *arg;
1906 
1907  scratch.opcode = EEOP_XMLEXPR;
1908  scratch.d.xmlexpr.xexpr = xexpr;
1909 
1910  /* allocate space for storing all the arguments */
1911  if (nnamed)
1912  {
1913  scratch.d.xmlexpr.named_argvalue =
1914  (Datum *) palloc(sizeof(Datum) * nnamed);
1915  scratch.d.xmlexpr.named_argnull =
1916  (bool *) palloc(sizeof(bool) * nnamed);
1917  }
1918  else
1919  {
1920  scratch.d.xmlexpr.named_argvalue = NULL;
1921  scratch.d.xmlexpr.named_argnull = NULL;
1922  }
1923 
1924  if (nargs)
1925  {
1926  scratch.d.xmlexpr.argvalue =
1927  (Datum *) palloc(sizeof(Datum) * nargs);
1928  scratch.d.xmlexpr.argnull =
1929  (bool *) palloc(sizeof(bool) * nargs);
1930  }
1931  else
1932  {
1933  scratch.d.xmlexpr.argvalue = NULL;
1934  scratch.d.xmlexpr.argnull = NULL;
1935  }
1936 
1937  /* prepare argument execution */
1938  off = 0;
1939  foreach(arg, xexpr->named_args)
1940  {
1941  Expr *e = (Expr *) lfirst(arg);
1942 
1943  ExecInitExprRec(e, state,
1944  &scratch.d.xmlexpr.named_argvalue[off],
1945  &scratch.d.xmlexpr.named_argnull[off]);
1946  off++;
1947  }
1948 
1949  off = 0;
1950  foreach(arg, xexpr->args)
1951  {
1952  Expr *e = (Expr *) lfirst(arg);
1953 
1954  ExecInitExprRec(e, state,
1955  &scratch.d.xmlexpr.argvalue[off],
1956  &scratch.d.xmlexpr.argnull[off]);
1957  off++;
1958  }
1959 
1960  /* and evaluate the actual XML expression */
1961  ExprEvalPushStep(state, &scratch);
1962  break;
1963  }
1964 
1965  case T_NullTest:
1966  {
1967  NullTest *ntest = (NullTest *) node;
1968 
1969  if (ntest->nulltesttype == IS_NULL)
1970  {
1971  if (ntest->argisrow)
1972  scratch.opcode = EEOP_NULLTEST_ROWISNULL;
1973  else
1974  scratch.opcode = EEOP_NULLTEST_ISNULL;
1975  }
1976  else if (ntest->nulltesttype == IS_NOT_NULL)
1977  {
1978  if (ntest->argisrow)
1980  else
1981  scratch.opcode = EEOP_NULLTEST_ISNOTNULL;
1982  }
1983  else
1984  {
1985  elog(ERROR, "unrecognized nulltesttype: %d",
1986  (int) ntest->nulltesttype);
1987  }
1988  /* initialize cache in case it's a row test */
1989  scratch.d.nulltest_row.argdesc = NULL;
1990 
1991  /* first evaluate argument into result variable */
1992  ExecInitExprRec(ntest->arg, state,
1993  resv, resnull);
1994 
1995  /* then push the test of that argument */
1996  ExprEvalPushStep(state, &scratch);
1997  break;
1998  }
1999 
2000  case T_BooleanTest:
2001  {
2002  BooleanTest *btest = (BooleanTest *) node;
2003 
2004  /*
2005  * Evaluate argument, directly into result datum. That's ok,
2006  * because resv/resnull is definitely not used anywhere else,
2007  * and will get overwritten by the below EEOP_BOOLTEST_IS_*
2008  * step.
2009  */
2010  ExecInitExprRec(btest->arg, state, resv, resnull);
2011 
2012  switch (btest->booltesttype)
2013  {
2014  case IS_TRUE:
2015  scratch.opcode = EEOP_BOOLTEST_IS_TRUE;
2016  break;
2017  case IS_NOT_TRUE:
2019  break;
2020  case IS_FALSE:
2021  scratch.opcode = EEOP_BOOLTEST_IS_FALSE;
2022  break;
2023  case IS_NOT_FALSE:
2025  break;
2026  case IS_UNKNOWN:
2027  /* Same as scalar IS NULL test */
2028  scratch.opcode = EEOP_NULLTEST_ISNULL;
2029  break;
2030  case IS_NOT_UNKNOWN:
2031  /* Same as scalar IS NOT NULL test */
2032  scratch.opcode = EEOP_NULLTEST_ISNOTNULL;
2033  break;
2034  default:
2035  elog(ERROR, "unrecognized booltesttype: %d",
2036  (int) btest->booltesttype);
2037  }
2038 
2039  ExprEvalPushStep(state, &scratch);
2040  break;
2041  }
2042 
2043  case T_CoerceToDomain:
2044  {
2045  CoerceToDomain *ctest = (CoerceToDomain *) node;
2046 
2047  ExecInitCoerceToDomain(&scratch, ctest, state,
2048  resv, resnull);
2049  break;
2050  }
2051 
2052  case T_CoerceToDomainValue:
2053  {
2054  /*
2055  * Read from location identified by innermost_domainval. Note
2056  * that innermost_domainval could be NULL, if we're compiling
2057  * a standalone domain check rather than one embedded in a
2058  * larger expression. In that case we must read from
2059  * econtext->domainValue_datum. We'll take care of that
2060  * scenario at runtime.
2061  */
2062  scratch.opcode = EEOP_DOMAIN_TESTVAL;
2063  /* we share instruction union variant with case testval */
2064  scratch.d.casetest.value = state->innermost_domainval;
2065  scratch.d.casetest.isnull = state->innermost_domainnull;
2066 
2067  ExprEvalPushStep(state, &scratch);
2068  break;
2069  }
2070 
2071  case T_CurrentOfExpr:
2072  {
2073  scratch.opcode = EEOP_CURRENTOFEXPR;
2074  ExprEvalPushStep(state, &scratch);
2075  break;
2076  }
2077 
2078  case T_NextValueExpr:
2079  {
2080  NextValueExpr *nve = (NextValueExpr *) node;
2081 
2082  scratch.opcode = EEOP_NEXTVALUEEXPR;
2083  scratch.d.nextvalueexpr.seqid = nve->seqid;
2084  scratch.d.nextvalueexpr.seqtypid = nve->typeId;
2085 
2086  ExprEvalPushStep(state, &scratch);
2087  break;
2088  }
2089 
2090  default:
2091  elog(ERROR, "unrecognized node type: %d",
2092  (int) nodeTag(node));
2093  break;
2094  }
2095 }
Datum constvalue
Definition: primnodes.h:214
struct ExprEvalStep::@51::@71 arraycoerce
struct ExprEvalStep::@51::@63 param
Oid minmaxtype
Definition: primnodes.h:1117
bool multidims
Definition: primnodes.h:1007
#define NIL
Definition: pg_list.h:65
static void ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:2759
Definition: fmgr.h:56
struct ExprEvalStep::@51::@86 window_func
List * args
Definition: primnodes.h:1121
List * args
Definition: primnodes.h:1037
#define IsA(nodeptr, _type_)
Definition: nodes.h:578
static void ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, ExprState *state)
Definition: execExpr.c:2449
#define BTORDER_PROC
Definition: nbtree.h:575
struct ExprEvalStep::@51::@74 rowcompare_final
struct ExprEvalStep::@51::@70 arrayexpr
Expr * arg
Definition: primnodes.h:806
struct PlanState * parent
Definition: execnodes.h:107
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:434
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2789
ExprState * aggfilter
Definition: execnodes.h:758
List * args
Definition: primnodes.h:385
List * args
Definition: primnodes.h:489
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1741
Datum * resvalue
Definition: execExpr.h:252
Oid GetUserId(void)
Definition: miscinit.c:476
Oid resulttype
Definition: primnodes.h:779
PGFunction fn_addr
Definition: fmgr.h:58
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2641
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2164
struct ExprEvalStep * steps
Definition: execnodes.h:84
struct ExprEvalStep::@51::@81 convert_rowtype
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
bool * innermost_casenull
Definition: execnodes.h:111
struct ExprEvalStep::@51::@85 grouping_func
Oid resulttype
Definition: primnodes.h:850
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
struct ExprEvalStep::@51::@57 constval
RowCompareType rctype
Definition: primnodes.h:1085
List * opfamilies
Definition: primnodes.h:1087
bool * resnull
Definition: execExpr.h:253
List * subPlan
Definition: execnodes.h:955
ParamListInfo ext_params
Definition: execnodes.h:108
struct ExprEvalStep::@51::@77 fieldstore
Expr * arg
Definition: primnodes.h:829
ParamKind paramkind
Definition: primnodes.h:262
Definition: nodes.h:527
int errcode(int sqlerrcode)
Definition: elog.c:691
AttrNumber varattno
Definition: primnodes.h:186
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
Expr * arg
Definition: primnodes.h:777
Datum * innermost_domainval
Definition: execnodes.h:113
EState * state
Definition: execnodes.h:930
struct ExprEvalStep::@51::@67 iocoerce
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:181
#define OidIsValid(objectId)
Definition: c.h:706
struct ExprEvalStep::@51::@82 scalararrayop
#define lsecond(l)
Definition: pg_list.h:179
bool * innermost_domainnull
Definition: execnodes.h:114
SubPlanState * ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
Definition: nodeSubplan.c:789
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:337
struct ExprEvalStep::@51::@72 row
static void ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:2522
ParamCompileHook paramCompile
Definition: params.h:114
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
static void convert(const int32 val, char *const buf)
Definition: zic.c:1990
#define linitial(l)
Definition: pg_list.h:174
Oid funcid
Definition: primnodes.h:481
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
struct ExprEvalStep::@51::@87 subplan
List * colnames
Definition: primnodes.h:1053
bool resnull
Definition: execnodes.h:71
Expr * expr
Definition: execnodes.h:93
#define lfirst_int(lc)
Definition: pg_list.h:170
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1525
Oid vartype
Definition: primnodes.h:188
List * args
Definition: primnodes.h:1101
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
BoolExprType boolop
Definition: primnodes.h:594
Expr * arg
Definition: primnodes.h:1234
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2052
void check_stack_depth(void)
Definition: postgres.c:3317
Expr * arg
Definition: primnodes.h:1257
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:317
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
Oid resulttype
Definition: primnodes.h:809
Expr * arg
Definition: primnodes.h:849
List * elements
Definition: primnodes.h:1006
Expr * elemexpr
Definition: primnodes.h:874
Definition: type.h:82
Datum * innermost_caseval
Definition: execnodes.h:110
struct ExprEvalStep::@51::@76 fieldselect
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2756
struct ExprEvalStep::@51::@68 sqlvaluefunction
Datum value
Definition: postgres.h:378
List * lappend_int(List *list, int datum)
Definition: list.c:339
List * newvals
Definition: primnodes.h:807
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:191
List * cols
Definition: primnodes.h:370
union ExprEvalStep::@51 d
Definition: nodes.h:154
List * lappend(List *list, void *datum)
Definition: list.c:321
Index varno
Definition: primnodes.h:184
Definition: nodes.h:153
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:645
List * args
Definition: primnodes.h:948
void * palloc0(Size size)
Definition: mcxt.c:981
AclResult
Definition: acl.h:177
BoolTestType booltesttype
Definition: primnodes.h:1258
struct ExprEvalStep::@51::@66 make_readonly
uintptr_t Datum
Definition: postgres.h:367
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2104
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:628
Oid opfuncid
Definition: primnodes.h:529
List * groupingSets
Definition: plannodes.h:829
struct ExprEvalStep::@51::@59 boolexpr
struct ExprEvalStep::@51::@53 var
NullTestType nulltesttype
Definition: primnodes.h:1235
struct ExprEvalStep::@51::@69 nextvalueexpr
Plan * plan
Definition: execnodes.h:928
struct ExprEvalStep::@51::@83 xmlexpr
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:334
#define InvalidOid
Definition: postgres_ext.h:36
List * named_args
Definition: primnodes.h:1198
#define ereport(elevel,...)
Definition: elog.h:155
#define INNER_VAR
Definition: primnodes.h:171
struct ExprEvalStep::@51::@62 nulltest_row
List * args
Definition: primnodes.h:1200
#define TYPECACHE_CMP_PROC
Definition: typcache.h:133
int aggno
Definition: primnodes.h:335
#define Max(x, y)
Definition: c.h:976
#define makeNode(_type_)
Definition: nodes.h:575
struct ExprEvalStep::@51::@73 rowcompare_step
Oid inputcollid
Definition: primnodes.h:488
#define Assert(condition)
Definition: c.h:800
#define lfirst(lc)
Definition: pg_list.h:169
intptr_t opcode
Definition: execExpr.h:249
Expr * aggfilter
Definition: primnodes.h:386
void DecrTupleDescRefCount(TupleDesc tupdesc)
Definition: tupdesc.c:393
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:794
int paramid
Definition: primnodes.h:263
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
Oid row_typeid
Definition: primnodes.h:1038
static int list_length(const List *l)
Definition: pg_list.h:149
Oid inputcollid
Definition: primnodes.h:1119
Oid inputcollid
Definition: primnodes.h:533
static void ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, Oid inputcollid, ExprState *state)
Definition: execExpr.c:2130
struct ExprEvalStep::@51::@65 casetest
List * args
Definition: primnodes.h:595
#define InvalidAttrNumber
Definition: attnum.h:23
#define nodeTag(nodeptr)
Definition: nodes.h:532
Oid element_typeid
Definition: primnodes.h:1005
static Datum values[MAXATTR]
Definition: bootstrap.c:165
struct ExprEvalStep::@51::@84 aggref
#define Int32GetDatum(X)
Definition: postgres.h:479
e
Definition: preproc-init.c:82
void get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op, int *strategy, Oid *lefttype, Oid *righttype)
Definition: lsyscache.c:134
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2090
TupleDesc ExecTypeFromExprList(List *exprList)
Definition: execTuples.c:1967
void * palloc(Size size)
Definition: mcxt.c:950
int errmsg(const char *fmt,...)
Definition: elog.c:902
int steps_len
Definition: execnodes.h:103
#define ACL_EXECUTE
Definition: parsenodes.h:81
List * fieldnums
Definition: primnodes.h:808
bool winagg
Definition: primnodes.h:389
#define elog(elevel,...)
Definition: elog.h:228
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4587
#define forfive(cell1, list1, cell2, list2, cell3, list3, cell4, list4, cell5, list5)
Definition: pg_list.h:504
int i
void * arg
struct ExprEvalStep::@51::@61 jump
ParamListInfo es_param_list_info
Definition: execnodes.h:553
bool argisrow
Definition: primnodes.h:1236
MinMaxOp op
Definition: primnodes.h:1120
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:122
Expr * arg
Definition: primnodes.h:947
Definition: plannodes.h:816
struct ExprEvalStep::@51::@75 minmax
WindowFunc * wfunc
Definition: execnodes.h:756
List * aggs
Definition: execnodes.h:2133
Expr * result
Definition: primnodes.h:960
List * args
Definition: primnodes.h:534
List * inputcollids
Definition: primnodes.h:1088
Expr * defresult
Definition: primnodes.h:949
Expr * expr
Definition: primnodes.h:959
Definition: pg_list.h:50
Datum resvalue
Definition: execnodes.h:73
int16 AttrNumber
Definition: attnum.h:21
#define OUTER_VAR
Definition: primnodes.h:172
void ExecTypeSetColNames(TupleDesc typeInfo, List *namesList)
Definition: execTuples.c:2006
Oid paramtype
Definition: primnodes.h:264
bool constisnull
Definition: primnodes.h:215
#define lfirst_oid(lc)
Definition: pg_list.h:171
TupleDesc lookup_rowtype_tupdesc_copy(Oid type_id, int32 typmod)
Definition: typcache.c:1775
Definition: nodes.h:155
AttrNumber fieldnum
Definition: primnodes.h:778

◆ ExecInitExprSlots()

static void ExecInitExprSlots ( ExprState state,
Node node 
)
static

Definition at line 2235 of file execExpr.c.

References ExecPushExprSlots(), and get_last_attnums_walker().

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

2236 {
2237  LastAttnumInfo info = {0, 0, 0};
2238 
2239  /*
2240  * Figure out which attributes we're going to need.
2241  */
2242  get_last_attnums_walker(node, &info);
2243 
2244  ExecPushExprSlots(state, &info);
2245 }
static void ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
Definition: execExpr.c:2253
static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info)
Definition: execExpr.c:2297

◆ ExecInitExprWithParams()

ExprState* ExecInitExprWithParams ( Expr node,
ParamListInfo  ext_params 
)

Definition at line 159 of file execExpr.c.

References EEOP_DONE, ExecInitExprRec(), ExecInitExprSlots(), ExecReadyExpr(), ExprState::expr, ExprEvalPushStep(), ExprState::ext_params, makeNode, ExprEvalStep::opcode, ExprState::parent, ExprState::resnull, and ExprState::resvalue.

Referenced by exec_eval_simple_expr(), and ExecProcNode().

160 {
161  ExprState *state;
162  ExprEvalStep scratch = {0};
163 
164  /* Special case: NULL expression produces a NULL ExprState pointer */
165  if (node == NULL)
166  return NULL;
167 
168  /* Initialize ExprState with empty step list */
169  state = makeNode(ExprState);
170  state->expr = node;
171  state->parent = NULL;
172  state->ext_params = ext_params;
173 
174  /* Insert EEOP_*_FETCHSOME steps as needed */
175  ExecInitExprSlots(state, (Node *) node);
176 
177  /* Compile the expression proper */
178  ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
179 
180  /* Finally, append a DONE step */
181  scratch.opcode = EEOP_DONE;
182  ExprEvalPushStep(state, &scratch);
183 
184  ExecReadyExpr(state);
185 
186  return state;
187 }
struct PlanState * parent
Definition: execnodes.h:107
ParamListInfo ext_params
Definition: execnodes.h:108
Definition: nodes.h:527
bool resnull
Definition: execnodes.h:71
Expr * expr
Definition: execnodes.h:93
static void ExecInitExprSlots(ExprState *state, Node *node)
Definition: execExpr.c:2235
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:645
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2104
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:628
#define makeNode(_type_)
Definition: nodes.h:575
Definition: regguts.h:298
intptr_t opcode
Definition: execExpr.h:249
Datum resvalue
Definition: execnodes.h:73

◆ ExecInitFunc()

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

Definition at line 2130 of file execExpr.c.

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

Referenced by ExecInitExprRec().

2132 {
2133  int nargs = list_length(args);
2134  AclResult aclresult;
2135  FmgrInfo *flinfo;
2136  FunctionCallInfo fcinfo;
2137  int argno;
2138  ListCell *lc;
2139 
2140  /* Check permission to call function */
2141  aclresult = pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE);
2142  if (aclresult != ACLCHECK_OK)
2143  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(funcid));
2144  InvokeFunctionExecuteHook(funcid);
2145 
2146  /*
2147  * Safety check on nargs. Under normal circumstances this should never
2148  * fail, as parser should check sooner. But possibly it might fail if
2149  * server has been compiled with FUNC_MAX_ARGS smaller than some functions
2150  * declared in pg_proc?
2151  */
2152  if (nargs > FUNC_MAX_ARGS)
2153  ereport(ERROR,
2154  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2155  errmsg_plural("cannot pass more than %d argument to a function",
2156  "cannot pass more than %d arguments to a function",
2157  FUNC_MAX_ARGS,
2158  FUNC_MAX_ARGS)));
2159 
2160  /* Allocate function lookup data and parameter workspace for this call */
2161  scratch->d.func.finfo = palloc0(sizeof(FmgrInfo));
2162  scratch->d.func.fcinfo_data = palloc0(SizeForFunctionCallInfo(nargs));
2163  flinfo = scratch->d.func.finfo;
2164  fcinfo = scratch->d.func.fcinfo_data;
2165 
2166  /* Set up the primary fmgr lookup information */
2167  fmgr_info(funcid, flinfo);
2168  fmgr_info_set_expr((Node *) node, flinfo);
2169 
2170  /* Initialize function call parameter structure too */
2171  InitFunctionCallInfoData(*fcinfo, flinfo,
2172  nargs, inputcollid, NULL, NULL);
2173 
2174  /* Keep extra copies of this info to save an indirection at runtime */
2175  scratch->d.func.fn_addr = flinfo->fn_addr;
2176  scratch->d.func.nargs = nargs;
2177 
2178  /* We only support non-set functions here */
2179  if (flinfo->fn_retset)
2180  ereport(ERROR,
2181  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2182  errmsg("set-valued function called in context that cannot accept a set"),
2183  state->parent ?
2185  exprLocation((Node *) node)) : 0));
2186 
2187  /* Build code to evaluate arguments directly into the fcinfo struct */
2188  argno = 0;
2189  foreach(lc, args)
2190  {
2191  Expr *arg = (Expr *) lfirst(lc);
2192 
2193  if (IsA(arg, Const))
2194  {
2195  /*
2196  * Don't evaluate const arguments every round; especially
2197  * interesting for constants in comparisons.
2198  */
2199  Const *con = (Const *) arg;
2200 
2201  fcinfo->args[argno].value = con->constvalue;
2202  fcinfo->args[argno].isnull = con->constisnull;
2203  }
2204  else
2205  {
2206  ExecInitExprRec(arg, state,
2207  &fcinfo->args[argno].value,
2208  &fcinfo->args[argno].isnull);
2209  }
2210  argno++;
2211  }
2212 
2213  /* Insert appropriate opcode depending on strictness and stats level */
2214  if (pgstat_track_functions <= flinfo->fn_stats)
2215  {
2216  if (flinfo->fn_strict && nargs > 0)
2217  scratch->opcode = EEOP_FUNCEXPR_STRICT;
2218  else
2219  scratch->opcode = EEOP_FUNCEXPR;
2220  }
2221  else
2222  {
2223  if (flinfo->fn_strict && nargs > 0)
2225  else
2226  scratch->opcode = EEOP_FUNCEXPR_FUSAGE;
2227  }
2228 }
Datum constvalue
Definition: primnodes.h:214
Definition: fmgr.h:56
#define IsA(nodeptr, _type_)
Definition: nodes.h:578
struct PlanState * parent
Definition: execnodes.h:107
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1240
Oid GetUserId(void)
Definition: miscinit.c:476
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1012
PGFunction fn_addr
Definition: fmgr.h:58
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
Definition: nodes.h:527
int errcode(int sqlerrcode)
Definition: elog.c:691
EState * state
Definition: execnodes.h:930
struct ExprEvalStep::@51::@58 func
#define FUNC_MAX_ARGS
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
bool fn_retset
Definition: fmgr.h:62
#define ERROR
Definition: elog.h:43
bool fn_strict
Definition: fmgr.h:61
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1525
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
Datum value
Definition: postgres.h:378
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:191
union ExprEvalStep::@51 d
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:645
void * palloc0(Size size)
Definition: mcxt.c:981
AclResult
Definition: acl.h:177
#define ereport(elevel,...)
Definition: elog.h:155
int executor_errposition(EState *estate, int location)
Definition: execUtils.c:897
#define lfirst(lc)
Definition: pg_list.h:169
intptr_t opcode
Definition: execExpr.h:249
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
static int list_length(const List *l)
Definition: pg_list.h:149
int errmsg(const char *fmt,...)
Definition: elog.c:902
#define ACL_EXECUTE
Definition: parsenodes.h:81
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4587
void * arg
bool constisnull
Definition: primnodes.h:215

◆ ExecInitQual()

ExprState* ExecInitQual ( List qual,
PlanState parent 
)

Definition at line 208 of file execExpr.c.

References Assert, ExprEvalStep::d, EEO_FLAG_IS_QUAL, EEOP_DONE, EEOP_QUAL, ExecInitExprRec(), ExecInitExprSlots(), ExecReadyExpr(), ExprState::expr, ExprEvalPushStep(), ExprState::ext_params, ExprState::flags, IsA, lappend_int(), lfirst, lfirst_int, makeNode, NIL, ExprEvalStep::opcode, ExprState::parent, ExprEvalStep::qualexpr, ExprState::resnull, ExprEvalStep::resnull, ExprState::resvalue, ExprEvalStep::resvalue, ExprState::steps, and ExprState::steps_len.

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

209 {
210  ExprState *state;
211  ExprEvalStep scratch = {0};
212  List *adjust_jumps = NIL;
213  ListCell *lc;
214 
215  /* short-circuit (here and in ExecQual) for empty restriction list */
216  if (qual == NIL)
217  return NULL;
218 
219  Assert(IsA(qual, List));
220 
221  state = makeNode(ExprState);
222  state->expr = (Expr *) qual;
223  state->parent = parent;
224  state->ext_params = NULL;
225 
226  /* mark expression as to be used with ExecQual() */
227  state->flags = EEO_FLAG_IS_QUAL;
228 
229  /* Insert EEOP_*_FETCHSOME steps as needed */
230  ExecInitExprSlots(state, (Node *) qual);
231 
232  /*
233  * ExecQual() needs to return false for an expression returning NULL. That
234  * allows us to short-circuit the evaluation the first time a NULL is
235  * encountered. As qual evaluation is a hot-path this warrants using a
236  * special opcode for qual evaluation that's simpler than BOOL_AND (which
237  * has more complex NULL handling).
238  */
239  scratch.opcode = EEOP_QUAL;
240 
241  /*
242  * We can use ExprState's resvalue/resnull as target for each qual expr.
243  */
244  scratch.resvalue = &state->resvalue;
245  scratch.resnull = &state->resnull;
246 
247  foreach(lc, qual)
248  {
249  Expr *node = (Expr *) lfirst(lc);
250 
251  /* first evaluate expression */
252  ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
253 
254  /* then emit EEOP_QUAL to detect if it's false (or null) */
255  scratch.d.qualexpr.jumpdone = -1;
256  ExprEvalPushStep(state, &scratch);
257  adjust_jumps = lappend_int(adjust_jumps,
258  state->steps_len - 1);
259  }
260 
261  /* adjust jump targets */
262  foreach(lc, adjust_jumps)
263  {
264  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
265 
266  Assert(as->opcode == EEOP_QUAL);
267  Assert(as->d.qualexpr.jumpdone == -1);
268  as->d.qualexpr.jumpdone = state->steps_len;
269  }
270 
271  /*
272  * At the end, we don't need to do anything more. The last qual expr must
273  * have yielded TRUE, and since its result is stored in the desired output
274  * location, we're done.
275  */
276  scratch.opcode = EEOP_DONE;
277  ExprEvalPushStep(state, &scratch);
278 
279  ExecReadyExpr(state);
280 
281  return state;
282 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:578
struct PlanState * parent
Definition: execnodes.h:107
Datum * resvalue
Definition: execExpr.h:252
struct ExprEvalStep * steps
Definition: execnodes.h:84
bool * resnull
Definition: execExpr.h:253
ParamListInfo ext_params
Definition: execnodes.h:108
Definition: nodes.h:527
bool resnull
Definition: execnodes.h:71
Expr * expr
Definition: execnodes.h:93
#define lfirst_int(lc)
Definition: pg_list.h:170
static void ExecInitExprSlots(ExprState *state, Node *node)
Definition: execExpr.c:2235
#define EEO_FLAG_IS_QUAL
Definition: execnodes.h:58
List * lappend_int(List *list, int datum)
Definition: list.c:339
union ExprEvalStep::@51 d
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:645
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2104
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:628
#define makeNode(_type_)
Definition: nodes.h:575
#define Assert(condition)
Definition: c.h:800
#define lfirst(lc)
Definition: pg_list.h:169
Definition: regguts.h:298
intptr_t opcode
Definition: execExpr.h:249
int steps_len
Definition: execnodes.h:103
uint8 flags
Definition: execnodes.h:64
Definition: pg_list.h:50
Datum resvalue
Definition: execnodes.h:73
struct ExprEvalStep::@51::@60 qualexpr

◆ ExecInitSubscriptingRef()

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

Definition at line 2522 of file execExpr.c.

References Assert, ExprEvalStep::d, EEOP_JUMP_IF_NULL, EEOP_SBSREF_ASSIGN, EEOP_SBSREF_FETCH, EEOP_SBSREF_OLD, EEOP_SBSREF_SUBSCRIPT, elog, ereport, errcode(), errmsg(), ERROR, ExecInitExprRec(), ExprEvalPushStep(), get_typlen(), get_typlenbyvalalign(), i, ExprState::innermost_casenull, ExprState::innermost_caseval, SubscriptingRefState::isassignment, isAssignmentIndirectionExpr(), ExprEvalStep::jump, lappend_int(), lfirst, lfirst_int, list_length(), SubscriptingRefState::lowerprovided, MAXDIM, NIL, SubscriptingRefState::numlower, SubscriptingRefState::numupper, ExprEvalStep::opcode, palloc0(), SubscriptingRefState::prevnull, SubscriptingRefState::prevvalue, SubscriptingRef::refassgnexpr, SubscriptingRefState::refattrlength, SubscriptingRef::refcontainertype, SubscriptingRefState::refelemalign, SubscriptingRefState::refelembyval, SubscriptingRefState::refelemlength, SubscriptingRef::refelemtype, SubscriptingRefState::refelemtype, SubscriptingRef::refexpr, SubscriptingRef::reflowerindexpr, SubscriptingRef::refupperindexpr, SubscriptingRefState::replacenull, SubscriptingRefState::replacevalue, ExprEvalStep::sbsref, ExprEvalStep::sbsref_subscript, ExprState::steps, ExprState::steps_len, SubscriptingRefState::subscriptnull, SubscriptingRefState::subscriptvalue, and SubscriptingRefState::upperprovided.

Referenced by ExecInitExprRec().

2524 {
2525  bool isAssignment = (sbsref->refassgnexpr != NULL);
2526  SubscriptingRefState *sbsrefstate = palloc0(sizeof(SubscriptingRefState));
2527  List *adjust_jumps = NIL;
2528  ListCell *lc;
2529  int i;
2530 
2531  /* Fill constant fields of SubscriptingRefState */
2532  sbsrefstate->isassignment = isAssignment;
2533  sbsrefstate->refelemtype = sbsref->refelemtype;
2534  sbsrefstate->refattrlength = get_typlen(sbsref->refcontainertype);
2536  &sbsrefstate->refelemlength,
2537  &sbsrefstate->refelembyval,
2538  &sbsrefstate->refelemalign);
2539 
2540  /*
2541  * Evaluate array input. It's safe to do so into resv/resnull, because we
2542  * won't use that as target for any of the other subexpressions, and it'll
2543  * be overwritten by the final EEOP_SBSREF_FETCH/ASSIGN step, which is
2544  * pushed last.
2545  */
2546  ExecInitExprRec(sbsref->refexpr, state, resv, resnull);
2547 
2548  /*
2549  * If refexpr yields NULL, and it's a fetch, then result is NULL. We can
2550  * implement this with just JUMP_IF_NULL, since we evaluated the array
2551  * into the desired target location.
2552  */
2553  if (!isAssignment)
2554  {
2555  scratch->opcode = EEOP_JUMP_IF_NULL;
2556  scratch->d.jump.jumpdone = -1; /* adjust later */
2557  ExprEvalPushStep(state, scratch);
2558  adjust_jumps = lappend_int(adjust_jumps,
2559  state->steps_len - 1);
2560  }
2561 
2562  /* Verify subscript list lengths are within limit */
2563  if (list_length(sbsref->refupperindexpr) > MAXDIM)
2564  ereport(ERROR,
2565  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2566  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
2567  list_length(sbsref->refupperindexpr), MAXDIM)));
2568 
2569  if (list_length(sbsref->reflowerindexpr) > MAXDIM)
2570  ereport(ERROR,
2571  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2572  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
2573  list_length(sbsref->reflowerindexpr), MAXDIM)));
2574 
2575  /* Evaluate upper subscripts */
2576  i = 0;
2577  foreach(lc, sbsref->refupperindexpr)
2578  {
2579  Expr *e = (Expr *) lfirst(lc);
2580 
2581  /* When slicing, individual subscript bounds can be omitted */
2582  if (!e)
2583  {
2584  sbsrefstate->upperprovided[i] = false;
2585  i++;
2586  continue;
2587  }
2588 
2589  sbsrefstate->upperprovided[i] = true;
2590 
2591  /* Each subscript is evaluated into subscriptvalue/subscriptnull */
2592  ExecInitExprRec(e, state,
2593  &sbsrefstate->subscriptvalue, &sbsrefstate->subscriptnull);
2594 
2595  /* ... and then SBSREF_SUBSCRIPT saves it into step's workspace */
2596  scratch->opcode = EEOP_SBSREF_SUBSCRIPT;
2597  scratch->d.sbsref_subscript.state = sbsrefstate;
2598  scratch->d.sbsref_subscript.off = i;
2599  scratch->d.sbsref_subscript.isupper = true;
2600  scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */
2601  ExprEvalPushStep(state, scratch);
2602  adjust_jumps = lappend_int(adjust_jumps,
2603  state->steps_len - 1);
2604  i++;
2605  }
2606  sbsrefstate->numupper = i;
2607 
2608  /* Evaluate lower subscripts similarly */
2609  i = 0;
2610  foreach(lc, sbsref->reflowerindexpr)
2611  {
2612  Expr *e = (Expr *) lfirst(lc);
2613 
2614  /* When slicing, individual subscript bounds can be omitted */
2615  if (!e)
2616  {
2617  sbsrefstate->lowerprovided[i] = false;
2618  i++;
2619  continue;
2620  }
2621 
2622  sbsrefstate->lowerprovided[i] = true;
2623 
2624  /* Each subscript is evaluated into subscriptvalue/subscriptnull */
2625  ExecInitExprRec(e, state,
2626  &sbsrefstate->subscriptvalue, &sbsrefstate->subscriptnull);
2627 
2628  /* ... and then SBSREF_SUBSCRIPT saves it into step's workspace */
2629  scratch->opcode = EEOP_SBSREF_SUBSCRIPT;
2630  scratch->d.sbsref_subscript.state = sbsrefstate;
2631  scratch->d.sbsref_subscript.off = i;
2632  scratch->d.sbsref_subscript.isupper = false;
2633  scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */
2634  ExprEvalPushStep(state, scratch);
2635  adjust_jumps = lappend_int(adjust_jumps,
2636  state->steps_len - 1);
2637  i++;
2638  }
2639  sbsrefstate->numlower = i;
2640 
2641  /* Should be impossible if parser is sane, but check anyway: */
2642  if (sbsrefstate->numlower != 0 &&
2643  sbsrefstate->numupper != sbsrefstate->numlower)
2644  elog(ERROR, "upper and lower index lists are not same length");
2645 
2646  if (isAssignment)
2647  {
2648  Datum *save_innermost_caseval;
2649  bool *save_innermost_casenull;
2650 
2651  /*
2652  * We might have a nested-assignment situation, in which the
2653  * refassgnexpr is itself a FieldStore or SubscriptingRef that needs
2654  * to obtain and modify the previous value of the array element or
2655  * slice being replaced. If so, we have to extract that value from
2656  * the array and pass it down via the CaseTestExpr mechanism. It's
2657  * safe to reuse the CASE mechanism because there cannot be a CASE
2658  * between here and where the value would be needed, and an array
2659  * assignment can't be within a CASE either. (So saving and restoring
2660  * innermost_caseval is just paranoia, but let's do it anyway.)
2661  *
2662  * Since fetching the old element might be a nontrivial expense, do it
2663  * only if the argument actually needs it.
2664  */
2666  {
2667  scratch->opcode = EEOP_SBSREF_OLD;
2668  scratch->d.sbsref.state = sbsrefstate;
2669  ExprEvalPushStep(state, scratch);
2670  }
2671 
2672  /* SBSREF_OLD puts extracted value into prevvalue/prevnull */
2673  save_innermost_caseval = state->innermost_caseval;
2674  save_innermost_casenull = state->innermost_casenull;
2675  state->innermost_caseval = &sbsrefstate->prevvalue;
2676  state->innermost_casenull = &sbsrefstate->prevnull;
2677 
2678  /* evaluate replacement value into replacevalue/replacenull */
2679  ExecInitExprRec(sbsref->refassgnexpr, state,
2680  &sbsrefstate->replacevalue, &sbsrefstate->replacenull);
2681 
2682  state->innermost_caseval = save_innermost_caseval;
2683  state->innermost_casenull = save_innermost_casenull;
2684 
2685  /* and perform the assignment */
2686  scratch->opcode = EEOP_SBSREF_ASSIGN;
2687  scratch->d.sbsref.state = sbsrefstate;
2688  ExprEvalPushStep(state, scratch);
2689 
2690  }
2691  else
2692  {
2693  /* array fetch is much simpler */
2694  scratch->opcode = EEOP_SBSREF_FETCH;
2695  scratch->d.sbsref.state = sbsrefstate;
2696  ExprEvalPushStep(state, scratch);
2697 
2698  }
2699 
2700  /* adjust jump targets */
2701  foreach(lc, adjust_jumps)
2702  {
2703  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
2704 
2705  if (as->opcode == EEOP_SBSREF_SUBSCRIPT)
2706  {
2707  Assert(as->d.sbsref_subscript.jumpdone == -1);
2708  as->d.sbsref_subscript.jumpdone = state->steps_len;
2709  }
2710  else
2711  {
2713  Assert(as->d.jump.jumpdone == -1);
2714  as->d.jump.jumpdone = state->steps_len;
2715  }
2716  }
2717 }
#define NIL
Definition: pg_list.h:65
struct ExprEvalStep::@51::@79 sbsref
#define MAXDIM
Definition: c.h:597
struct ExprEvalStep::@51::@78 sbsref_subscript
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2164
struct ExprEvalStep * steps
Definition: execnodes.h:84
bool * innermost_casenull
Definition: execnodes.h:111
static bool isAssignmentIndirectionExpr(Expr *expr)
Definition: execExpr.c:2734
int errcode(int sqlerrcode)
Definition: elog.c:691
List * refupperindexpr
Definition: primnodes.h:430
#define ERROR
Definition: elog.h:43
#define lfirst_int(lc)
Definition: pg_list.h:170
bool upperprovided[MAXDIM]
Definition: execExpr.h:652
Datum * innermost_caseval
Definition: execnodes.h:110
List * lappend_int(List *list, int datum)
Definition: list.c:339
union ExprEvalStep::@51 d
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:645
void * palloc0(Size size)
Definition: mcxt.c:981
uintptr_t Datum
Definition: postgres.h:367
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2104
bool lowerprovided[MAXDIM]
Definition: execExpr.h:657
#define ereport(elevel,...)
Definition: elog.h:155
#define Assert(condition)
Definition: c.h:800
#define lfirst(lc)
Definition: pg_list.h:169
intptr_t opcode
Definition: execExpr.h:249
static int list_length(const List *l)
Definition: pg_list.h:149
Expr * refassgnexpr
Definition: primnodes.h:438
e
Definition: preproc-init.c:82
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2090
int errmsg(const char *fmt,...)
Definition: elog.c:902
int steps_len
Definition: execnodes.h:103
List * reflowerindexpr
Definition: primnodes.h:432
#define elog(elevel,...)
Definition: elog.h:228
int i
struct ExprEvalStep::@51::@61 jump
Oid refcontainertype
Definition: primnodes.h:426
Expr * refexpr
Definition: primnodes.h:435
Definition: pg_list.h:50

◆ ExecInitWholeRowVar()

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

Definition at line 2449 of file execExpr.c.

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

Referenced by ExecInitExprRec().

2450 {
2451  PlanState *parent = state->parent;
2452 
2453  /* fill in all but the target */
2454  scratch->opcode = EEOP_WHOLEROW;
2455  scratch->d.wholerow.var = variable;
2456  scratch->d.wholerow.first = true;
2457  scratch->d.wholerow.slow = false;
2458  scratch->d.wholerow.tupdesc = NULL; /* filled at runtime */
2459  scratch->d.wholerow.junkFilter = NULL;
2460 
2461  /*
2462  * If the input tuple came from a subquery, it might contain "resjunk"
2463  * columns (such as GROUP BY or ORDER BY columns), which we don't want to
2464  * keep in the whole-row result. We can get rid of such columns by
2465  * passing the tuple through a JunkFilter --- but to make one, we have to
2466  * lay our hands on the subquery's targetlist. Fortunately, there are not
2467  * very many cases where this can happen, and we can identify all of them
2468  * by examining our parent PlanState. We assume this is not an issue in
2469  * standalone expressions that don't have parent plans. (Whole-row Vars
2470  * can occur in such expressions, but they will always be referencing
2471  * table rows.)
2472  */
2473  if (parent)
2474  {
2475  PlanState *subplan = NULL;
2476 
2477  switch (nodeTag(parent))
2478  {
2479  case T_SubqueryScanState:
2480  subplan = ((SubqueryScanState *) parent)->subplan;
2481  break;
2482  case T_CteScanState:
2483  subplan = ((CteScanState *) parent)->cteplanstate;
2484  break;
2485  default:
2486  break;
2487  }
2488 
2489  if (subplan)
2490  {
2491  bool junk_filter_needed = false;
2492  ListCell *tlist;
2493 
2494  /* Detect whether subplan tlist actually has any junk columns */
2495  foreach(tlist, subplan->plan->targetlist)
2496  {
2497  TargetEntry *tle = (TargetEntry *) lfirst(tlist);
2498 
2499  if (tle->resjunk)
2500  {
2501  junk_filter_needed = true;
2502  break;
2503  }
2504  }
2505 
2506  /* If so, build the junkfilter now */
2507  if (junk_filter_needed)
2508  {
2509  scratch->d.wholerow.junkFilter =
2511  ExecInitExtraTupleSlot(parent->state, NULL,
2512  &TTSOpsVirtual));
2513  }
2514  }
2515  }
2516 }
struct PlanState * parent
Definition: execnodes.h:107
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1801
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
EState * state
Definition: execnodes.h:930
bool resjunk
Definition: primnodes.h:1429
union ExprEvalStep::@51 d
Plan * plan
Definition: execnodes.h:928
#define lfirst(lc)
Definition: pg_list.h:169
intptr_t opcode
Definition: execExpr.h:249
#define nodeTag(nodeptr)
Definition: nodes.h:532
List * targetlist
Definition: plannodes.h:136
struct variable * variable
Definition: type.h:173
struct ExprEvalStep::@51::@54 wholerow
JunkFilter * ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
Definition: execJunk.c:60

◆ ExecPrepareCheck()

ExprState* ExecPrepareCheck ( List qual,
EState estate 
)

Definition at line 542 of file execExpr.c.

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

Referenced by ExecPartitionCheck(), and ExecProcNode().

543 {
544  ExprState *result;
545  MemoryContext oldcontext;
546 
547  oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
548 
549  qual = (List *) expression_planner((Expr *) qual);
550 
551  result = ExecInitCheck(qual, NULL);
552 
553  MemoryContextSwitchTo(oldcontext);
554 
555  return result;
556 }
ExprState * ExecInitCheck(List *qual, PlanState *parent)
Definition: execExpr.c:297
Expr * expression_planner(Expr *expr)
Definition: planner.c:6166
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext es_query_cxt
Definition: execnodes.h:559
Definition: pg_list.h:50

◆ ExecPrepareExpr()

ExprState* ExecPrepareExpr ( Expr node,
EState estate 
)

Definition at line 491 of file execExpr.c.

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

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

492 {
493  ExprState *result;
494  MemoryContext oldcontext;
495 
496  oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
497 
498  node = expression_planner(node);
499 
500  result = ExecInitExpr(node, NULL);
501 
502  MemoryContextSwitchTo(oldcontext);
503 
504  return result;
505 }
Expr * expression_planner(Expr *expr)
Definition: planner.c:6166
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext es_query_cxt
Definition: execnodes.h:559
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:122

◆ ExecPrepareExprList()

List* ExecPrepareExprList ( List nodes,
EState estate 
)

Definition at line 565 of file execExpr.c.

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

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

566 {
567  List *result = NIL;
568  MemoryContext oldcontext;
569  ListCell *lc;
570 
571  /* Ensure that the list cell nodes are in the right context too */
572  oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
573 
574  foreach(lc, nodes)
575  {
576  Expr *e = (Expr *) lfirst(lc);
577 
578  result = lappend(result, ExecPrepareExpr(e, estate));
579  }
580 
581  MemoryContextSwitchTo(oldcontext);
582 
583  return result;
584 }
#define NIL
Definition: pg_list.h:65
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:491
MemoryContext es_query_cxt
Definition: execnodes.h:559
List * lappend(List *list, void *datum)
Definition: list.c:321
#define lfirst(lc)
Definition: pg_list.h:169
e
Definition: preproc-init.c:82
Definition: pg_list.h:50

◆ ExecPrepareQual()

ExprState* ExecPrepareQual ( List qual,
EState estate 
)

Definition at line 519 of file execExpr.c.

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

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

520 {
521  ExprState *result;
522  MemoryContext oldcontext;
523 
524  oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
525 
526  qual = (List *) expression_planner((Expr *) qual);
527 
528  result = ExecInitQual(qual, NULL);
529 
530  MemoryContextSwitchTo(oldcontext);
531 
532  return result;
533 }
Expr * expression_planner(Expr *expr)
Definition: planner.c:6166
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:208
MemoryContext es_query_cxt
Definition: execnodes.h:559
Definition: pg_list.h:50

◆ ExecPushExprSlots()

static void ExecPushExprSlots ( ExprState state,
LastAttnumInfo info 
)
static

Definition at line 2253 of file execExpr.c.

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

Referenced by ExecBuildAggTrans(), and ExecInitExprSlots().

2254 {
2255  ExprEvalStep scratch = {0};
2256 
2257  scratch.resvalue = NULL;
2258  scratch.resnull = NULL;
2259 
2260  /* Emit steps as needed */
2261  if (info->last_inner > 0)
2262  {
2263  scratch.opcode = EEOP_INNER_FETCHSOME;
2264  scratch.d.fetch.last_var = info->last_inner;
2265  scratch.d.fetch.fixed = false;
2266  scratch.d.fetch.kind = NULL;
2267  scratch.d.fetch.known_desc = NULL;
2268  if (ExecComputeSlotInfo(state, &scratch))
2269  ExprEvalPushStep(state, &scratch);
2270  }
2271  if (info->last_outer > 0)
2272  {
2273  scratch.opcode = EEOP_OUTER_FETCHSOME;
2274  scratch.d.fetch.last_var = info->last_outer;
2275  scratch.d.fetch.fixed = false;
2276  scratch.d.fetch.kind = NULL;
2277  scratch.d.fetch.known_desc = NULL;
2278  if (ExecComputeSlotInfo(state, &scratch))
2279  ExprEvalPushStep(state, &scratch);
2280  }
2281  if (info->last_scan > 0)
2282  {
2283  scratch.opcode = EEOP_SCAN_FETCHSOME;
2284  scratch.d.fetch.last_var = info->last_scan;
2285  scratch.d.fetch.fixed = false;
2286  scratch.d.fetch.kind = NULL;
2287  scratch.d.fetch.known_desc = NULL;
2288  if (ExecComputeSlotInfo(state, &scratch))
2289  ExprEvalPushStep(state, &scratch);
2290  }
2291 }
Datum * resvalue
Definition: execExpr.h:252
struct ExprEvalStep::@51::@52 fetch
bool * resnull
Definition: execExpr.h:253
AttrNumber last_scan
Definition: execExpr.c:57
AttrNumber last_inner
Definition: execExpr.c:55
AttrNumber last_outer
Definition: execExpr.c:56
union ExprEvalStep::@51 d
static bool ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op)
Definition: execExpr.c:2351
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2104
intptr_t opcode
Definition: execExpr.h:249

◆ ExecReadyExpr()

static void ExecReadyExpr ( ExprState state)
static

Definition at line 628 of file execExpr.c.

References ExecReadyInterpretedExpr(), and jit_compile_expr().

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

629 {
630  if (jit_compile_expr(state))
631  return;
632 
634 }
void ExecReadyInterpretedExpr(ExprState *state)
bool jit_compile_expr(struct ExprState *state)
Definition: jit.c:153

◆ ExprEvalPushStep()

void ExprEvalPushStep ( ExprState es,
const ExprEvalStep s 
)

Definition at line 2104 of file execExpr.c.

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

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

2105 {
2106  if (es->steps_alloc == 0)
2107  {
2108  es->steps_alloc = 16;
2109  es->steps = palloc(sizeof(ExprEvalStep) * es->steps_alloc);
2110  }
2111  else if (es->steps_alloc == es->steps_len)
2112  {
2113  es->steps_alloc *= 2;
2114  es->steps = repalloc(es->steps,
2115  sizeof(ExprEvalStep) * es->steps_alloc);
2116  }
2117 
2118  memcpy(&es->steps[es->steps_len++], s, sizeof(ExprEvalStep));
2119 }
struct ExprEvalStep * steps
Definition: execnodes.h:84
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1070
int steps_alloc
Definition: execnodes.h:104
void * palloc(Size size)
Definition: mcxt.c:950
int steps_len
Definition: execnodes.h:103

◆ get_last_attnums_walker()

static bool get_last_attnums_walker ( Node node,
LastAttnumInfo info 
)
static

Definition at line 2297 of file execExpr.c.

References attnum, expression_tree_walker(), INNER_VAR, IsA, LastAttnumInfo::last_inner, LastAttnumInfo::last_outer, LastAttnumInfo::last_scan, Max, OUTER_VAR, Var::varattno, and Var::varno.

Referenced by ExecBuildAggTrans(), and ExecInitExprSlots().

2298 {
2299  if (node == NULL)
2300  return false;
2301  if (IsA(node, Var))
2302  {
2303  Var *variable = (Var *) node;
2304  AttrNumber attnum = variable->varattno;
2305 
2306  switch (variable->varno)
2307  {
2308  case INNER_VAR:
2309  info->last_inner = Max(info->last_inner, attnum);
2310  break;
2311 
2312  case OUTER_VAR:
2313  info->last_outer = Max(info->last_outer, attnum);
2314  break;
2315 
2316  /* INDEX_VAR is handled by default case */
2317 
2318  default:
2319  info->last_scan = Max(info->last_scan, attnum);
2320  break;
2321  }
2322  return false;
2323  }
2324 
2325  /*
2326  * Don't examine the arguments or filters of Aggrefs or WindowFuncs,
2327  * because those do not represent expressions to be evaluated within the
2328  * calling expression's econtext. GroupingFunc arguments are never
2329  * evaluated at all.
2330  */
2331  if (IsA(node, Aggref))
2332  return false;
2333  if (IsA(node, WindowFunc))
2334  return false;
2335  if (IsA(node, GroupingFunc))
2336  return false;
2338  (void *) info);
2339 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:578
AttrNumber varattno
Definition: primnodes.h:186
Definition: primnodes.h:181
AttrNumber last_scan
Definition: execExpr.c:57
AttrNumber last_inner
Definition: execExpr.c:55
AttrNumber last_outer
Definition: execExpr.c:56
Index varno
Definition: primnodes.h:184
int16 attnum
Definition: pg_attribute.h:79
#define INNER_VAR
Definition: primnodes.h:171
#define Max(x, y)
Definition: c.h:976
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1888
static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info)
Definition: execExpr.c:2297
int16 AttrNumber
Definition: attnum.h:21
#define OUTER_VAR
Definition: primnodes.h:172

◆ isAssignmentIndirectionExpr()

static bool isAssignmentIndirectionExpr ( Expr expr)
static

Definition at line 2734 of file execExpr.c.

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

Referenced by ExecInitSubscriptingRef().

2735 {
2736  if (expr == NULL)
2737  return false; /* just paranoia */
2738  if (IsA(expr, FieldStore))
2739  {
2740  FieldStore *fstore = (FieldStore *) expr;
2741 
2742  if (fstore->arg && IsA(fstore->arg, CaseTestExpr))
2743  return true;
2744  }
2745  else if (IsA(expr, SubscriptingRef))
2746  {
2747  SubscriptingRef *sbsRef = (SubscriptingRef *) expr;
2748 
2749  if (sbsRef->refexpr && IsA(sbsRef->refexpr, CaseTestExpr))
2750  return true;
2751  }
2752  return false;
2753 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:578
Expr * arg