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

Go to the source code of this file.

Data Structures

struct  ExprSetupInfo
 

Typedefs

typedef struct ExprSetupInfo ExprSetupInfo
 

Functions

static void ExecReadyExpr (ExprState *state)
 
static void ExecInitExprRec (Expr *node, ExprState *state, Datum *resv, bool *resnull)
 
static void ExecInitFunc (ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, Oid inputcollid, ExprState *state)
 
static void ExecInitSubPlanExpr (SubPlan *subplan, ExprState *state, Datum *resv, bool *resnull)
 
static void ExecCreateExprSetupSteps (ExprState *state, Node *node)
 
static void ExecPushExprSetupSteps (ExprState *state, ExprSetupInfo *info)
 
static bool expr_setup_walker (Node *node, ExprSetupInfo *info)
 
static bool ExecComputeSlotInfo (ExprState *state, ExprEvalStep *op)
 
static void ExecInitWholeRowVar (ExprEvalStep *scratch, Var *variable, ExprState *state)
 
static void ExecInitSubscriptingRef (ExprEvalStep *scratch, SubscriptingRef *sbsref, ExprState *state, Datum *resv, bool *resnull)
 
static bool isAssignmentIndirectionExpr (Expr *expr)
 
static void ExecInitCoerceToDomain (ExprEvalStep *scratch, CoerceToDomain *ctest, ExprState *state, Datum *resv, bool *resnull)
 
static void ExecBuildAggTransCall (ExprState *state, AggState *aggstate, ExprEvalStep *scratch, FunctionCallInfo fcinfo, AggStatePerTrans pertrans, int transno, int setno, int setoff, bool ishash, bool nullcheck)
 
static void ExecInitJsonExpr (JsonExpr *jsexpr, ExprState *state, Datum *resv, bool *resnull, ExprEvalStep *scratch)
 
static void ExecInitJsonCoercion (ExprState *state, JsonReturning *returning, ErrorSaveContext *escontext, bool omit_quotes, bool exists_coerce, Datum *resv, bool *resnull)
 
ExprStateExecInitExpr (Expr *node, PlanState *parent)
 
ExprStateExecInitExprWithParams (Expr *node, ParamListInfo ext_params)
 
ExprStateExecInitQual (List *qual, PlanState *parent)
 
ExprStateExecInitCheck (List *qual, PlanState *parent)
 
ListExecInitExprList (List *nodes, PlanState *parent)
 
ProjectionInfoExecBuildProjectionInfo (List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
 
ProjectionInfoExecBuildUpdateProjection (List *targetList, bool evalTargetList, List *targetColnos, TupleDesc relDesc, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent)
 
ExprStateExecPrepareExpr (Expr *node, EState *estate)
 
ExprStateExecPrepareQual (List *qual, EState *estate)
 
ExprStateExecPrepareCheck (List *qual, EState *estate)
 
ListExecPrepareExprList (List *nodes, EState *estate)
 
bool ExecCheck (ExprState *state, ExprContext *econtext)
 
void ExprEvalPushStep (ExprState *es, const ExprEvalStep *s)
 
ExprStateExecBuildAggTrans (AggState *aggstate, AggStatePerPhase phase, bool doSort, bool doHash, bool nullcheck)
 
ExprStateExecBuildHash32FromAttrs (TupleDesc desc, const TupleTableSlotOps *ops, FmgrInfo *hashfunctions, Oid *collations, int numCols, AttrNumber *keyColIdx, PlanState *parent, uint32 init_value)
 
ExprStateExecBuildHash32Expr (TupleDesc desc, const TupleTableSlotOps *ops, const Oid *hashfunc_oids, const List *collations, const List *hash_exprs, const bool *opstrict, PlanState *parent, uint32 init_value, bool keep_nulls)
 
ExprStateExecBuildGroupingEqual (TupleDesc ldesc, TupleDesc rdesc, const TupleTableSlotOps *lops, const TupleTableSlotOps *rops, int numCols, const AttrNumber *keyColIdx, const Oid *eqfunctions, const Oid *collations, PlanState *parent)
 
ExprStateExecBuildParamSetEqual (TupleDesc desc, const TupleTableSlotOps *lops, const TupleTableSlotOps *rops, const Oid *eqfunctions, const Oid *collations, const List *param_exprs, PlanState *parent)
 

Typedef Documentation

◆ ExprSetupInfo

typedef struct ExprSetupInfo ExprSetupInfo

Function Documentation

◆ ExecBuildAggTrans()

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

Definition at line 3669 of file execExpr.c.

3671{
3673 PlanState *parent = &aggstate->ss.ps;
3674 ExprEvalStep scratch = {0};
3675 bool isCombine = DO_AGGSPLIT_COMBINE(aggstate->aggsplit);
3676 ExprSetupInfo deform = {0, 0, 0, 0, 0, NIL};
3677
3678 state->expr = (Expr *) aggstate;
3679 state->parent = parent;
3680
3681 scratch.resvalue = &state->resvalue;
3682 scratch.resnull = &state->resnull;
3683
3684 /*
3685 * First figure out which slots, and how many columns from each, we're
3686 * going to need.
3687 */
3688 for (int transno = 0; transno < aggstate->numtrans; transno++)
3689 {
3690 AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3691
3693 &deform);
3694 expr_setup_walker((Node *) pertrans->aggref->args,
3695 &deform);
3696 expr_setup_walker((Node *) pertrans->aggref->aggorder,
3697 &deform);
3699 &deform);
3700 expr_setup_walker((Node *) pertrans->aggref->aggfilter,
3701 &deform);
3702 }
3703 ExecPushExprSetupSteps(state, &deform);
3704
3705 /*
3706 * Emit instructions for each transition value / grouping set combination.
3707 */
3708 for (int transno = 0; transno < aggstate->numtrans; transno++)
3709 {
3710 AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3711 FunctionCallInfo trans_fcinfo = pertrans->transfn_fcinfo;
3712 List *adjust_bailout = NIL;
3713 NullableDatum *strictargs = NULL;
3714 bool *strictnulls = NULL;
3715 int argno;
3716 ListCell *bail;
3717
3718 /*
3719 * If filter present, emit. Do so before evaluating the input, to
3720 * avoid potentially unneeded computations, or even worse, unintended
3721 * side-effects. When combining, all the necessary filtering has
3722 * already been done.
3723 */
3724 if (pertrans->aggref->aggfilter && !isCombine)
3725 {
3726 /* evaluate filter expression */
3728 &state->resvalue, &state->resnull);
3729 /* and jump out if false */
3730 scratch.opcode = EEOP_JUMP_IF_NOT_TRUE;
3731 scratch.d.jump.jumpdone = -1; /* adjust later */
3732 ExprEvalPushStep(state, &scratch);
3733 adjust_bailout = lappend_int(adjust_bailout,
3734 state->steps_len - 1);
3735 }
3736
3737 /*
3738 * Evaluate arguments to aggregate/combine function.
3739 */
3740 argno = 0;
3741 if (isCombine)
3742 {
3743 /*
3744 * Combining two aggregate transition values. Instead of directly
3745 * coming from a tuple the input is a, potentially deserialized,
3746 * transition value.
3747 */
3748 TargetEntry *source_tle;
3749
3750 Assert(pertrans->numSortCols == 0);
3751 Assert(list_length(pertrans->aggref->args) == 1);
3752
3753 strictargs = trans_fcinfo->args + 1;
3754 source_tle = (TargetEntry *) linitial(pertrans->aggref->args);
3755
3756 /*
3757 * deserialfn_oid will be set if we must deserialize the input
3758 * state before calling the combine function.
3759 */
3760 if (!OidIsValid(pertrans->deserialfn_oid))
3761 {
3762 /*
3763 * Start from 1, since the 0th arg will be the transition
3764 * value
3765 */
3766 ExecInitExprRec(source_tle->expr, state,
3767 &trans_fcinfo->args[argno + 1].value,
3768 &trans_fcinfo->args[argno + 1].isnull);
3769 }
3770 else
3771 {
3772 FunctionCallInfo ds_fcinfo = pertrans->deserialfn_fcinfo;
3773
3774 /* evaluate argument */
3775 ExecInitExprRec(source_tle->expr, state,
3776 &ds_fcinfo->args[0].value,
3777 &ds_fcinfo->args[0].isnull);
3778
3779 /* Dummy second argument for type-safety reasons */
3780 ds_fcinfo->args[1].value = PointerGetDatum(NULL);
3781 ds_fcinfo->args[1].isnull = false;
3782
3783 /*
3784 * Don't call a strict deserialization function with NULL
3785 * input
3786 */
3787 if (pertrans->deserialfn.fn_strict)
3789 else
3790 scratch.opcode = EEOP_AGG_DESERIALIZE;
3791
3792 scratch.d.agg_deserialize.fcinfo_data = ds_fcinfo;
3793 scratch.d.agg_deserialize.jumpnull = -1; /* adjust later */
3794 scratch.resvalue = &trans_fcinfo->args[argno + 1].value;
3795 scratch.resnull = &trans_fcinfo->args[argno + 1].isnull;
3796
3797 ExprEvalPushStep(state, &scratch);
3798 /* don't add an adjustment unless the function is strict */
3799 if (pertrans->deserialfn.fn_strict)
3800 adjust_bailout = lappend_int(adjust_bailout,
3801 state->steps_len - 1);
3802
3803 /* restore normal settings of scratch fields */
3804 scratch.resvalue = &state->resvalue;
3805 scratch.resnull = &state->resnull;
3806 }
3807 argno++;
3808
3809 Assert(pertrans->numInputs == argno);
3810 }
3811 else if (!pertrans->aggsortrequired)
3812 {
3813 ListCell *arg;
3814
3815 /*
3816 * Normal transition function without ORDER BY / DISTINCT or with
3817 * ORDER BY / DISTINCT but the planner has given us pre-sorted
3818 * input.
3819 */
3820 strictargs = trans_fcinfo->args + 1;
3821
3822 foreach(arg, pertrans->aggref->args)
3823 {
3824 TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3825
3826 /*
3827 * Don't initialize args for any ORDER BY clause that might
3828 * exist in a presorted aggregate.
3829 */
3830 if (argno == pertrans->numTransInputs)
3831 break;
3832
3833 /*
3834 * Start from 1, since the 0th arg will be the transition
3835 * value
3836 */
3837 ExecInitExprRec(source_tle->expr, state,
3838 &trans_fcinfo->args[argno + 1].value,
3839 &trans_fcinfo->args[argno + 1].isnull);
3840 argno++;
3841 }
3842 Assert(pertrans->numTransInputs == argno);
3843 }
3844 else if (pertrans->numInputs == 1)
3845 {
3846 /*
3847 * Non-presorted DISTINCT and/or ORDER BY case, with a single
3848 * column sorted on.
3849 */
3850 TargetEntry *source_tle =
3851 (TargetEntry *) linitial(pertrans->aggref->args);
3852
3853 Assert(list_length(pertrans->aggref->args) == 1);
3854
3855 ExecInitExprRec(source_tle->expr, state,
3856 &state->resvalue,
3857 &state->resnull);
3858 strictnulls = &state->resnull;
3859 argno++;
3860
3861 Assert(pertrans->numInputs == argno);
3862 }
3863 else
3864 {
3865 /*
3866 * Non-presorted DISTINCT and/or ORDER BY case, with multiple
3867 * columns sorted on.
3868 */
3869 Datum *values = pertrans->sortslot->tts_values;
3870 bool *nulls = pertrans->sortslot->tts_isnull;
3871 ListCell *arg;
3872
3873 strictnulls = nulls;
3874
3875 foreach(arg, pertrans->aggref->args)
3876 {
3877 TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3878
3879 ExecInitExprRec(source_tle->expr, state,
3880 &values[argno], &nulls[argno]);
3881 argno++;
3882 }
3883 Assert(pertrans->numInputs == argno);
3884 }
3885
3886 /*
3887 * For a strict transfn, nothing happens when there's a NULL input; we
3888 * just keep the prior transValue. This is true for both plain and
3889 * sorted/distinct aggregates.
3890 */
3891 if (trans_fcinfo->flinfo->fn_strict && pertrans->numTransInputs > 0)
3892 {
3893 if (strictnulls)
3895 else if (strictargs && pertrans->numTransInputs == 1)
3897 else
3899 scratch.d.agg_strict_input_check.nulls = strictnulls;
3900 scratch.d.agg_strict_input_check.args = strictargs;
3901 scratch.d.agg_strict_input_check.jumpnull = -1; /* adjust later */
3902 scratch.d.agg_strict_input_check.nargs = pertrans->numTransInputs;
3903 ExprEvalPushStep(state, &scratch);
3904 adjust_bailout = lappend_int(adjust_bailout,
3905 state->steps_len - 1);
3906 }
3907
3908 /* Handle DISTINCT aggregates which have pre-sorted input */
3909 if (pertrans->numDistinctCols > 0 && !pertrans->aggsortrequired)
3910 {
3911 if (pertrans->numDistinctCols > 1)
3913 else
3915
3916 scratch.d.agg_presorted_distinctcheck.pertrans = pertrans;
3917 scratch.d.agg_presorted_distinctcheck.jumpdistinct = -1; /* adjust later */
3918 ExprEvalPushStep(state, &scratch);
3919 adjust_bailout = lappend_int(adjust_bailout,
3920 state->steps_len - 1);
3921 }
3922
3923 /*
3924 * Call transition function (once for each concurrently evaluated
3925 * grouping set). Do so for both sort and hash based computations, as
3926 * applicable.
3927 */
3928 if (doSort)
3929 {
3930 int processGroupingSets = Max(phase->numsets, 1);
3931 int setoff = 0;
3932
3933 for (int setno = 0; setno < processGroupingSets; setno++)
3934 {
3935 ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3936 pertrans, transno, setno, setoff, false,
3937 nullcheck);
3938 setoff++;
3939 }
3940 }
3941
3942 if (doHash)
3943 {
3944 int numHashes = aggstate->num_hashes;
3945 int setoff;
3946
3947 /* in MIXED mode, there'll be preceding transition values */
3948 if (aggstate->aggstrategy != AGG_HASHED)
3949 setoff = aggstate->maxsets;
3950 else
3951 setoff = 0;
3952
3953 for (int setno = 0; setno < numHashes; setno++)
3954 {
3955 ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3956 pertrans, transno, setno, setoff, true,
3957 nullcheck);
3958 setoff++;
3959 }
3960 }
3961
3962 /* adjust early bail out jump target(s) */
3963 foreach(bail, adjust_bailout)
3964 {
3965 ExprEvalStep *as = &state->steps[lfirst_int(bail)];
3966
3967 if (as->opcode == EEOP_JUMP_IF_NOT_TRUE)
3968 {
3969 Assert(as->d.jump.jumpdone == -1);
3970 as->d.jump.jumpdone = state->steps_len;
3971 }
3972 else if (as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_ARGS ||
3975 {
3977 as->d.agg_strict_input_check.jumpnull = state->steps_len;
3978 }
3979 else if (as->opcode == EEOP_AGG_STRICT_DESERIALIZE)
3980 {
3981 Assert(as->d.agg_deserialize.jumpnull == -1);
3982 as->d.agg_deserialize.jumpnull = state->steps_len;
3983 }
3986 {
3989 }
3990 else
3991 Assert(false);
3992 }
3993 }
3994
3995 scratch.resvalue = NULL;
3996 scratch.resnull = NULL;
3997 scratch.opcode = EEOP_DONE_NO_RETURN;
3998 ExprEvalPushStep(state, &scratch);
3999
4001
4002 return state;
4003}
static Datum values[MAXATTR]
Definition: bootstrap.c:153
#define Max(x, y)
Definition: c.h:1010
#define OidIsValid(objectId)
Definition: c.h:788
static void ExecPushExprSetupSteps(ExprState *state, ExprSetupInfo *info)
Definition: execExpr.c:2890
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:919
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:4011
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2671
static bool expr_setup_walker(Node *node, ExprSetupInfo *info)
Definition: execExpr.c:2976
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:902
@ EEOP_AGG_STRICT_DESERIALIZE
Definition: execExpr.h:278
@ EEOP_AGG_PRESORTED_DISTINCT_MULTI
Definition: execExpr.h:291
@ EEOP_AGG_STRICT_INPUT_CHECK_NULLS
Definition: execExpr.h:282
@ EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1
Definition: execExpr.h:281
@ EEOP_AGG_STRICT_INPUT_CHECK_ARGS
Definition: execExpr.h:280
@ EEOP_AGG_DESERIALIZE
Definition: execExpr.h:279
@ EEOP_JUMP_IF_NOT_TRUE
Definition: execExpr.h:156
@ EEOP_AGG_PRESORTED_DISTINCT_SINGLE
Definition: execExpr.h:290
@ EEOP_DONE_NO_RETURN
Definition: execExpr.h:72
Assert(PointerIsAligned(start, uint64))
List * lappend_int(List *list, int datum)
Definition: list.c:357
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:395
@ AGG_HASHED
Definition: nodes.h:366
#define makeNode(_type_)
Definition: nodes.h:161
void * arg
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define lfirst_int(lc)
Definition: pg_list.h:173
#define linitial(l)
Definition: pg_list.h:178
#define bail(...)
Definition: pg_regress.c:167
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:332
uint64_t Datum
Definition: postgres.h:70
TupleTableSlot * sortslot
Definition: nodeAgg.h:141
Aggref * aggref
Definition: nodeAgg.h:44
FmgrInfo deserialfn
Definition: nodeAgg.h:92
FunctionCallInfo deserialfn_fcinfo
Definition: nodeAgg.h:175
FunctionCallInfo transfn_fcinfo
Definition: nodeAgg.h:170
ScanState ss
Definition: execnodes.h:2535
AggStatePerTrans pertrans
Definition: execnodes.h:2545
AggStrategy aggstrategy
Definition: execnodes.h:2539
int numtrans
Definition: execnodes.h:2538
AggSplit aggsplit
Definition: execnodes.h:2540
int num_hashes
Definition: execnodes.h:2576
int maxsets
Definition: execnodes.h:2565
List * aggdistinct
Definition: primnodes.h:493
List * aggdirectargs
Definition: primnodes.h:484
List * args
Definition: primnodes.h:487
Expr * aggfilter
Definition: primnodes.h:496
List * aggorder
Definition: primnodes.h:490
struct ExprEvalStep::@57::@100 agg_strict_input_check
AggStatePerTrans pertrans
Definition: execExpr.h:731
intptr_t opcode
Definition: execExpr.h:307
struct ExprEvalStep::@57::@68 jump
NullableDatum * args
Definition: execExpr.h:715
bool * nulls
Definition: execExpr.h:531
Datum * resvalue
Definition: execExpr.h:310
int jumpnull
Definition: execExpr.h:515
struct ExprEvalStep::@57::@102 agg_presorted_distinctcheck
FunctionCallInfo fcinfo_data
Definition: execExpr.h:389
int jumpdistinct
Definition: execExpr.h:733
int jumpdone
Definition: execExpr.h:374
union ExprEvalStep::@57 d
bool * resnull
Definition: execExpr.h:311
struct ExprEvalStep::@57::@99 agg_deserialize
bool fn_strict
Definition: fmgr.h:61
FmgrInfo * flinfo
Definition: fmgr.h:87
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
Definition: pg_list.h:54
Definition: nodes.h:135
Datum value
Definition: postgres.h:87
bool isnull
Definition: postgres.h:89
PlanState ps
Definition: execnodes.h:1621
Expr * expr
Definition: primnodes.h:2239
bool * tts_isnull
Definition: tuptable.h:126
Datum * tts_values
Definition: tuptable.h:124
Definition: regguts.h:323

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

Referenced by ExecInitAgg(), and hashagg_recompile_expressions().

◆ ExecBuildAggTransCall()

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

Definition at line 4011 of file execExpr.c.

4016{
4017 ExprContext *aggcontext;
4018 int adjust_jumpnull = -1;
4019
4020 if (ishash)
4021 aggcontext = aggstate->hashcontext;
4022 else
4023 aggcontext = aggstate->aggcontexts[setno];
4024
4025 /* add check for NULL pointer? */
4026 if (nullcheck)
4027 {
4029 scratch->d.agg_plain_pergroup_nullcheck.setoff = setoff;
4030 /* adjust later */
4032 ExprEvalPushStep(state, scratch);
4033 adjust_jumpnull = state->steps_len - 1;
4034 }
4035
4036 /*
4037 * Determine appropriate transition implementation.
4038 *
4039 * For non-ordered aggregates and ORDER BY / DISTINCT aggregates with
4040 * presorted input:
4041 *
4042 * If the initial value for the transition state doesn't exist in the
4043 * pg_aggregate table then we will let the first non-NULL value returned
4044 * from the outer procNode become the initial value. (This is useful for
4045 * aggregates like max() and min().) The noTransValue flag signals that we
4046 * need to do so. If true, generate a
4047 * EEOP_AGG_INIT_STRICT_PLAIN_TRANS{,_BYVAL} step. This step also needs to
4048 * do the work described next:
4049 *
4050 * If the function is strict, but does have an initial value, choose
4051 * EEOP_AGG_STRICT_PLAIN_TRANS{,_BYVAL}, which skips the transition
4052 * function if the transition value has become NULL (because a previous
4053 * transition function returned NULL). This step also needs to do the work
4054 * described next:
4055 *
4056 * Otherwise we call EEOP_AGG_PLAIN_TRANS{,_BYVAL}, which does not have to
4057 * perform either of the above checks.
4058 *
4059 * Having steps with overlapping responsibilities is not nice, but
4060 * aggregations are very performance sensitive, making this worthwhile.
4061 *
4062 * For ordered aggregates:
4063 *
4064 * Only need to choose between the faster path for a single ordered
4065 * column, and the one between multiple columns. Checking strictness etc
4066 * is done when finalizing the aggregate. See
4067 * process_ordered_aggregate_{single, multi} and
4068 * advance_transition_function.
4069 */
4070 if (!pertrans->aggsortrequired)
4071 {
4072 if (pertrans->transtypeByVal)
4073 {
4074 if (fcinfo->flinfo->fn_strict &&
4075 pertrans->initValueIsNull)
4077 else if (fcinfo->flinfo->fn_strict)
4079 else
4081 }
4082 else
4083 {
4084 if (fcinfo->flinfo->fn_strict &&
4085 pertrans->initValueIsNull)
4087 else if (fcinfo->flinfo->fn_strict)
4089 else
4091 }
4092 }
4093 else if (pertrans->numInputs == 1)
4095 else
4097
4098 scratch->d.agg_trans.pertrans = pertrans;
4099 scratch->d.agg_trans.setno = setno;
4100 scratch->d.agg_trans.setoff = setoff;
4101 scratch->d.agg_trans.transno = transno;
4102 scratch->d.agg_trans.aggcontext = aggcontext;
4103 ExprEvalPushStep(state, scratch);
4104
4105 /* fix up jumpnull */
4106 if (adjust_jumpnull != -1)
4107 {
4108 ExprEvalStep *as = &state->steps[adjust_jumpnull];
4109
4113 }
4114}
@ EEOP_AGG_PLAIN_PERGROUP_NULLCHECK
Definition: execExpr.h:283
@ EEOP_AGG_PLAIN_TRANS_BYREF
Definition: execExpr.h:289
@ EEOP_AGG_PLAIN_TRANS_BYVAL
Definition: execExpr.h:286
@ EEOP_AGG_ORDERED_TRANS_DATUM
Definition: execExpr.h:292
@ EEOP_AGG_PLAIN_TRANS_STRICT_BYREF
Definition: execExpr.h:288
@ EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL
Definition: execExpr.h:284
@ EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL
Definition: execExpr.h:285
@ EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF
Definition: execExpr.h:287
@ EEOP_AGG_ORDERED_TRANS_TUPLE
Definition: execExpr.h:293
ExprContext * hashcontext
Definition: execnodes.h:2546
ExprContext ** aggcontexts
Definition: execnodes.h:2547
struct ExprEvalStep::@57::@103 agg_trans
struct ExprEvalStep::@57::@101 agg_plain_pergroup_nullcheck
ExprContext * aggcontext
Definition: execExpr.h:732

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

Referenced by ExecBuildAggTrans().

◆ ExecBuildGroupingEqual()

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

Definition at line 4457 of file execExpr.c.

4464{
4466 ExprEvalStep scratch = {0};
4467 int maxatt = -1;
4468 List *adjust_jumps = NIL;
4469 ListCell *lc;
4470
4471 /*
4472 * When no columns are actually compared, the result's always true. See
4473 * special case in ExecQual().
4474 */
4475 if (numCols == 0)
4476 return NULL;
4477
4478 state->expr = NULL;
4479 state->flags = EEO_FLAG_IS_QUAL;
4480 state->parent = parent;
4481
4482 scratch.resvalue = &state->resvalue;
4483 scratch.resnull = &state->resnull;
4484
4485 /* compute max needed attribute */
4486 for (int natt = 0; natt < numCols; natt++)
4487 {
4488 int attno = keyColIdx[natt];
4489
4490 if (attno > maxatt)
4491 maxatt = attno;
4492 }
4493 Assert(maxatt >= 0);
4494
4495 /* push deform steps */
4496 scratch.opcode = EEOP_INNER_FETCHSOME;
4497 scratch.d.fetch.last_var = maxatt;
4498 scratch.d.fetch.fixed = false;
4499 scratch.d.fetch.known_desc = ldesc;
4500 scratch.d.fetch.kind = lops;
4501 if (ExecComputeSlotInfo(state, &scratch))
4502 ExprEvalPushStep(state, &scratch);
4503
4504 scratch.opcode = EEOP_OUTER_FETCHSOME;
4505 scratch.d.fetch.last_var = maxatt;
4506 scratch.d.fetch.fixed = false;
4507 scratch.d.fetch.known_desc = rdesc;
4508 scratch.d.fetch.kind = rops;
4509 if (ExecComputeSlotInfo(state, &scratch))
4510 ExprEvalPushStep(state, &scratch);
4511
4512 /*
4513 * Start comparing at the last field (least significant sort key). That's
4514 * the most likely to be different if we are dealing with sorted input.
4515 */
4516 for (int natt = numCols; --natt >= 0;)
4517 {
4518 int attno = keyColIdx[natt];
4519 Form_pg_attribute latt = TupleDescAttr(ldesc, attno - 1);
4520 Form_pg_attribute ratt = TupleDescAttr(rdesc, attno - 1);
4521 Oid foid = eqfunctions[natt];
4522 Oid collid = collations[natt];
4523 FmgrInfo *finfo;
4524 FunctionCallInfo fcinfo;
4525 AclResult aclresult;
4526
4527 /* Check permission to call function */
4528 aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE);
4529 if (aclresult != ACLCHECK_OK)
4530 aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
4531
4533
4534 /* Set up the primary fmgr lookup information */
4535 finfo = palloc0_object(FmgrInfo);
4536 fcinfo = palloc0(SizeForFunctionCallInfo(2));
4537 fmgr_info(foid, finfo);
4538 fmgr_info_set_expr(NULL, finfo);
4539 InitFunctionCallInfoData(*fcinfo, finfo, 2,
4540 collid, NULL, NULL);
4541
4542 /* left arg */
4543 scratch.opcode = EEOP_INNER_VAR;
4544 scratch.d.var.attnum = attno - 1;
4545 scratch.d.var.vartype = latt->atttypid;
4547 scratch.resvalue = &fcinfo->args[0].value;
4548 scratch.resnull = &fcinfo->args[0].isnull;
4549 ExprEvalPushStep(state, &scratch);
4550
4551 /* right arg */
4552 scratch.opcode = EEOP_OUTER_VAR;
4553 scratch.d.var.attnum = attno - 1;
4554 scratch.d.var.vartype = ratt->atttypid;
4556 scratch.resvalue = &fcinfo->args[1].value;
4557 scratch.resnull = &fcinfo->args[1].isnull;
4558 ExprEvalPushStep(state, &scratch);
4559
4560 /* evaluate distinctness */
4561 scratch.opcode = EEOP_NOT_DISTINCT;
4562 scratch.d.func.finfo = finfo;
4563 scratch.d.func.fcinfo_data = fcinfo;
4564 scratch.d.func.fn_addr = finfo->fn_addr;
4565 scratch.d.func.nargs = 2;
4566 scratch.resvalue = &state->resvalue;
4567 scratch.resnull = &state->resnull;
4568 ExprEvalPushStep(state, &scratch);
4569
4570 /* then emit EEOP_QUAL to detect if result is false (or null) */
4571 scratch.opcode = EEOP_QUAL;
4572 scratch.d.qualexpr.jumpdone = -1;
4573 scratch.resvalue = &state->resvalue;
4574 scratch.resnull = &state->resnull;
4575 ExprEvalPushStep(state, &scratch);
4576 adjust_jumps = lappend_int(adjust_jumps,
4577 state->steps_len - 1);
4578 }
4579
4580 /* adjust jump targets */
4581 foreach(lc, adjust_jumps)
4582 {
4583 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4584
4585 Assert(as->opcode == EEOP_QUAL);
4586 Assert(as->d.qualexpr.jumpdone == -1);
4587 as->d.qualexpr.jumpdone = state->steps_len;
4588 }
4589
4590 scratch.resvalue = NULL;
4591 scratch.resnull = NULL;
4592 scratch.opcode = EEOP_DONE_RETURN;
4593 ExprEvalPushStep(state, &scratch);
4594
4596
4597 return state;
4598}
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2654
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3836
Oid collid
static bool ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op)
Definition: execExpr.c:3055
@ EEOP_NOT_DISTINCT
Definition: execExpr.h:190
@ EEOP_DONE_RETURN
Definition: execExpr.h:69
@ EEOP_INNER_VAR
Definition: execExpr.h:82
@ EEOP_QUAL
Definition: execExpr.h:148
@ EEOP_INNER_FETCHSOME
Definition: execExpr.h:75
@ EEOP_OUTER_FETCHSOME
Definition: execExpr.h:76
@ EEOP_OUTER_VAR
Definition: execExpr.h:83
#define EEO_FLAG_IS_QUAL
Definition: execnodes.h:74
#define palloc0_object(type)
Definition: fe_memutils.h:75
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:128
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1773
void * palloc0(Size size)
Definition: mcxt.c:1395
Oid GetUserId(void)
Definition: miscinit.c:469
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:213
@ OBJECT_FUNCTION
Definition: parsenodes.h:2344
#define ACL_EXECUTE
Definition: parsenodes.h:83
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
unsigned int Oid
Definition: postgres_ext.h:32
@ VAR_RETURNING_DEFAULT
Definition: primnodes.h:256
int last_var
Definition: execExpr.h:325
struct ExprEvalStep::@57::@59 var
VarReturningType varreturningtype
Definition: execExpr.h:341
PGFunction fn_addr
Definition: execExpr.h:391
TupleDesc known_desc
Definition: execExpr.h:329
const TupleTableSlotOps * kind
Definition: execExpr.h:331
struct ExprEvalStep::@57::@65 func
struct ExprEvalStep::@57::@67 qualexpr
bool fixed
Definition: execExpr.h:327
struct ExprEvalStep::@57::@58 fetch
FmgrInfo * finfo
Definition: execExpr.h:388
Definition: fmgr.h:57
PGFunction fn_addr
Definition: fmgr.h:58
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, FunctionCallInfoBaseData::args, Assert(), ExprEvalStep::attnum, collid, ExprEvalStep::d, EEO_FLAG_IS_QUAL, EEOP_DONE_RETURN, EEOP_INNER_FETCHSOME, EEOP_INNER_VAR, EEOP_NOT_DISTINCT, EEOP_OUTER_FETCHSOME, EEOP_OUTER_VAR, EEOP_QUAL, ExecComputeSlotInfo(), ExecReadyExpr(), ExprEvalPushStep(), ExprEvalStep::fcinfo_data, ExprEvalStep::fetch, ExprEvalStep::finfo, ExprEvalStep::fixed, fmgr_info(), fmgr_info_set_expr, ExprEvalStep::fn_addr, FmgrInfo::fn_addr, ExprEvalStep::func, get_func_name(), GetUserId(), InitFunctionCallInfoData, InvokeFunctionExecuteHook, NullableDatum::isnull, ExprEvalStep::jumpdone, ExprEvalStep::kind, ExprEvalStep::known_desc, lappend_int(), ExprEvalStep::last_var, lfirst_int, makeNode, ExprEvalStep::nargs, NIL, object_aclcheck(), OBJECT_FUNCTION, ExprEvalStep::opcode, palloc0(), palloc0_object, ExprEvalStep::qualexpr, ExprEvalStep::resnull, ExprEvalStep::resvalue, SizeForFunctionCallInfo, TupleDescAttr(), NullableDatum::value, ExprEvalStep::var, VAR_RETURNING_DEFAULT, ExprEvalStep::varreturningtype, and ExprEvalStep::vartype.

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

◆ ExecBuildHash32Expr()

ExprState * ExecBuildHash32Expr ( TupleDesc  desc,
const TupleTableSlotOps ops,
const Oid hashfunc_oids,
const List collations,
const List hash_exprs,
const bool *  opstrict,
PlanState parent,
uint32  init_value,
bool  keep_nulls 
)

Definition at line 4292 of file execExpr.c.

4296{
4298 ExprEvalStep scratch = {0};
4299 NullableDatum *iresult = NULL;
4300 List *adjust_jumps = NIL;
4301 ListCell *lc;
4302 ListCell *lc2;
4303 intptr_t strict_opcode;
4304 intptr_t opcode;
4305 int num_exprs = list_length(hash_exprs);
4306
4307 Assert(num_exprs == list_length(collations));
4308
4309 state->parent = parent;
4310
4311 /* Insert setup steps as needed. */
4312 ExecCreateExprSetupSteps(state, (Node *) hash_exprs);
4313
4314 /*
4315 * Make a place to store intermediate hash values between subsequent
4316 * hashing of individual expressions. We only need this if there is more
4317 * than one expression to hash or an initial value plus one expression.
4318 */
4319 if ((int64) num_exprs + (init_value != 0) > 1)
4320 iresult = palloc_object(NullableDatum);
4321
4322 if (init_value == 0)
4323 {
4324 /*
4325 * No initial value, so we can assign the result of the hash function
4326 * for the first hash_expr without having to concern ourselves with
4327 * combining the result with any initial value.
4328 */
4329 strict_opcode = EEOP_HASHDATUM_FIRST_STRICT;
4330 opcode = EEOP_HASHDATUM_FIRST;
4331 }
4332 else
4333 {
4334 /*
4335 * Set up operation to set the initial value. Normally we store this
4336 * in the intermediate hash value location, but if there are no exprs
4337 * to hash, store it in the ExprState's result field.
4338 */
4340 scratch.d.hashdatum_initvalue.init_value = UInt32GetDatum(init_value);
4341 scratch.resvalue = num_exprs > 0 ? &iresult->value : &state->resvalue;
4342 scratch.resnull = num_exprs > 0 ? &iresult->isnull : &state->resnull;
4343
4344 ExprEvalPushStep(state, &scratch);
4345
4346 /*
4347 * When using an initial value use the NEXT32/NEXT32_STRICT ops as the
4348 * FIRST/FIRST_STRICT ops would overwrite the stored initial value.
4349 */
4350 strict_opcode = EEOP_HASHDATUM_NEXT32_STRICT;
4351 opcode = EEOP_HASHDATUM_NEXT32;
4352 }
4353
4354 forboth(lc, hash_exprs, lc2, collations)
4355 {
4356 Expr *expr = (Expr *) lfirst(lc);
4357 FmgrInfo *finfo;
4358 FunctionCallInfo fcinfo;
4359 int i = foreach_current_index(lc);
4360 Oid funcid;
4361 Oid inputcollid = lfirst_oid(lc2);
4362
4363 funcid = hashfunc_oids[i];
4364
4365 /* Allocate hash function lookup data. */
4366 finfo = palloc0_object(FmgrInfo);
4367 fcinfo = palloc0(SizeForFunctionCallInfo(1));
4368
4369 fmgr_info(funcid, finfo);
4370
4371 /*
4372 * Build the steps to evaluate the hash function's argument have it so
4373 * the value of that is stored in the 0th argument of the hash func.
4374 */
4375 ExecInitExprRec(expr,
4376 state,
4377 &fcinfo->args[0].value,
4378 &fcinfo->args[0].isnull);
4379
4380 if (i == num_exprs - 1)
4381 {
4382 /* the result for hashing the final expr is stored in the state */
4383 scratch.resvalue = &state->resvalue;
4384 scratch.resnull = &state->resnull;
4385 }
4386 else
4387 {
4388 Assert(iresult != NULL);
4389
4390 /* intermediate values are stored in an intermediate result */
4391 scratch.resvalue = &iresult->value;
4392 scratch.resnull = &iresult->isnull;
4393 }
4394
4395 /*
4396 * NEXT32 opcodes need to look at the intermediate result. We might
4397 * as well just set this for all ops. FIRSTs won't look at it.
4398 */
4399 scratch.d.hashdatum.iresult = iresult;
4400
4401 /* Initialize function call parameter structure too */
4402 InitFunctionCallInfoData(*fcinfo, finfo, 1, inputcollid, NULL, NULL);
4403
4404 scratch.d.hashdatum.finfo = finfo;
4405 scratch.d.hashdatum.fcinfo_data = fcinfo;
4406 scratch.d.hashdatum.fn_addr = finfo->fn_addr;
4407
4408 scratch.opcode = opstrict[i] && !keep_nulls ? strict_opcode : opcode;
4409 scratch.d.hashdatum.jumpdone = -1;
4410
4411 ExprEvalPushStep(state, &scratch);
4412 adjust_jumps = lappend_int(adjust_jumps, state->steps_len - 1);
4413
4414 /*
4415 * For subsequent keys we must combine the hash value with the
4416 * previous hashes.
4417 */
4418 strict_opcode = EEOP_HASHDATUM_NEXT32_STRICT;
4419 opcode = EEOP_HASHDATUM_NEXT32;
4420 }
4421
4422 /* adjust jump targets */
4423 foreach(lc, adjust_jumps)
4424 {
4425 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4426
4431 Assert(as->d.hashdatum.jumpdone == -1);
4432 as->d.hashdatum.jumpdone = state->steps_len;
4433 }
4434
4435 scratch.resvalue = NULL;
4436 scratch.resnull = NULL;
4437 scratch.opcode = EEOP_DONE_RETURN;
4438 ExprEvalPushStep(state, &scratch);
4439
4441
4442 return state;
4443}
int64_t int64
Definition: c.h:549
static void ExecCreateExprSetupSteps(ExprState *state, Node *node)
Definition: execExpr.c:2874
@ EEOP_HASHDATUM_NEXT32_STRICT
Definition: execExpr.h:259
@ EEOP_HASHDATUM_FIRST_STRICT
Definition: execExpr.h:257
@ EEOP_HASHDATUM_NEXT32
Definition: execExpr.h:258
@ EEOP_HASHDATUM_FIRST
Definition: execExpr.h:256
@ EEOP_HASHDATUM_SET_INITVAL
Definition: execExpr.h:255
#define palloc_object(type)
Definition: fe_memutils.h:74
int i
Definition: isn.c:77
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
#define foreach_current_index(var_or_cell)
Definition: pg_list.h:403
#define lfirst_oid(lc)
Definition: pg_list.h:174
static Datum UInt32GetDatum(uint32 X)
Definition: postgres.h:242
struct ExprEvalStep::@57::@88 hashdatum_initvalue
struct ExprEvalStep::@57::@89 hashdatum
NullableDatum * iresult
Definition: execExpr.h:610
Datum init_value
Definition: execExpr.h:598

References FunctionCallInfoBaseData::args, Assert(), ExprEvalStep::d, EEOP_DONE_RETURN, EEOP_HASHDATUM_FIRST, EEOP_HASHDATUM_FIRST_STRICT, EEOP_HASHDATUM_NEXT32, EEOP_HASHDATUM_NEXT32_STRICT, EEOP_HASHDATUM_SET_INITVAL, ExecCreateExprSetupSteps(), ExecInitExprRec(), ExecReadyExpr(), ExprEvalPushStep(), ExprEvalStep::fcinfo_data, ExprEvalStep::finfo, fmgr_info(), ExprEvalStep::fn_addr, FmgrInfo::fn_addr, forboth, foreach_current_index, ExprEvalStep::hashdatum, ExprEvalStep::hashdatum_initvalue, i, ExprEvalStep::init_value, InitFunctionCallInfoData, ExprEvalStep::iresult, NullableDatum::isnull, ExprEvalStep::jumpdone, lappend_int(), lfirst, lfirst_int, lfirst_oid, list_length(), makeNode, NIL, ExprEvalStep::opcode, palloc0(), palloc0_object, palloc_object, ExprEvalStep::resnull, ExprEvalStep::resvalue, SizeForFunctionCallInfo, UInt32GetDatum(), and NullableDatum::value.

Referenced by ExecInitHashJoin().

◆ ExecBuildHash32FromAttrs()

ExprState * ExecBuildHash32FromAttrs ( TupleDesc  desc,
const TupleTableSlotOps ops,
FmgrInfo hashfunctions,
Oid collations,
int  numCols,
AttrNumber keyColIdx,
PlanState parent,
uint32  init_value 
)

Definition at line 4133 of file execExpr.c.

4137{
4139 ExprEvalStep scratch = {0};
4140 NullableDatum *iresult = NULL;
4141 intptr_t opcode;
4142 AttrNumber last_attnum = 0;
4143
4144 Assert(numCols >= 0);
4145
4146 state->parent = parent;
4147
4148 /*
4149 * Make a place to store intermediate hash values between subsequent
4150 * hashing of individual columns. We only need this if there is more than
4151 * one column to hash or an initial value plus one column.
4152 */
4153 if ((int64) numCols + (init_value != 0) > 1)
4154 iresult = palloc_object(NullableDatum);
4155
4156 /* find the highest attnum so we deform the tuple to that point */
4157 for (int i = 0; i < numCols; i++)
4158 last_attnum = Max(last_attnum, keyColIdx[i]);
4159
4160 scratch.opcode = EEOP_INNER_FETCHSOME;
4161 scratch.d.fetch.last_var = last_attnum;
4162 scratch.d.fetch.fixed = false;
4163 scratch.d.fetch.kind = ops;
4164 scratch.d.fetch.known_desc = desc;
4165 if (ExecComputeSlotInfo(state, &scratch))
4166 ExprEvalPushStep(state, &scratch);
4167
4168 if (init_value == 0)
4169 {
4170 /*
4171 * No initial value, so we can assign the result of the hash function
4172 * for the first attribute without having to concern ourselves with
4173 * combining the result with any initial value.
4174 */
4175 opcode = EEOP_HASHDATUM_FIRST;
4176 }
4177 else
4178 {
4179 /*
4180 * Set up operation to set the initial value. Normally we store this
4181 * in the intermediate hash value location, but if there are no
4182 * columns to hash, store it in the ExprState's result field.
4183 */
4185 scratch.d.hashdatum_initvalue.init_value = UInt32GetDatum(init_value);
4186 scratch.resvalue = numCols > 0 ? &iresult->value : &state->resvalue;
4187 scratch.resnull = numCols > 0 ? &iresult->isnull : &state->resnull;
4188
4189 ExprEvalPushStep(state, &scratch);
4190
4191 /*
4192 * When using an initial value use the NEXT32 ops as the FIRST ops
4193 * would overwrite the stored initial value.
4194 */
4195 opcode = EEOP_HASHDATUM_NEXT32;
4196 }
4197
4198 for (int i = 0; i < numCols; i++)
4199 {
4200 FmgrInfo *finfo;
4201 FunctionCallInfo fcinfo;
4202 Oid inputcollid = collations[i];
4203 AttrNumber attnum = keyColIdx[i] - 1;
4204
4205 finfo = &hashfunctions[i];
4206 fcinfo = palloc0(SizeForFunctionCallInfo(1));
4207
4208 /* Initialize function call parameter structure too */
4209 InitFunctionCallInfoData(*fcinfo, finfo, 1, inputcollid, NULL, NULL);
4210
4211 /*
4212 * Fetch inner Var for this attnum and store it in the 1st arg of the
4213 * hash func.
4214 */
4215 scratch.opcode = EEOP_INNER_VAR;
4216 scratch.resvalue = &fcinfo->args[0].value;
4217 scratch.resnull = &fcinfo->args[0].isnull;
4218 scratch.d.var.attnum = attnum;
4219 scratch.d.var.vartype = TupleDescAttr(desc, attnum)->atttypid;
4221
4222 ExprEvalPushStep(state, &scratch);
4223
4224 /* Call the hash function */
4225 scratch.opcode = opcode;
4226
4227 if (i == numCols - 1)
4228 {
4229 /*
4230 * The result for hashing the final column is stored in the
4231 * ExprState.
4232 */
4233 scratch.resvalue = &state->resvalue;
4234 scratch.resnull = &state->resnull;
4235 }
4236 else
4237 {
4238 Assert(iresult != NULL);
4239
4240 /* intermediate values are stored in an intermediate result */
4241 scratch.resvalue = &iresult->value;
4242 scratch.resnull = &iresult->isnull;
4243 }
4244
4245 /*
4246 * NEXT32 opcodes need to look at the intermediate result. We might
4247 * as well just set this for all ops. FIRSTs won't look at it.
4248 */
4249 scratch.d.hashdatum.iresult = iresult;
4250
4251 scratch.d.hashdatum.finfo = finfo;
4252 scratch.d.hashdatum.fcinfo_data = fcinfo;
4253 scratch.d.hashdatum.fn_addr = finfo->fn_addr;
4254 scratch.d.hashdatum.jumpdone = -1;
4255
4256 ExprEvalPushStep(state, &scratch);
4257
4258 /* subsequent attnums must be combined with the previous */
4259 opcode = EEOP_HASHDATUM_NEXT32;
4260 }
4261
4262 scratch.resvalue = NULL;
4263 scratch.resnull = NULL;
4264 scratch.opcode = EEOP_DONE_RETURN;
4265 ExprEvalPushStep(state, &scratch);
4266
4268
4269 return state;
4270}
int16 AttrNumber
Definition: attnum.h:21
int16 attnum
Definition: pg_attribute.h:74

References FunctionCallInfoBaseData::args, Assert(), attnum, ExprEvalStep::attnum, ExprEvalStep::d, EEOP_DONE_RETURN, EEOP_HASHDATUM_FIRST, EEOP_HASHDATUM_NEXT32, EEOP_HASHDATUM_SET_INITVAL, EEOP_INNER_FETCHSOME, EEOP_INNER_VAR, ExecComputeSlotInfo(), ExecReadyExpr(), ExprEvalPushStep(), ExprEvalStep::fcinfo_data, ExprEvalStep::fetch, ExprEvalStep::finfo, ExprEvalStep::fixed, ExprEvalStep::fn_addr, FmgrInfo::fn_addr, ExprEvalStep::hashdatum, ExprEvalStep::hashdatum_initvalue, i, ExprEvalStep::init_value, InitFunctionCallInfoData, ExprEvalStep::iresult, NullableDatum::isnull, ExprEvalStep::jumpdone, ExprEvalStep::kind, ExprEvalStep::known_desc, ExprEvalStep::last_var, makeNode, Max, ExprEvalStep::opcode, palloc0(), palloc_object, ExprEvalStep::resnull, ExprEvalStep::resvalue, SizeForFunctionCallInfo, TupleDescAttr(), UInt32GetDatum(), NullableDatum::value, ExprEvalStep::var, VAR_RETURNING_DEFAULT, ExprEvalStep::varreturningtype, and ExprEvalStep::vartype.

Referenced by BuildTupleHashTable(), and ExecInitSubPlan().

◆ ExecBuildParamSetEqual()

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

Definition at line 4616 of file execExpr.c.

4623{
4625 ExprEvalStep scratch = {0};
4626 int maxatt = list_length(param_exprs);
4627 List *adjust_jumps = NIL;
4628 ListCell *lc;
4629
4630 state->expr = NULL;
4631 state->flags = EEO_FLAG_IS_QUAL;
4632 state->parent = parent;
4633
4634 scratch.resvalue = &state->resvalue;
4635 scratch.resnull = &state->resnull;
4636
4637 /* push deform steps */
4638 scratch.opcode = EEOP_INNER_FETCHSOME;
4639 scratch.d.fetch.last_var = maxatt;
4640 scratch.d.fetch.fixed = false;
4641 scratch.d.fetch.known_desc = desc;
4642 scratch.d.fetch.kind = lops;
4643 if (ExecComputeSlotInfo(state, &scratch))
4644 ExprEvalPushStep(state, &scratch);
4645
4646 scratch.opcode = EEOP_OUTER_FETCHSOME;
4647 scratch.d.fetch.last_var = maxatt;
4648 scratch.d.fetch.fixed = false;
4649 scratch.d.fetch.known_desc = desc;
4650 scratch.d.fetch.kind = rops;
4651 if (ExecComputeSlotInfo(state, &scratch))
4652 ExprEvalPushStep(state, &scratch);
4653
4654 for (int attno = 0; attno < maxatt; attno++)
4655 {
4656 Form_pg_attribute att = TupleDescAttr(desc, attno);
4657 Oid foid = eqfunctions[attno];
4658 Oid collid = collations[attno];
4659 FmgrInfo *finfo;
4660 FunctionCallInfo fcinfo;
4661 AclResult aclresult;
4662
4663 /* Check permission to call function */
4664 aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE);
4665 if (aclresult != ACLCHECK_OK)
4666 aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
4667
4669
4670 /* Set up the primary fmgr lookup information */
4671 finfo = palloc0_object(FmgrInfo);
4672 fcinfo = palloc0(SizeForFunctionCallInfo(2));
4673 fmgr_info(foid, finfo);
4674 fmgr_info_set_expr(NULL, finfo);
4675 InitFunctionCallInfoData(*fcinfo, finfo, 2,
4676 collid, NULL, NULL);
4677
4678 /* left arg */
4679 scratch.opcode = EEOP_INNER_VAR;
4680 scratch.d.var.attnum = attno;
4681 scratch.d.var.vartype = att->atttypid;
4683 scratch.resvalue = &fcinfo->args[0].value;
4684 scratch.resnull = &fcinfo->args[0].isnull;
4685 ExprEvalPushStep(state, &scratch);
4686
4687 /* right arg */
4688 scratch.opcode = EEOP_OUTER_VAR;
4689 scratch.d.var.attnum = attno;
4690 scratch.d.var.vartype = att->atttypid;
4692 scratch.resvalue = &fcinfo->args[1].value;
4693 scratch.resnull = &fcinfo->args[1].isnull;
4694 ExprEvalPushStep(state, &scratch);
4695
4696 /* evaluate distinctness */
4697 scratch.opcode = EEOP_NOT_DISTINCT;
4698 scratch.d.func.finfo = finfo;
4699 scratch.d.func.fcinfo_data = fcinfo;
4700 scratch.d.func.fn_addr = finfo->fn_addr;
4701 scratch.d.func.nargs = 2;
4702 scratch.resvalue = &state->resvalue;
4703 scratch.resnull = &state->resnull;
4704 ExprEvalPushStep(state, &scratch);
4705
4706 /* then emit EEOP_QUAL to detect if result is false (or null) */
4707 scratch.opcode = EEOP_QUAL;
4708 scratch.d.qualexpr.jumpdone = -1;
4709 scratch.resvalue = &state->resvalue;
4710 scratch.resnull = &state->resnull;
4711 ExprEvalPushStep(state, &scratch);
4712 adjust_jumps = lappend_int(adjust_jumps,
4713 state->steps_len - 1);
4714 }
4715
4716 /* adjust jump targets */
4717 foreach(lc, adjust_jumps)
4718 {
4719 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4720
4721 Assert(as->opcode == EEOP_QUAL);
4722 Assert(as->d.qualexpr.jumpdone == -1);
4723 as->d.qualexpr.jumpdone = state->steps_len;
4724 }
4725
4726 scratch.resvalue = NULL;
4727 scratch.resnull = NULL;
4728 scratch.opcode = EEOP_DONE_RETURN;
4729 ExprEvalPushStep(state, &scratch);
4730
4732
4733 return state;
4734}

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, FunctionCallInfoBaseData::args, Assert(), ExprEvalStep::attnum, collid, ExprEvalStep::d, EEO_FLAG_IS_QUAL, EEOP_DONE_RETURN, EEOP_INNER_FETCHSOME, EEOP_INNER_VAR, EEOP_NOT_DISTINCT, EEOP_OUTER_FETCHSOME, EEOP_OUTER_VAR, EEOP_QUAL, ExecComputeSlotInfo(), ExecReadyExpr(), ExprEvalPushStep(), ExprEvalStep::fcinfo_data, ExprEvalStep::fetch, ExprEvalStep::finfo, ExprEvalStep::fixed, fmgr_info(), fmgr_info_set_expr, ExprEvalStep::fn_addr, FmgrInfo::fn_addr, ExprEvalStep::func, get_func_name(), GetUserId(), InitFunctionCallInfoData, InvokeFunctionExecuteHook, NullableDatum::isnull, ExprEvalStep::jumpdone, ExprEvalStep::kind, ExprEvalStep::known_desc, lappend_int(), ExprEvalStep::last_var, lfirst_int, list_length(), makeNode, ExprEvalStep::nargs, NIL, object_aclcheck(), OBJECT_FUNCTION, ExprEvalStep::opcode, palloc0(), palloc0_object, ExprEvalStep::qualexpr, ExprEvalStep::resnull, ExprEvalStep::resvalue, SizeForFunctionCallInfo, TupleDescAttr(), NullableDatum::value, ExprEvalStep::var, VAR_RETURNING_DEFAULT, ExprEvalStep::varreturningtype, and ExprEvalStep::vartype.

Referenced by ExecInitMemoize().

◆ ExecBuildProjectionInfo()

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

Definition at line 370 of file execExpr.c.

375{
378 ExprEvalStep scratch = {0};
379 ListCell *lc;
380
381 projInfo->pi_exprContext = econtext;
382 /* We embed ExprState into ProjectionInfo instead of doing extra palloc */
383 projInfo->pi_state.type = T_ExprState;
384 state = &projInfo->pi_state;
385 state->expr = (Expr *) targetList;
386 state->parent = parent;
387 state->ext_params = NULL;
388
389 state->resultslot = slot;
390
391 /* Insert setup steps as needed */
392 ExecCreateExprSetupSteps(state, (Node *) targetList);
393
394 /* Now compile each tlist column */
395 foreach(lc, targetList)
396 {
398 Var *variable = NULL;
399 AttrNumber attnum = 0;
400 bool isSafeVar = false;
401
402 /*
403 * If tlist expression is a safe non-system Var, use the fast-path
404 * ASSIGN_*_VAR opcodes. "Safe" means that we don't need to apply
405 * CheckVarSlotCompatibility() during plan startup. If a source slot
406 * was provided, we make the equivalent tests here; if a slot was not
407 * provided, we assume that no check is needed because we're dealing
408 * with a non-relation-scan-level expression.
409 */
410 if (tle->expr != NULL &&
411 IsA(tle->expr, Var) &&
412 ((Var *) tle->expr)->varattno > 0)
413 {
414 /* Non-system Var, but how safe is it? */
415 variable = (Var *) tle->expr;
416 attnum = variable->varattno;
417
418 if (inputDesc == NULL)
419 isSafeVar = true; /* can't check, just assume OK */
420 else if (attnum <= inputDesc->natts)
421 {
422 Form_pg_attribute attr = TupleDescAttr(inputDesc, attnum - 1);
423
424 /*
425 * If user attribute is dropped or has a type mismatch, don't
426 * use ASSIGN_*_VAR. Instead let the normal expression
427 * machinery handle it (which'll possibly error out).
428 */
429 if (!attr->attisdropped && variable->vartype == attr->atttypid)
430 {
431 isSafeVar = true;
432 }
433 }
434 }
435
436 if (isSafeVar)
437 {
438 /* Fast-path: just generate an EEOP_ASSIGN_*_VAR step */
439 switch (variable->varno)
440 {
441 case INNER_VAR:
442 /* get the tuple from the inner node */
444 break;
445
446 case OUTER_VAR:
447 /* get the tuple from the outer node */
449 break;
450
451 /* INDEX_VAR is handled by default case */
452
453 default:
454
455 /*
456 * Get the tuple from the relation being scanned, or the
457 * old/new tuple slot, if old/new values were requested.
458 */
459 switch (variable->varreturningtype)
460 {
463 break;
465 scratch.opcode = EEOP_ASSIGN_OLD_VAR;
466 state->flags |= EEO_FLAG_HAS_OLD;
467 break;
469 scratch.opcode = EEOP_ASSIGN_NEW_VAR;
470 state->flags |= EEO_FLAG_HAS_NEW;
471 break;
472 }
473 break;
474 }
475
476 scratch.d.assign_var.attnum = attnum - 1;
477 scratch.d.assign_var.resultnum = tle->resno - 1;
478 ExprEvalPushStep(state, &scratch);
479 }
480 else
481 {
482 /*
483 * Otherwise, compile the column expression normally.
484 *
485 * We can't tell the expression to evaluate directly into the
486 * result slot, as the result slot (and the exprstate for that
487 * matter) can change between executions. We instead evaluate
488 * into the ExprState's resvalue/resnull and then move.
489 */
491 &state->resvalue, &state->resnull);
492
493 /*
494 * Column might be referenced multiple times in upper nodes, so
495 * force value to R/O - but only if it could be an expanded datum.
496 */
497 if (get_typlen(exprType((Node *) tle->expr)) == -1)
499 else
500 scratch.opcode = EEOP_ASSIGN_TMP;
501 scratch.d.assign_tmp.resultnum = tle->resno - 1;
502 ExprEvalPushStep(state, &scratch);
503 }
504 }
505
506 scratch.opcode = EEOP_DONE_NO_RETURN;
507 ExprEvalPushStep(state, &scratch);
508
510
511 return projInfo;
512}
@ EEOP_ASSIGN_TMP
Definition: execExpr.h:110
@ EEOP_ASSIGN_SCAN_VAR
Definition: execExpr.h:105
@ EEOP_ASSIGN_OUTER_VAR
Definition: execExpr.h:104
@ EEOP_ASSIGN_OLD_VAR
Definition: execExpr.h:106
@ EEOP_ASSIGN_TMP_MAKE_RO
Definition: execExpr.h:112
@ EEOP_ASSIGN_INNER_VAR
Definition: execExpr.h:103
@ EEOP_ASSIGN_NEW_VAR
Definition: execExpr.h:107
#define EEO_FLAG_HAS_OLD
Definition: execnodes.h:76
#define EEO_FLAG_HAS_NEW
Definition: execnodes.h:78
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2362
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define lfirst_node(type, lc)
Definition: pg_list.h:176
@ VAR_RETURNING_OLD
Definition: primnodes.h:257
@ VAR_RETURNING_NEW
Definition: primnodes.h:258
#define OUTER_VAR
Definition: primnodes.h:243
#define INNER_VAR
Definition: primnodes.h:242
struct ExprEvalStep::@57::@62 assign_tmp
int resultnum
Definition: execExpr.h:358
struct ExprEvalStep::@57::@61 assign_var
NodeTag type
Definition: execnodes.h:86
ExprState pi_state
Definition: execnodes.h:386
ExprContext * pi_exprContext
Definition: execnodes.h:388
AttrNumber resno
Definition: primnodes.h:2241
Definition: primnodes.h:262

References ExprEvalStep::assign_tmp, ExprEvalStep::assign_var, attnum, ExprEvalStep::attnum, ExprEvalStep::d, EEO_FLAG_HAS_NEW, EEO_FLAG_HAS_OLD, EEOP_ASSIGN_INNER_VAR, EEOP_ASSIGN_NEW_VAR, EEOP_ASSIGN_OLD_VAR, EEOP_ASSIGN_OUTER_VAR, EEOP_ASSIGN_SCAN_VAR, EEOP_ASSIGN_TMP, EEOP_ASSIGN_TMP_MAKE_RO, EEOP_DONE_NO_RETURN, ExecCreateExprSetupSteps(), ExecInitExprRec(), ExecReadyExpr(), TargetEntry::expr, ExprEvalPushStep(), exprType(), get_typlen(), if(), INNER_VAR, IsA, lfirst_node, makeNode, ExprEvalStep::opcode, OUTER_VAR, ProjectionInfo::pi_exprContext, ProjectionInfo::pi_state, TargetEntry::resno, ExprEvalStep::resultnum, TupleDescAttr(), ExprState::type, VAR_RETURNING_DEFAULT, VAR_RETURNING_NEW, and VAR_RETURNING_OLD.

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

◆ ExecBuildUpdateProjection()

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

Definition at line 547 of file execExpr.c.

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

References Assert(), ExprEvalStep::assign_tmp, ExprEvalStep::assign_var, CompactAttribute::attisdropped, attnum, ExprEvalStep::attnum, bms_add_member(), bms_is_member(), ExprEvalStep::constval, ExprEvalStep::d, EEOP_ASSIGN_OUTER_VAR, EEOP_ASSIGN_SCAN_VAR, EEOP_ASSIGN_TMP, EEOP_CONST, EEOP_DONE_NO_RETURN, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, ExecInitExprRec(), ExecPushExprSetupSteps(), ExecReadyExpr(), TargetEntry::expr, expr_setup_walker(), ExprEvalPushStep(), exprType(), forboth, format_type_be(), ExprEvalStep::isnull, ExprSetupInfo::last_outer, ExprSetupInfo::last_scan, lfirst_int, lfirst_node, list_length(), makeNode, TupleDescData::natts, NIL, ExprEvalStep::opcode, ProjectionInfo::pi_exprContext, ProjectionInfo::pi_state, ExprEvalStep::resnull, ExprEvalStep::resultnum, ExprEvalStep::resvalue, TupleDescAttr(), TupleDescCompactAttr(), ExprState::type, and ExprEvalStep::value.

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

◆ ExecCheck()

bool ExecCheck ( ExprState state,
ExprContext econtext 
)

Definition at line 872 of file execExpr.c.

873{
874 Datum ret;
875 bool isnull;
876
877 /* short-circuit (here and in ExecInitCheck) for empty restriction list */
878 if (state == NULL)
879 return true;
880
881 /* verify that expression was not compiled using ExecInitQual */
882 Assert(!(state->flags & EEO_FLAG_IS_QUAL));
883
884 ret = ExecEvalExprSwitchContext(state, econtext, &isnull);
885
886 if (isnull)
887 return true;
888
889 return DatumGetBool(ret);
890}
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:436
static bool DatumGetBool(Datum X)
Definition: postgres.h:100

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

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

◆ ExecComputeSlotInfo()

static bool ExecComputeSlotInfo ( ExprState state,
ExprEvalStep op 
)
static

Definition at line 3055 of file execExpr.c.

3056{
3057 PlanState *parent = state->parent;
3058 TupleDesc desc = NULL;
3059 const TupleTableSlotOps *tts_ops = NULL;
3060 bool isfixed = false;
3061 ExprEvalOp opcode = op->opcode;
3062
3063 Assert(opcode == EEOP_INNER_FETCHSOME ||
3064 opcode == EEOP_OUTER_FETCHSOME ||
3065 opcode == EEOP_SCAN_FETCHSOME ||
3066 opcode == EEOP_OLD_FETCHSOME ||
3067 opcode == EEOP_NEW_FETCHSOME);
3068
3069 if (op->d.fetch.known_desc != NULL)
3070 {
3071 desc = op->d.fetch.known_desc;
3072 tts_ops = op->d.fetch.kind;
3073 isfixed = op->d.fetch.kind != NULL;
3074 }
3075 else if (!parent)
3076 {
3077 isfixed = false;
3078 }
3079 else if (opcode == EEOP_INNER_FETCHSOME)
3080 {
3081 PlanState *is = innerPlanState(parent);
3082
3083 if (parent->inneropsset && !parent->inneropsfixed)
3084 {
3085 isfixed = false;
3086 }
3087 else if (parent->inneropsset && parent->innerops)
3088 {
3089 isfixed = true;
3090 tts_ops = parent->innerops;
3091 desc = ExecGetResultType(is);
3092 }
3093 else if (is)
3094 {
3095 tts_ops = ExecGetResultSlotOps(is, &isfixed);
3096 desc = ExecGetResultType(is);
3097 }
3098 }
3099 else if (opcode == EEOP_OUTER_FETCHSOME)
3100 {
3101 PlanState *os = outerPlanState(parent);
3102
3103 if (parent->outeropsset && !parent->outeropsfixed)
3104 {
3105 isfixed = false;
3106 }
3107 else if (parent->outeropsset && parent->outerops)
3108 {
3109 isfixed = true;
3110 tts_ops = parent->outerops;
3111 desc = ExecGetResultType(os);
3112 }
3113 else if (os)
3114 {
3115 tts_ops = ExecGetResultSlotOps(os, &isfixed);
3116 desc = ExecGetResultType(os);
3117 }
3118 }
3119 else if (opcode == EEOP_SCAN_FETCHSOME ||
3120 opcode == EEOP_OLD_FETCHSOME ||
3121 opcode == EEOP_NEW_FETCHSOME)
3122 {
3123 desc = parent->scandesc;
3124
3125 if (parent->scanops)
3126 tts_ops = parent->scanops;
3127
3128 if (parent->scanopsset)
3129 isfixed = parent->scanopsfixed;
3130 }
3131
3132 if (isfixed && desc != NULL && tts_ops != NULL)
3133 {
3134 op->d.fetch.fixed = true;
3135 op->d.fetch.kind = tts_ops;
3136 op->d.fetch.known_desc = desc;
3137 }
3138 else
3139 {
3140 op->d.fetch.fixed = false;
3141 op->d.fetch.kind = NULL;
3142 op->d.fetch.known_desc = NULL;
3143 }
3144
3145 /* if the slot is known to always virtual we never need to deform */
3146 if (op->d.fetch.fixed && op->d.fetch.kind == &TTSOpsVirtual)
3147 return false;
3148
3149 return true;
3150}
ExprEvalOp
Definition: execExpr.h:67
@ EEOP_NEW_FETCHSOME
Definition: execExpr.h:79
@ EEOP_OLD_FETCHSOME
Definition: execExpr.h:78
@ EEOP_SCAN_FETCHSOME
Definition: execExpr.h:77
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:84
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:495
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:504
#define outerPlanState(node)
Definition: execnodes.h:1261
#define innerPlanState(node)
Definition: execnodes.h:1260
bool inneropsset
Definition: execnodes.h:1249
bool outeropsset
Definition: execnodes.h:1248
const TupleTableSlotOps * outerops
Definition: execnodes.h:1240
const TupleTableSlotOps * innerops
Definition: execnodes.h:1241
const TupleTableSlotOps * scanops
Definition: execnodes.h:1239
bool outeropsfixed
Definition: execnodes.h:1244
bool scanopsset
Definition: execnodes.h:1247
TupleDesc scandesc
Definition: execnodes.h:1214
bool scanopsfixed
Definition: execnodes.h:1243
bool inneropsfixed
Definition: execnodes.h:1245

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

Referenced by ExecBuildGroupingEqual(), ExecBuildHash32FromAttrs(), ExecBuildParamSetEqual(), and ExecPushExprSetupSteps().

◆ ExecCreateExprSetupSteps()

static void ExecCreateExprSetupSteps ( ExprState state,
Node node 
)
static

Definition at line 2874 of file execExpr.c.

2875{
2876 ExprSetupInfo info = {0, 0, 0, 0, 0, NIL};
2877
2878 /* Prescan to find out what we need. */
2879 expr_setup_walker(node, &info);
2880
2881 /* And generate those steps. */
2883}

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

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

◆ ExecInitCheck()

ExprState * ExecInitCheck ( List qual,
PlanState parent 
)

Definition at line 315 of file execExpr.c.

316{
317 /* short-circuit (here and in ExecCheck) for empty restriction list */
318 if (qual == NIL)
319 return NULL;
320
321 Assert(IsA(qual, List));
322
323 /*
324 * Just convert the implicit-AND list to an explicit AND (if there's more
325 * than one entry), and compile normally. Unlike ExecQual, we can't
326 * short-circuit on NULL results, so the regular AND behavior is needed.
327 */
328 return ExecInitExpr(make_ands_explicit(qual), parent);
329}
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:143
Expr * make_ands_explicit(List *andclauses)
Definition: makefuncs.c:799

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

Referenced by ExecPrepareCheck().

◆ ExecInitCoerceToDomain()

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

Definition at line 3515 of file execExpr.c.

3517{
3518 DomainConstraintRef *constraint_ref;
3519 Datum *domainval = NULL;
3520 bool *domainnull = NULL;
3521 ListCell *l;
3522
3523 scratch->d.domaincheck.resulttype = ctest->resulttype;
3524 /* we'll allocate workspace only if needed */
3525 scratch->d.domaincheck.checkvalue = NULL;
3526 scratch->d.domaincheck.checknull = NULL;
3527 scratch->d.domaincheck.escontext = state->escontext;
3528
3529 /*
3530 * Evaluate argument - it's fine to directly store it into resv/resnull,
3531 * if there's constraint failures there'll be errors, otherwise it's what
3532 * needs to be returned.
3533 */
3534 ExecInitExprRec(ctest->arg, state, resv, resnull);
3535
3536 /*
3537 * Note: if the argument is of varlena type, it could be a R/W expanded
3538 * object. We want to return the R/W pointer as the final result, but we
3539 * have to pass a R/O pointer as the value to be tested by any functions
3540 * in check expressions. We don't bother to emit a MAKE_READONLY step
3541 * unless there's actually at least one check expression, though. Until
3542 * we've tested that, domainval/domainnull are NULL.
3543 */
3544
3545 /*
3546 * Collect the constraints associated with the domain.
3547 *
3548 * Note: before PG v10 we'd recheck the set of constraints during each
3549 * evaluation of the expression. Now we bake them into the ExprState
3550 * during executor initialization. That means we don't need typcache.c to
3551 * provide compiled exprs.
3552 */
3553 constraint_ref = palloc_object(DomainConstraintRef);
3555 constraint_ref,
3557 false);
3558
3559 /*
3560 * Compile code to check each domain constraint. NOTNULL constraints can
3561 * just be applied on the resv/resnull value, but for CHECK constraints we
3562 * need more pushups.
3563 */
3564 foreach(l, constraint_ref->constraints)
3565 {
3567 Datum *save_innermost_domainval;
3568 bool *save_innermost_domainnull;
3569
3570 scratch->d.domaincheck.constraintname = con->name;
3571
3572 switch (con->constrainttype)
3573 {
3575 scratch->opcode = EEOP_DOMAIN_NOTNULL;
3576 ExprEvalPushStep(state, scratch);
3577 break;
3579 /* Allocate workspace for CHECK output if we didn't yet */
3580 if (scratch->d.domaincheck.checkvalue == NULL)
3581 {
3582 scratch->d.domaincheck.checkvalue =
3584 scratch->d.domaincheck.checknull =
3585 palloc_object(bool);
3586 }
3587
3588 /*
3589 * If first time through, determine where CoerceToDomainValue
3590 * nodes should read from.
3591 */
3592 if (domainval == NULL)
3593 {
3594 /*
3595 * Since value might be read multiple times, force to R/O
3596 * - but only if it could be an expanded datum.
3597 */
3598 if (get_typlen(ctest->resulttype) == -1)
3599 {
3600 ExprEvalStep scratch2 = {0};
3601
3602 /* Yes, so make output workspace for MAKE_READONLY */
3603 domainval = palloc_object(Datum);
3604 domainnull = palloc_object(bool);
3605
3606 /* Emit MAKE_READONLY */
3607 scratch2.opcode = EEOP_MAKE_READONLY;
3608 scratch2.resvalue = domainval;
3609 scratch2.resnull = domainnull;
3610 scratch2.d.make_readonly.value = resv;
3611 scratch2.d.make_readonly.isnull = resnull;
3612 ExprEvalPushStep(state, &scratch2);
3613 }
3614 else
3615 {
3616 /* No, so it's fine to read from resv/resnull */
3617 domainval = resv;
3618 domainnull = resnull;
3619 }
3620 }
3621
3622 /*
3623 * Set up value to be returned by CoerceToDomainValue nodes.
3624 * We must save and restore innermost_domainval/null fields,
3625 * in case this node is itself within a check expression for
3626 * another domain.
3627 */
3628 save_innermost_domainval = state->innermost_domainval;
3629 save_innermost_domainnull = state->innermost_domainnull;
3630 state->innermost_domainval = domainval;
3631 state->innermost_domainnull = domainnull;
3632
3633 /* evaluate check expression value */
3635 scratch->d.domaincheck.checkvalue,
3636 scratch->d.domaincheck.checknull);
3637
3638 state->innermost_domainval = save_innermost_domainval;
3639 state->innermost_domainnull = save_innermost_domainnull;
3640
3641 /* now test result */
3642 scratch->opcode = EEOP_DOMAIN_CHECK;
3643 ExprEvalPushStep(state, scratch);
3644
3645 break;
3646 default:
3647 elog(ERROR, "unrecognized constraint type: %d",
3648 (int) con->constrainttype);
3649 break;
3650 }
3651 }
3652}
@ EEOP_DOMAIN_CHECK
Definition: execExpr.h:252
@ EEOP_DOMAIN_NOTNULL
Definition: execExpr.h:249
@ EEOP_MAKE_READONLY
Definition: execExpr.h:184
@ DOM_CONSTRAINT_CHECK
Definition: execnodes.h:1050
@ DOM_CONSTRAINT_NOTNULL
Definition: execnodes.h:1049
MemoryContext CurrentMemoryContext
Definition: mcxt.c:160
DomainConstraintType constrainttype
Definition: execnodes.h:1056
bool * checknull
Definition: execExpr.h:589
Oid resulttype
Definition: execExpr.h:544
Datum * checkvalue
Definition: execExpr.h:588
ErrorSaveContext * escontext
Definition: execExpr.h:592
struct ExprEvalStep::@57::@87 domaincheck
char * constraintname
Definition: execExpr.h:586
struct ExprEvalStep::@57::@73 make_readonly
void InitDomainConstraintRef(Oid type_id, DomainConstraintRef *ref, MemoryContext refctx, bool need_exprstate)
Definition: typcache.c:1401

References CoerceToDomain::arg, DomainConstraintState::check_expr, ExprEvalStep::checknull, ExprEvalStep::checkvalue, ExprEvalStep::constraintname, 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, ExprEvalStep::escontext, ExecInitExprRec(), ExprEvalPushStep(), get_typlen(), InitDomainConstraintRef(), ExprEvalStep::isnull, lfirst, ExprEvalStep::make_readonly, DomainConstraintState::name, ExprEvalStep::opcode, palloc_object, ExprEvalStep::resnull, ExprEvalStep::resulttype, CoerceToDomain::resulttype, ExprEvalStep::resvalue, and ExprEvalStep::value.

Referenced by ExecInitExprRec().

◆ ExecInitExpr()

ExprState * ExecInitExpr ( Expr node,
PlanState parent 
)

Definition at line 143 of file execExpr.c.

144{
146 ExprEvalStep scratch = {0};
147
148 /* Special case: NULL expression produces a NULL ExprState pointer */
149 if (node == NULL)
150 return NULL;
151
152 /* Initialize ExprState with empty step list */
154 state->expr = node;
155 state->parent = parent;
156 state->ext_params = NULL;
157
158 /* Insert setup steps as needed */
160
161 /* Compile the expression proper */
162 ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
163
164 /* Finally, append a DONE step */
165 scratch.opcode = EEOP_DONE_RETURN;
166 ExprEvalPushStep(state, &scratch);
167
169
170 return state;
171}

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

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

◆ ExecInitExprList()

List * ExecInitExprList ( List nodes,
PlanState parent 
)

Definition at line 335 of file execExpr.c.

336{
337 List *result = NIL;
338 ListCell *lc;
339
340 foreach(lc, nodes)
341 {
342 Expr *e = lfirst(lc);
343
344 result = lappend(result, ExecInitExpr(e, parent));
345 }
346
347 return result;
348}
List * lappend(List *list, void *datum)
Definition: list.c:339
e
Definition: preproc-init.c:82

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

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

◆ ExecInitExprRec()

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

Definition at line 919 of file execExpr.c.

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

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, WindowFuncExprState::aggfilter, WindowFunc::aggfilter, ExprEvalStep::aggno, ExprEvalStep::aggref, AggState::aggs, ExprEvalStep::amstate, AND_EXPR, ExprEvalStep::anynull, arg, FieldSelect::arg, FieldStore::arg, RelabelType::arg, CoerceViaIO::arg, ArrayCoerceExpr::arg, CaseExpr::arg, NullTest::arg, BooleanTest::arg, JsonConstructorExprState::arg_nulls, JsonConstructorExprState::arg_type_cache, JsonConstructorExprState::arg_types, JsonConstructorExprState::arg_values, ExprEvalStep::argnull, generate_unaccent_rules::args, FunctionCallInfoBaseData::args, WindowFuncExprState::args, WindowFunc::args, FuncExpr::args, OpExpr::args, ScalarArrayOpExpr::args, BoolExpr::args, CaseExpr::args, RowExpr::args, CoalesceExpr::args, MinMaxExpr::args, XmlExpr::args, JsonConstructorExpr::args, ExprEvalStep::argvalue, ExprEvalStep::arraycoerce, ExprEvalStep::arrayexpr, Assert(), ExprEvalStep::attnum, BlessTupleDesc(), ExprEvalStep::boolexpr, BoolExpr::boolop, BooleanTest::booltesttype, BTORDER_PROC, ExprEvalRowtypeCache::cacheptr, ExprEvalStep::casetest, castNode, JsonConstructorExprState::category, check_stack_depth(), ExprEvalStep::clauses, CMD_MERGE, TypeCacheEntry::cmp_proc, ExprEvalStep::cmptype, RowCompareExpr::cmptype, JsonConstructorExpr::coercion, JsonConstructorExprState::constructor, ExprEvalStep::constval, FunctionCallInfoBaseData::context, convert(), ExprEvalStep::convert_rowtype, ExprEvalStep::d, CaseExpr::defresult, EEO_FLAG_HAS_NEW, EEO_FLAG_HAS_OLD, EEO_FLAG_NEW_IS_NULL, EEO_FLAG_OLD_IS_NULL, 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_CASE_TESTVAL_EXT, EEOP_CONST, EEOP_CONVERT_ROWTYPE, EEOP_CURRENTOFEXPR, EEOP_DISTINCT, EEOP_DOMAIN_TESTVAL, EEOP_DOMAIN_TESTVAL_EXT, EEOP_DONE_RETURN, EEOP_FIELDSELECT, EEOP_FIELDSTORE_DEFORM, EEOP_FIELDSTORE_FORM, EEOP_GROUPING_FUNC, EEOP_HASHED_SCALARARRAYOP, EEOP_INNER_SYSVAR, EEOP_INNER_VAR, EEOP_IOCOERCE, EEOP_IOCOERCE_SAFE, EEOP_IS_JSON, EEOP_JSON_CONSTRUCTOR, EEOP_JUMP, EEOP_JUMP_IF_NOT_NULL, EEOP_JUMP_IF_NOT_TRUE, EEOP_MAKE_READONLY, EEOP_MERGE_SUPPORT_FUNC, EEOP_MINMAX, EEOP_NEW_SYSVAR, EEOP_NEW_VAR, EEOP_NEXTVALUEEXPR, EEOP_NULLIF, EEOP_NULLTEST_ISNOTNULL, EEOP_NULLTEST_ISNULL, EEOP_NULLTEST_ROWISNOTNULL, EEOP_NULLTEST_ROWISNULL, EEOP_OLD_SYSVAR, EEOP_OLD_VAR, EEOP_OUTER_SYSVAR, EEOP_OUTER_VAR, EEOP_PARAM_EXEC, EEOP_PARAM_EXTERN, EEOP_RETURNINGEXPR, EEOP_ROW, EEOP_ROWCOMPARE_FINAL, EEOP_ROWCOMPARE_STEP, EEOP_SCALARARRAYOP, EEOP_SCAN_SYSVAR, EEOP_SCAN_VAR, EEOP_SQLVALUEFUNCTION, EEOP_WINDOW_FUNC, EEOP_XMLEXPR, ExprEvalStep::elemalign, ExprEvalStep::elembyval, ExprEvalStep::element_type, ArrayCoerceExpr::elemexpr, ExprEvalStep::elemexprstate, ExprEvalStep::elemlength, ExprEvalStep::elemnulls, ExprEvalStep::elemtype, ExprEvalStep::elemvalues, elog, ereport, errcode(), errmsg(), ERROR, ExecInitCoerceToDomain(), ExecInitExpr(), ExecInitExprList(), ExecInitExprRec(), ExecInitFunc(), ExecInitJsonExpr(), ExecInitSubPlanExpr(), ExecInitSubscriptingRef(), ExecInitWholeRowVar(), ExecReadyExpr(), ExecTypeFromExprList(), ExecTypeSetColNames(), ExprState::expr, JsonIsPredicate::expr, ExprEvalPushStep(), exprType(), ExprState::ext_params, ExprEvalStep::fcinfo_data, ExprEvalStep::fcinfo_data_in, ExprEvalStep::fcinfo_data_out, ExprEvalStep::fieldnum, FieldSelect::fieldnum, ExprEvalStep::fieldselect, ExprEvalStep::fieldstore, ExprEvalStep::finfo, ExprEvalStep::finfo_in, ExprEvalStep::finfo_out, fmgr_info(), fmgr_info_set_expr, ExprEvalStep::fn_addr, FmgrInfo::fn_addr, forboth, forfive, JsonReturning::format, JsonFormat::format_type, format_type_be(), JsonValueExpr::formatted_expr, JsonExpr::formatted_expr, ExprEvalStep::fstore, ExprEvalStep::func, JsonConstructorExpr::func, FuncExpr::funcid, WindowAggState::funcs, get_element_type(), get_func_name(), get_op_opfamily_properties(), get_opfamily_proc(), get_typlen(), get_typlenbyvalalign(), getTypeInputInfo(), getTypeOutputInfo(), GetUserId(), ExprEvalStep::grouping_func, Agg::groupingSets, ExprEvalStep::hashedscalararrayop, i, ExprEvalStep::incache, ExprEvalStep::inclause, InitFunctionCallInfoData, INNER_VAR, ExprState::innermost_casenull, ExprState::innermost_caseval, ExprEvalStep::inputtype, Int32GetDatum(), InvalidAttrNumber, InvalidOid, InvokeFunctionExecuteHook, ExprEvalStep::iocoerce, IS_FALSE, ExprEvalStep::is_json, IS_NOT_FALSE, IS_NOT_NULL, IS_NOT_TRUE, IS_NOT_UNKNOWN, IS_NULL, IS_TRUE, IS_UNKNOWN, IsA, ExprEvalStep::isnull, NullableDatum::isnull, ExprEvalStep::jcstate, JS_FORMAT_JSONB, JSCTOR_JSON_PARSE, JSCTOR_JSON_SCALAR, JSCTOR_JSON_SERIALIZE, json_categorize_type(), ExprEvalStep::json_constructor, JSON_TABLE_OP, ExprEvalStep::jump, ExprEvalStep::jumpdone, ExprEvalStep::jumpnull, 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, ExprEvalStep::make_ro, makeNode, makeNullConst(), ExprEvalStep::map, Max, ExprEvalStep::minmax, ExprEvalStep::multidims, MULTIEXPR_SUBLINK, ExprEvalStep::named_argnull, XmlExpr::named_args, ExprEvalStep::named_argvalue, JsonConstructorExprState::nargs, TupleDescData::natts, ExprEvalStep::ncolumns, ExprEvalStep::nelems, FieldStore::newvals, ExprEvalStep::nextvalueexpr, NIL, nodeTag, NOT_EXPR, ExprEvalStep::nullflag, ExprEvalStep::nulls, ExprEvalStep::nulltest_row, NullTest::nulltesttype, WindowAggState::numaggs, WindowAggState::numfuncs, object_aclcheck(), OBJECT_FUNCTION, ObjectIdGetDatum(), OidIsValid, ExprEvalStep::op, MinMaxExpr::op, JsonExpr::op, ExprEvalStep::opcode, OR_EXPR, ExprEvalStep::outcache, OUTER_VAR, JsonConstructorExprState::outfuncid, ExprEvalStep::outputtype, palloc(), palloc0(), palloc0_object, palloc_array, palloc_object, ExprEvalStep::param, PARAM_EXEC, PARAM_EXTERN, ParamListInfoData::paramCompile, ExprEvalStep::paramid, Param::paramid, Param::paramkind, ExprEvalStep::paramtype, Param::paramtype, ExprState::parent, ExprEvalStep::pred, RowCompareExpr::rargs, JsonValueExpr::raw_expr, ReleaseTupleDesc, ExprEvalStep::resnull, ExprState::resnull, ExprEvalStep::resultelemtype, ExprEvalStep::resulttype, CoerceViaIO::resulttype, ArrayCoerceExpr::resulttype, ExprEvalStep::resvalue, ExprState::resvalue, ReturningExpr::retexpr, ReturningExpr::retold, JsonConstructorExpr::returning, ExprEvalStep::returningexpr, ExprEvalStep::row, ExprEvalStep::rowcache, ExprEvalStep::rowcompare_final, ExprEvalStep::rowcompare_step, ExprEvalStep::saop, ExprEvalStep::scalararrayop, ExprEvalStep::seqid, NextValueExpr::seqid, ExprEvalStep::seqtypid, SizeForFunctionCallInfo, ExprEvalStep::sqlvaluefunction, ExprState::steps, ExprState::steps_len, SubPlan::subLinkType, ExprEvalStep::svf, ExprEvalStep::tupdesc, TupleDescAttr(), JsonConstructorExpr::type, TYPECACHE_CMP_PROC, NextValueExpr::typeId, JsonConstructorExpr::unique, ExprEvalStep::useOr, ScalarArrayOpExpr::useOr, ExprEvalStep::value, NullableDatum::value, values, ExprEvalStep::values, ExprEvalStep::var, VAR_RETURNING_DEFAULT, VAR_RETURNING_NEW, VAR_RETURNING_OLD, ExprEvalStep::varreturningtype, ExprEvalStep::vartype, ExprEvalStep::wfstate, WindowFuncExprState::wfunc, ExprEvalStep::window_func, ExprEvalStep::xexpr, and ExprEvalStep::xmlexpr.

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

◆ ExecInitExprWithParams()

ExprState * ExecInitExprWithParams ( Expr node,
ParamListInfo  ext_params 
)

Definition at line 180 of file execExpr.c.

181{
183 ExprEvalStep scratch = {0};
184
185 /* Special case: NULL expression produces a NULL ExprState pointer */
186 if (node == NULL)
187 return NULL;
188
189 /* Initialize ExprState with empty step list */
191 state->expr = node;
192 state->parent = NULL;
193 state->ext_params = ext_params;
194
195 /* Insert setup steps as needed */
197
198 /* Compile the expression proper */
199 ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
200
201 /* Finally, append a DONE step */
202 scratch.opcode = EEOP_DONE_RETURN;
203 ExprEvalPushStep(state, &scratch);
204
206
207 return state;
208}

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

Referenced by exec_eval_simple_expr(), and InitPartitionPruneContext().

◆ ExecInitFunc()

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

Definition at line 2697 of file execExpr.c.

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

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, arg, generate_unaccent_rules::args, FunctionCallInfoBaseData::args, ExprEvalStep::d, EEOP_FUNCEXPR, EEOP_FUNCEXPR_FUSAGE, EEOP_FUNCEXPR_STRICT, EEOP_FUNCEXPR_STRICT_1, EEOP_FUNCEXPR_STRICT_2, EEOP_FUNCEXPR_STRICT_FUSAGE, ereport, errcode(), errmsg(), errmsg_plural(), ERROR, ExecInitExprRec(), executor_errposition(), exprLocation(), ExprEvalStep::fcinfo_data, ExprEvalStep::finfo, fmgr_info(), fmgr_info_set_expr, ExprEvalStep::fn_addr, 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(), ExprEvalStep::nargs, object_aclcheck(), OBJECT_FUNCTION, ExprEvalStep::opcode, palloc0(), palloc0_object, SizeForFunctionCallInfo, and NullableDatum::value.

Referenced by ExecInitExprRec().

◆ ExecInitJsonCoercion()

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

Definition at line 5042 of file execExpr.c.

5046{
5047 ExprEvalStep scratch = {0};
5048
5049 /* For json_populate_type() */
5051 scratch.resvalue = resv;
5052 scratch.resnull = resnull;
5053 scratch.d.jsonexpr_coercion.targettype = returning->typid;
5054 scratch.d.jsonexpr_coercion.targettypmod = returning->typmod;
5056 scratch.d.jsonexpr_coercion.escontext = escontext;
5057 scratch.d.jsonexpr_coercion.omit_quotes = omit_quotes;
5058 scratch.d.jsonexpr_coercion.exists_coerce = exists_coerce;
5059 scratch.d.jsonexpr_coercion.exists_cast_to_int = exists_coerce &&
5060 getBaseType(returning->typid) == INT4OID;
5061 scratch.d.jsonexpr_coercion.exists_check_domain = exists_coerce &&
5062 DomainHasConstraints(returning->typid);
5063 ExprEvalPushStep(state, &scratch);
5064}
@ EEOP_JSONEXPR_COERCION
Definition: execExpr.h:269
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2686
void * json_coercion_cache
Definition: execExpr.h:769
bool exists_coerce
Definition: execExpr.h:766
bool exists_cast_to_int
Definition: execExpr.h:767
struct ExprEvalStep::@57::@106 jsonexpr_coercion
bool exists_check_domain
Definition: execExpr.h:768
int32 targettypmod
Definition: execExpr.h:763
Oid targettype
Definition: execExpr.h:762
bool omit_quotes
Definition: execExpr.h:764
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1488

References ExprEvalStep::d, DomainHasConstraints(), EEOP_JSONEXPR_COERCION, ExprEvalStep::escontext, ExprEvalStep::exists_cast_to_int, ExprEvalStep::exists_check_domain, ExprEvalStep::exists_coerce, ExprEvalPushStep(), getBaseType(), ExprEvalStep::json_coercion_cache, ExprEvalStep::jsonexpr_coercion, ExprEvalStep::omit_quotes, ExprEvalStep::opcode, ExprEvalStep::resnull, ExprEvalStep::resvalue, ExprEvalStep::targettype, ExprEvalStep::targettypmod, JsonReturning::typid, and JsonReturning::typmod.

Referenced by ExecInitJsonExpr().

◆ ExecInitJsonExpr()

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

Definition at line 4740 of file execExpr.c.

4743{
4745 ListCell *argexprlc;
4746 ListCell *argnamelc;
4747 List *jumps_return_null = NIL;
4748 List *jumps_to_end = NIL;
4749 ListCell *lc;
4750 ErrorSaveContext *escontext;
4751 bool returning_domain =
4752 get_typtype(jsexpr->returning->typid) == TYPTYPE_DOMAIN;
4753
4754 Assert(jsexpr->on_error != NULL);
4755
4756 jsestate->jsexpr = jsexpr;
4757
4758 /*
4759 * Evaluate formatted_expr storing the result into
4760 * jsestate->formatted_expr.
4761 */
4763 &jsestate->formatted_expr.value,
4764 &jsestate->formatted_expr.isnull);
4765
4766 /* JUMP to return NULL if formatted_expr evaluates to NULL */
4767 jumps_return_null = lappend_int(jumps_return_null, state->steps_len);
4768 scratch->opcode = EEOP_JUMP_IF_NULL;
4769 scratch->resnull = &jsestate->formatted_expr.isnull;
4770 scratch->d.jump.jumpdone = -1; /* set below */
4771 ExprEvalPushStep(state, scratch);
4772
4773 /*
4774 * Evaluate pathspec expression storing the result into
4775 * jsestate->pathspec.
4776 */
4777 ExecInitExprRec((Expr *) jsexpr->path_spec, state,
4778 &jsestate->pathspec.value,
4779 &jsestate->pathspec.isnull);
4780
4781 /* JUMP to return NULL if path_spec evaluates to NULL */
4782 jumps_return_null = lappend_int(jumps_return_null, state->steps_len);
4783 scratch->opcode = EEOP_JUMP_IF_NULL;
4784 scratch->resnull = &jsestate->pathspec.isnull;
4785 scratch->d.jump.jumpdone = -1; /* set below */
4786 ExprEvalPushStep(state, scratch);
4787
4788 /* Steps to compute PASSING args. */
4789 jsestate->args = NIL;
4790 forboth(argexprlc, jsexpr->passing_values,
4791 argnamelc, jsexpr->passing_names)
4792 {
4793 Expr *argexpr = (Expr *) lfirst(argexprlc);
4794 String *argname = lfirst_node(String, argnamelc);
4796
4797 var->name = argname->sval;
4798 var->namelen = strlen(var->name);
4799 var->typid = exprType((Node *) argexpr);
4800 var->typmod = exprTypmod((Node *) argexpr);
4801
4802 ExecInitExprRec(argexpr, state, &var->value, &var->isnull);
4803
4804 jsestate->args = lappend(jsestate->args, var);
4805 }
4806
4807 /* Step for jsonpath evaluation; see ExecEvalJsonExprPath(). */
4808 scratch->opcode = EEOP_JSONEXPR_PATH;
4809 scratch->resvalue = resv;
4810 scratch->resnull = resnull;
4811 scratch->d.jsonexpr.jsestate = jsestate;
4812 ExprEvalPushStep(state, scratch);
4813
4814 /*
4815 * Step to return NULL after jumping to skip the EEOP_JSONEXPR_PATH step
4816 * when either formatted_expr or pathspec is NULL. Adjust jump target
4817 * addresses of JUMPs that we added above.
4818 */
4819 foreach(lc, jumps_return_null)
4820 {
4821 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4822
4823 as->d.jump.jumpdone = state->steps_len;
4824 }
4825 scratch->opcode = EEOP_CONST;
4826 scratch->resvalue = resv;
4827 scratch->resnull = resnull;
4828 scratch->d.constval.value = (Datum) 0;
4829 scratch->d.constval.isnull = true;
4830 ExprEvalPushStep(state, scratch);
4831
4832 escontext = jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR ?
4833 &jsestate->escontext : NULL;
4834
4835 /*
4836 * To handle coercion errors softly, use the following ErrorSaveContext to
4837 * pass to ExecInitExprRec() when initializing the coercion expressions
4838 * and in the EEOP_JSONEXPR_COERCION step.
4839 */
4840 jsestate->escontext.type = T_ErrorSaveContext;
4841
4842 /*
4843 * Steps to coerce the result value computed by EEOP_JSONEXPR_PATH or the
4844 * NULL returned on NULL input as described above.
4845 */
4846 jsestate->jump_eval_coercion = -1;
4847 if (jsexpr->use_json_coercion)
4848 {
4849 jsestate->jump_eval_coercion = state->steps_len;
4850
4851 ExecInitJsonCoercion(state, jsexpr->returning, escontext,
4852 jsexpr->omit_quotes,
4853 jsexpr->op == JSON_EXISTS_OP,
4854 resv, resnull);
4855 }
4856 else if (jsexpr->use_io_coercion)
4857 {
4858 /*
4859 * Here we only need to initialize the FunctionCallInfo for the target
4860 * type's input function, which is called by ExecEvalJsonExprPath()
4861 * itself, so no additional step is necessary.
4862 */
4863 Oid typinput;
4864 Oid typioparam;
4865 FmgrInfo *finfo;
4866 FunctionCallInfo fcinfo;
4867
4868 getTypeInputInfo(jsexpr->returning->typid, &typinput, &typioparam);
4869 finfo = palloc0_object(FmgrInfo);
4870 fcinfo = palloc0(SizeForFunctionCallInfo(3));
4871 fmgr_info(typinput, finfo);
4872 fmgr_info_set_expr((Node *) jsexpr->returning, finfo);
4873 InitFunctionCallInfoData(*fcinfo, finfo, 3, InvalidOid, NULL, NULL);
4874
4875 /*
4876 * We can preload the second and third arguments for the input
4877 * function, since they're constants.
4878 */
4879 fcinfo->args[1].value = ObjectIdGetDatum(typioparam);
4880 fcinfo->args[1].isnull = false;
4881 fcinfo->args[2].value = Int32GetDatum(jsexpr->returning->typmod);
4882 fcinfo->args[2].isnull = false;
4883 fcinfo->context = (Node *) escontext;
4884
4885 jsestate->input_fcinfo = fcinfo;
4886 }
4887
4888 /*
4889 * Add a special step, if needed, to check if the coercion evaluation ran
4890 * into an error but was not thrown because the ON ERROR behavior is not
4891 * ERROR. It will set jsestate->error if an error did occur.
4892 */
4893 if (jsestate->jump_eval_coercion >= 0 && escontext != NULL)
4894 {
4896 scratch->d.jsonexpr.jsestate = jsestate;
4897 ExprEvalPushStep(state, scratch);
4898 }
4899
4900 jsestate->jump_empty = jsestate->jump_error = -1;
4901
4902 /*
4903 * Step to check jsestate->error and return the ON ERROR expression if
4904 * there is one. This handles both the errors that occur during jsonpath
4905 * evaluation in EEOP_JSONEXPR_PATH and subsequent coercion evaluation.
4906 *
4907 * Speed up common cases by avoiding extra steps for a NULL-valued ON
4908 * ERROR expression unless RETURNING a domain type, where constraints must
4909 * be checked. ExecEvalJsonExprPath() already returns NULL on error,
4910 * making additional steps unnecessary in typical scenarios. Note that the
4911 * default ON ERROR behavior for JSON_VALUE() and JSON_QUERY() is to
4912 * return NULL.
4913 */
4914 if (jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR &&
4915 (!(IsA(jsexpr->on_error->expr, Const) &&
4916 ((Const *) jsexpr->on_error->expr)->constisnull) ||
4917 returning_domain))
4918 {
4919 ErrorSaveContext *saved_escontext;
4920
4921 jsestate->jump_error = state->steps_len;
4922
4923 /* JUMP to end if false, that is, skip the ON ERROR expression. */
4924 jumps_to_end = lappend_int(jumps_to_end, state->steps_len);
4925 scratch->opcode = EEOP_JUMP_IF_NOT_TRUE;
4926 scratch->resvalue = &jsestate->error.value;
4927 scratch->resnull = &jsestate->error.isnull;
4928 scratch->d.jump.jumpdone = -1; /* set below */
4929 ExprEvalPushStep(state, scratch);
4930
4931 /*
4932 * Steps to evaluate the ON ERROR expression; handle errors softly to
4933 * rethrow them in COERCION_FINISH step that will be added later.
4934 */
4935 saved_escontext = state->escontext;
4936 state->escontext = escontext;
4937 ExecInitExprRec((Expr *) jsexpr->on_error->expr,
4938 state, resv, resnull);
4939 state->escontext = saved_escontext;
4940
4941 /* Step to coerce the ON ERROR expression if needed */
4942 if (jsexpr->on_error->coerce)
4943 ExecInitJsonCoercion(state, jsexpr->returning, escontext,
4944 jsexpr->omit_quotes, false,
4945 resv, resnull);
4946
4947 /*
4948 * Add a COERCION_FINISH step to check for errors that may occur when
4949 * coercing and rethrow them.
4950 */
4951 if (jsexpr->on_error->coerce ||
4952 IsA(jsexpr->on_error->expr, CoerceViaIO) ||
4953 IsA(jsexpr->on_error->expr, CoerceToDomain))
4954 {
4956 scratch->resvalue = resv;
4957 scratch->resnull = resnull;
4958 scratch->d.jsonexpr.jsestate = jsestate;
4959 ExprEvalPushStep(state, scratch);
4960 }
4961
4962 /* JUMP to end to skip the ON EMPTY steps added below. */
4963 jumps_to_end = lappend_int(jumps_to_end, state->steps_len);
4964 scratch->opcode = EEOP_JUMP;
4965 scratch->d.jump.jumpdone = -1;
4966 ExprEvalPushStep(state, scratch);
4967 }
4968
4969 /*
4970 * Step to check jsestate->empty and return the ON EMPTY expression if
4971 * there is one.
4972 *
4973 * See the comment above for details on the optimization for NULL-valued
4974 * expressions.
4975 */
4976 if (jsexpr->on_empty != NULL &&
4977 jsexpr->on_empty->btype != JSON_BEHAVIOR_ERROR &&
4978 (!(IsA(jsexpr->on_empty->expr, Const) &&
4979 ((Const *) jsexpr->on_empty->expr)->constisnull) ||
4980 returning_domain))
4981 {
4982 ErrorSaveContext *saved_escontext;
4983
4984 jsestate->jump_empty = state->steps_len;
4985
4986 /* JUMP to end if false, that is, skip the ON EMPTY expression. */
4987 jumps_to_end = lappend_int(jumps_to_end, state->steps_len);
4988 scratch->opcode = EEOP_JUMP_IF_NOT_TRUE;
4989 scratch->resvalue = &jsestate->empty.value;
4990 scratch->resnull = &jsestate->empty.isnull;
4991 scratch->d.jump.jumpdone = -1; /* set below */
4992 ExprEvalPushStep(state, scratch);
4993
4994 /*
4995 * Steps to evaluate the ON EMPTY expression; handle errors softly to
4996 * rethrow them in COERCION_FINISH step that will be added later.
4997 */
4998 saved_escontext = state->escontext;
4999 state->escontext = escontext;
5000 ExecInitExprRec((Expr *) jsexpr->on_empty->expr,
5001 state, resv, resnull);
5002 state->escontext = saved_escontext;
5003
5004 /* Step to coerce the ON EMPTY expression if needed */
5005 if (jsexpr->on_empty->coerce)
5006 ExecInitJsonCoercion(state, jsexpr->returning, escontext,
5007 jsexpr->omit_quotes, false,
5008 resv, resnull);
5009
5010 /*
5011 * Add a COERCION_FINISH step to check for errors that may occur when
5012 * coercing and rethrow them.
5013 */
5014 if (jsexpr->on_empty->coerce ||
5015 IsA(jsexpr->on_empty->expr, CoerceViaIO) ||
5016 IsA(jsexpr->on_empty->expr, CoerceToDomain))
5017 {
5018
5020 scratch->resvalue = resv;
5021 scratch->resnull = resnull;
5022 scratch->d.jsonexpr.jsestate = jsestate;
5023 ExprEvalPushStep(state, scratch);
5024 }
5025 }
5026
5027 foreach(lc, jumps_to_end)
5028 {
5029 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
5030
5031 as->d.jump.jumpdone = state->steps_len;
5032 }
5033
5034 jsestate->jump_end = state->steps_len;
5035}
static void ExecInitJsonCoercion(ExprState *state, JsonReturning *returning, ErrorSaveContext *escontext, bool omit_quotes, bool exists_coerce, Datum *resv, bool *resnull)
Definition: execExpr.c:5042
@ EEOP_JSONEXPR_PATH
Definition: execExpr.h:268
@ EEOP_JSONEXPR_COERCION_FINISH
Definition: execExpr.h:270
@ EEOP_JUMP_IF_NULL
Definition: execExpr.h:154
char get_typtype(Oid typid)
Definition: lsyscache.c:2794
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:301
@ JSON_BEHAVIOR_ERROR
Definition: primnodes.h:1791
@ JSON_EXISTS_OP
Definition: primnodes.h:1827
NodeTag type
Definition: miscnodes.h:46
struct JsonExprState * jsestate
Definition: execExpr.h:756
struct ExprEvalStep::@57::@105 jsonexpr
Node * expr
Definition: primnodes.h:1816
JsonBehaviorType btype
Definition: primnodes.h:1815
int jump_eval_coercion
Definition: execnodes.h:1107
NullableDatum empty
Definition: execnodes.h:1093
FunctionCallInfo input_fcinfo
Definition: execnodes.h:1121
JsonExpr * jsexpr
Definition: execnodes.h:1071
NullableDatum error
Definition: execnodes.h:1090
NullableDatum pathspec
Definition: execnodes.h:1077
ErrorSaveContext escontext
Definition: execnodes.h:1130
NullableDatum formatted_expr
Definition: execnodes.h:1074
List * passing_values
Definition: primnodes.h:1861
JsonBehavior * on_empty
Definition: primnodes.h:1864
List * passing_names
Definition: primnodes.h:1860
Node * path_spec
Definition: primnodes.h:1854
bool use_io_coercion
Definition: primnodes.h:1871
JsonReturning * returning
Definition: primnodes.h:1857
bool use_json_coercion
Definition: primnodes.h:1872
JsonBehavior * on_error
Definition: primnodes.h:1865
bool omit_quotes
Definition: primnodes.h:1878
Definition: value.h:64
char * sval
Definition: value.h:68

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

Referenced by ExecInitExprRec().

◆ ExecInitQual()

ExprState * ExecInitQual ( List qual,
PlanState parent 
)

Definition at line 229 of file execExpr.c.

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

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

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

◆ ExecInitSubPlanExpr()

static void ExecInitSubPlanExpr ( SubPlan subplan,
ExprState state,
Datum resv,
bool *  resnull 
)
static

Definition at line 2814 of file execExpr.c.

2817{
2818 ExprEvalStep scratch = {0};
2819 SubPlanState *sstate;
2820 ListCell *pvar;
2821 ListCell *l;
2822
2823 if (!state->parent)
2824 elog(ERROR, "SubPlan found with no parent plan");
2825
2826 /*
2827 * Generate steps to evaluate input arguments for the subplan.
2828 *
2829 * We evaluate the argument expressions into ExprState's resvalue/resnull,
2830 * and then use PARAM_SET to update the parameter. We do that, instead of
2831 * evaluating directly into the param, to avoid depending on the pointer
2832 * value remaining stable / being included in the generated expression. No
2833 * danger of conflicts with other uses of resvalue/resnull as storing and
2834 * using the value always is in subsequent steps.
2835 *
2836 * Any calculation we have to do can be done in the parent econtext, since
2837 * the Param values don't need to have per-query lifetime.
2838 */
2839 Assert(list_length(subplan->parParam) == list_length(subplan->args));
2840 forboth(l, subplan->parParam, pvar, subplan->args)
2841 {
2842 int paramid = lfirst_int(l);
2843 Expr *arg = (Expr *) lfirst(pvar);
2844
2846 &state->resvalue, &state->resnull);
2847
2848 scratch.opcode = EEOP_PARAM_SET;
2849 scratch.d.param.paramid = paramid;
2850 /* paramtype's not actually used, but we might as well fill it */
2851 scratch.d.param.paramtype = exprType((Node *) arg);
2852 ExprEvalPushStep(state, &scratch);
2853 }
2854
2855 sstate = ExecInitSubPlan(subplan, state->parent);
2856
2857 /* add SubPlanState nodes to state->parent->subPlan */
2858 state->parent->subPlan = lappend(state->parent->subPlan,
2859 sstate);
2860
2861 scratch.opcode = EEOP_SUBPLAN;
2862 scratch.resvalue = resv;
2863 scratch.resnull = resnull;
2864 scratch.d.subplan.sstate = sstate;
2865
2866 ExprEvalPushStep(state, &scratch);
2867}
@ EEOP_SUBPLAN
Definition: execExpr.h:275
@ EEOP_PARAM_SET
Definition: execExpr.h:177
SubPlanState * ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
Definition: nodeSubplan.c:852
SubPlanState * sstate
Definition: execExpr.h:691
struct ExprEvalStep::@57::@98 subplan
List * args
Definition: primnodes.h:1124
List * parParam
Definition: primnodes.h:1123

References arg, SubPlan::args, Assert(), ExprEvalStep::d, EEOP_PARAM_SET, EEOP_SUBPLAN, elog, ERROR, ExecInitExprRec(), ExecInitSubPlan(), ExprEvalPushStep(), exprType(), forboth, lappend(), lfirst, lfirst_int, list_length(), ExprEvalStep::opcode, ExprEvalStep::param, ExprEvalStep::paramid, ExprEvalStep::paramtype, SubPlan::parParam, ExprEvalStep::resnull, ExprEvalStep::resvalue, ExprEvalStep::sstate, and ExprEvalStep::subplan.

Referenced by ExecInitExprRec(), and ExecPushExprSetupSteps().

◆ ExecInitSubscriptingRef()

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

Definition at line 3236 of file execExpr.c.

3238{
3239 bool isAssignment = (sbsref->refassgnexpr != NULL);
3240 int nupper = list_length(sbsref->refupperindexpr);
3241 int nlower = list_length(sbsref->reflowerindexpr);
3242 const SubscriptRoutines *sbsroutines;
3243 SubscriptingRefState *sbsrefstate;
3244 SubscriptExecSteps methods;
3245 char *ptr;
3246 List *adjust_jumps = NIL;
3247 ListCell *lc;
3248 int i;
3249
3250 /* Look up the subscripting support methods */
3251 sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype, NULL);
3252 if (!sbsroutines)
3253 ereport(ERROR,
3254 (errcode(ERRCODE_DATATYPE_MISMATCH),
3255 errmsg("cannot subscript type %s because it does not support subscripting",
3256 format_type_be(sbsref->refcontainertype)),
3257 state->parent ?
3258 executor_errposition(state->parent->state,
3259 exprLocation((Node *) sbsref)) : 0));
3260
3261 /* Allocate sbsrefstate, with enough space for per-subscript arrays too */
3262 sbsrefstate = palloc0(MAXALIGN(sizeof(SubscriptingRefState)) +
3263 (nupper + nlower) * (sizeof(Datum) +
3264 2 * sizeof(bool)));
3265
3266 /* Fill constant fields of SubscriptingRefState */
3267 sbsrefstate->isassignment = isAssignment;
3268 sbsrefstate->numupper = nupper;
3269 sbsrefstate->numlower = nlower;
3270 /* Set up per-subscript arrays */
3271 ptr = ((char *) sbsrefstate) + MAXALIGN(sizeof(SubscriptingRefState));
3272 sbsrefstate->upperindex = (Datum *) ptr;
3273 ptr += nupper * sizeof(Datum);
3274 sbsrefstate->lowerindex = (Datum *) ptr;
3275 ptr += nlower * sizeof(Datum);
3276 sbsrefstate->upperprovided = (bool *) ptr;
3277 ptr += nupper * sizeof(bool);
3278 sbsrefstate->lowerprovided = (bool *) ptr;
3279 ptr += nlower * sizeof(bool);
3280 sbsrefstate->upperindexnull = (bool *) ptr;
3281 ptr += nupper * sizeof(bool);
3282 sbsrefstate->lowerindexnull = (bool *) ptr;
3283 /* ptr += nlower * sizeof(bool); */
3284
3285 /*
3286 * Let the container-type-specific code have a chance. It must fill the
3287 * "methods" struct with function pointers for us to possibly use in
3288 * execution steps below; and it can optionally set up some data pointed
3289 * to by the workspace field.
3290 */
3291 memset(&methods, 0, sizeof(methods));
3292 sbsroutines->exec_setup(sbsref, sbsrefstate, &methods);
3293
3294 /*
3295 * Evaluate array input. It's safe to do so into resv/resnull, because we
3296 * won't use that as target for any of the other subexpressions, and it'll
3297 * be overwritten by the final EEOP_SBSREF_FETCH/ASSIGN step, which is
3298 * pushed last.
3299 */
3300 ExecInitExprRec(sbsref->refexpr, state, resv, resnull);
3301
3302 /*
3303 * If refexpr yields NULL, and the operation should be strict, then result
3304 * is NULL. We can implement this with just JUMP_IF_NULL, since we
3305 * evaluated the array into the desired target location.
3306 */
3307 if (!isAssignment && sbsroutines->fetch_strict)
3308 {
3309 scratch->opcode = EEOP_JUMP_IF_NULL;
3310 scratch->d.jump.jumpdone = -1; /* adjust later */
3311 ExprEvalPushStep(state, scratch);
3312 adjust_jumps = lappend_int(adjust_jumps,
3313 state->steps_len - 1);
3314 }
3315
3316 /* Evaluate upper subscripts */
3317 i = 0;
3318 foreach(lc, sbsref->refupperindexpr)
3319 {
3320 Expr *e = (Expr *) lfirst(lc);
3321
3322 /* When slicing, individual subscript bounds can be omitted */
3323 if (!e)
3324 {
3325 sbsrefstate->upperprovided[i] = false;
3326 sbsrefstate->upperindexnull[i] = true;
3327 }
3328 else
3329 {
3330 sbsrefstate->upperprovided[i] = true;
3331 /* Each subscript is evaluated into appropriate array entry */
3333 &sbsrefstate->upperindex[i],
3334 &sbsrefstate->upperindexnull[i]);
3335 }
3336 i++;
3337 }
3338
3339 /* Evaluate lower subscripts similarly */
3340 i = 0;
3341 foreach(lc, sbsref->reflowerindexpr)
3342 {
3343 Expr *e = (Expr *) lfirst(lc);
3344
3345 /* When slicing, individual subscript bounds can be omitted */
3346 if (!e)
3347 {
3348 sbsrefstate->lowerprovided[i] = false;
3349 sbsrefstate->lowerindexnull[i] = true;
3350 }
3351 else
3352 {
3353 sbsrefstate->lowerprovided[i] = true;
3354 /* Each subscript is evaluated into appropriate array entry */
3356 &sbsrefstate->lowerindex[i],
3357 &sbsrefstate->lowerindexnull[i]);
3358 }
3359 i++;
3360 }
3361
3362 /* SBSREF_SUBSCRIPTS checks and converts all the subscripts at once */
3363 if (methods.sbs_check_subscripts)
3364 {
3365 scratch->opcode = EEOP_SBSREF_SUBSCRIPTS;
3367 scratch->d.sbsref_subscript.state = sbsrefstate;
3368 scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */
3369 ExprEvalPushStep(state, scratch);
3370 adjust_jumps = lappend_int(adjust_jumps,
3371 state->steps_len - 1);
3372 }
3373
3374 if (isAssignment)
3375 {
3376 Datum *save_innermost_caseval;
3377 bool *save_innermost_casenull;
3378
3379 /* Check for unimplemented methods */
3380 if (!methods.sbs_assign)
3381 ereport(ERROR,
3382 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3383 errmsg("type %s does not support subscripted assignment",
3384 format_type_be(sbsref->refcontainertype))));
3385
3386 /*
3387 * We might have a nested-assignment situation, in which the
3388 * refassgnexpr is itself a FieldStore or SubscriptingRef that needs
3389 * to obtain and modify the previous value of the array element or
3390 * slice being replaced. If so, we have to extract that value from
3391 * the array and pass it down via the CaseTestExpr mechanism. It's
3392 * safe to reuse the CASE mechanism because there cannot be a CASE
3393 * between here and where the value would be needed, and an array
3394 * assignment can't be within a CASE either. (So saving and restoring
3395 * innermost_caseval is just paranoia, but let's do it anyway.)
3396 *
3397 * Since fetching the old element might be a nontrivial expense, do it
3398 * only if the argument actually needs it.
3399 */
3401 {
3402 if (!methods.sbs_fetch_old)
3403 ereport(ERROR,
3404 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3405 errmsg("type %s does not support subscripted assignment",
3406 format_type_be(sbsref->refcontainertype))));
3407 scratch->opcode = EEOP_SBSREF_OLD;
3408 scratch->d.sbsref.subscriptfunc = methods.sbs_fetch_old;
3409 scratch->d.sbsref.state = sbsrefstate;
3410 ExprEvalPushStep(state, scratch);
3411 }
3412
3413 /* SBSREF_OLD puts extracted value into prevvalue/prevnull */
3414 save_innermost_caseval = state->innermost_caseval;
3415 save_innermost_casenull = state->innermost_casenull;
3416 state->innermost_caseval = &sbsrefstate->prevvalue;
3417 state->innermost_casenull = &sbsrefstate->prevnull;
3418
3419 /* evaluate replacement value into replacevalue/replacenull */
3421 &sbsrefstate->replacevalue, &sbsrefstate->replacenull);
3422
3423 state->innermost_caseval = save_innermost_caseval;
3424 state->innermost_casenull = save_innermost_casenull;
3425
3426 /* and perform the assignment */
3427 scratch->opcode = EEOP_SBSREF_ASSIGN;
3428 scratch->d.sbsref.subscriptfunc = methods.sbs_assign;
3429 scratch->d.sbsref.state = sbsrefstate;
3430 ExprEvalPushStep(state, scratch);
3431 }
3432 else
3433 {
3434 /* array fetch is much simpler */
3435 scratch->opcode = EEOP_SBSREF_FETCH;
3436 scratch->d.sbsref.subscriptfunc = methods.sbs_fetch;
3437 scratch->d.sbsref.state = sbsrefstate;
3438 ExprEvalPushStep(state, scratch);
3439 }
3440
3441 /* adjust jump targets */
3442 foreach(lc, adjust_jumps)
3443 {
3444 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
3445
3446 if (as->opcode == EEOP_SBSREF_SUBSCRIPTS)
3447 {
3448 Assert(as->d.sbsref_subscript.jumpdone == -1);
3449 as->d.sbsref_subscript.jumpdone = state->steps_len;
3450 }
3451 else
3452 {
3454 Assert(as->d.jump.jumpdone == -1);
3455 as->d.jump.jumpdone = state->steps_len;
3456 }
3457 }
3458}
#define MAXALIGN(LEN)
Definition: c.h:824
static bool isAssignmentIndirectionExpr(Expr *expr)
Definition: execExpr.c:3478
@ EEOP_SBSREF_SUBSCRIPTS
Definition: execExpr.h:229
@ EEOP_SBSREF_FETCH
Definition: execExpr.h:242
@ EEOP_SBSREF_ASSIGN
Definition: execExpr.h:239
@ EEOP_SBSREF_OLD
Definition: execExpr.h:236
const struct SubscriptRoutines * getSubscriptingRoutines(Oid typid, Oid *typelemp)
Definition: lsyscache.c:3295
ExecEvalBoolSubroutine subscriptfunc
Definition: execExpr.h:568
struct ExprEvalStep::@57::@85 sbsref_subscript
struct ExprEvalStep::@57::@86 sbsref
struct SubscriptingRefState * state
Definition: execExpr.h:570
ExecEvalSubroutine sbs_fetch_old
Definition: execExpr.h:817
ExecEvalBoolSubroutine sbs_check_subscripts
Definition: execExpr.h:814
ExecEvalSubroutine sbs_assign
Definition: execExpr.h:816
ExecEvalSubroutine sbs_fetch
Definition: execExpr.h:815
SubscriptExecSetup exec_setup
Definition: subscripting.h:161
Expr * refassgnexpr
Definition: primnodes.h:735
List * refupperindexpr
Definition: primnodes.h:725
Expr * refexpr
Definition: primnodes.h:733
List * reflowerindexpr
Definition: primnodes.h:731

References Assert(), ExprEvalStep::d, EEOP_JUMP_IF_NULL, EEOP_SBSREF_ASSIGN, EEOP_SBSREF_FETCH, EEOP_SBSREF_OLD, EEOP_SBSREF_SUBSCRIPTS, ereport, errcode(), errmsg(), ERROR, SubscriptRoutines::exec_setup, ExecInitExprRec(), executor_errposition(), ExprEvalPushStep(), exprLocation(), SubscriptRoutines::fetch_strict, format_type_be(), getSubscriptingRoutines(), i, SubscriptingRefState::isassignment, isAssignmentIndirectionExpr(), ExprEvalStep::jump, ExprEvalStep::jumpdone, lappend_int(), lfirst, lfirst_int, list_length(), SubscriptingRefState::lowerindex, SubscriptingRefState::lowerindexnull, SubscriptingRefState::lowerprovided, MAXALIGN, NIL, SubscriptingRefState::numlower, SubscriptingRefState::numupper, ExprEvalStep::opcode, palloc0(), SubscriptingRefState::prevnull, SubscriptingRefState::prevvalue, SubscriptingRef::refassgnexpr, SubscriptingRef::refexpr, SubscriptingRef::reflowerindexpr, SubscriptingRef::refupperindexpr, SubscriptingRefState::replacenull, SubscriptingRefState::replacevalue, SubscriptExecSteps::sbs_assign, SubscriptExecSteps::sbs_check_subscripts, SubscriptExecSteps::sbs_fetch, SubscriptExecSteps::sbs_fetch_old, ExprEvalStep::sbsref, ExprEvalStep::sbsref_subscript, ExprEvalStep::state, ExprEvalStep::subscriptfunc, SubscriptingRefState::upperindex, SubscriptingRefState::upperindexnull, and SubscriptingRefState::upperprovided.

Referenced by ExecInitExprRec().

◆ ExecInitWholeRowVar()

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

Definition at line 3157 of file execExpr.c.

3158{
3159 PlanState *parent = state->parent;
3160
3161 /* fill in all but the target */
3162 scratch->opcode = EEOP_WHOLEROW;
3163 scratch->d.wholerow.var = variable;
3164 scratch->d.wholerow.first = true;
3165 scratch->d.wholerow.slow = false;
3166 scratch->d.wholerow.tupdesc = NULL; /* filled at runtime */
3167 scratch->d.wholerow.junkFilter = NULL;
3168
3169 /* update ExprState flags if Var refers to OLD/NEW */
3170 if (variable->varreturningtype == VAR_RETURNING_OLD)
3171 state->flags |= EEO_FLAG_HAS_OLD;
3172 else if (variable->varreturningtype == VAR_RETURNING_NEW)
3173 state->flags |= EEO_FLAG_HAS_NEW;
3174
3175 /*
3176 * If the input tuple came from a subquery, it might contain "resjunk"
3177 * columns (such as GROUP BY or ORDER BY columns), which we don't want to
3178 * keep in the whole-row result. We can get rid of such columns by
3179 * passing the tuple through a JunkFilter --- but to make one, we have to
3180 * lay our hands on the subquery's targetlist. Fortunately, there are not
3181 * very many cases where this can happen, and we can identify all of them
3182 * by examining our parent PlanState. We assume this is not an issue in
3183 * standalone expressions that don't have parent plans. (Whole-row Vars
3184 * can occur in such expressions, but they will always be referencing
3185 * table rows.)
3186 */
3187 if (parent)
3188 {
3189 PlanState *subplan = NULL;
3190
3191 switch (nodeTag(parent))
3192 {
3193 case T_SubqueryScanState:
3194 subplan = ((SubqueryScanState *) parent)->subplan;
3195 break;
3196 case T_CteScanState:
3197 subplan = ((CteScanState *) parent)->cteplanstate;
3198 break;
3199 default:
3200 break;
3201 }
3202
3203 if (subplan)
3204 {
3205 bool junk_filter_needed = false;
3206 ListCell *tlist;
3207
3208 /* Detect whether subplan tlist actually has any junk columns */
3209 foreach(tlist, subplan->plan->targetlist)
3210 {
3211 TargetEntry *tle = (TargetEntry *) lfirst(tlist);
3212
3213 if (tle->resjunk)
3214 {
3215 junk_filter_needed = true;
3216 break;
3217 }
3218 }
3219
3220 /* If so, build the junkfilter now */
3221 if (junk_filter_needed)
3222 {
3223 scratch->d.wholerow.junkFilter =
3225 ExecInitExtraTupleSlot(parent->state, NULL,
3226 &TTSOpsVirtual));
3227 }
3228 }
3229 }
3230}
@ EEOP_WHOLEROW
Definition: execExpr.h:96
JunkFilter * ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
Definition: execJunk.c:60
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:2020
JunkFilter * junkFilter
Definition: execExpr.h:351
struct ExprEvalStep::@57::@60 wholerow
bool first
Definition: execExpr.h:348
Plan * plan
Definition: execnodes.h:1165
EState * state
Definition: execnodes.h:1167
List * targetlist
Definition: plannodes.h:229

References ExprEvalStep::d, EEO_FLAG_HAS_NEW, EEO_FLAG_HAS_OLD, EEOP_WHOLEROW, ExecInitExtraTupleSlot(), ExecInitJunkFilter(), ExprEvalStep::first, ExprEvalStep::junkFilter, lfirst, nodeTag, ExprEvalStep::opcode, PlanState::plan, ExprEvalStep::slow, PlanState::state, Plan::targetlist, TTSOpsVirtual, ExprEvalStep::tupdesc, ExprEvalStep::var, VAR_RETURNING_NEW, VAR_RETURNING_OLD, and ExprEvalStep::wholerow.

Referenced by ExecInitExprRec().

◆ ExecPrepareCheck()

ExprState * ExecPrepareCheck ( List qual,
EState estate 
)

Definition at line 816 of file execExpr.c.

817{
818 ExprState *result;
819 MemoryContext oldcontext;
820
821 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
822
823 qual = (List *) expression_planner((Expr *) qual);
824
825 result = ExecInitCheck(qual, NULL);
826
827 MemoryContextSwitchTo(oldcontext);
828
829 return result;
830}
ExprState * ExecInitCheck(List *qual, PlanState *parent)
Definition: execExpr.c:315
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
Expr * expression_planner(Expr *expr)
Definition: planner.c:6763
MemoryContext es_query_cxt
Definition: execnodes.h:710

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

Referenced by ExecPartitionCheck().

◆ ExecPrepareExpr()

ExprState * ExecPrepareExpr ( Expr node,
EState estate 
)

◆ ExecPrepareExprList()

List * ExecPrepareExprList ( List nodes,
EState estate 
)

Definition at line 839 of file execExpr.c.

840{
841 List *result = NIL;
842 MemoryContext oldcontext;
843 ListCell *lc;
844
845 /* Ensure that the list cell nodes are in the right context too */
846 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
847
848 foreach(lc, nodes)
849 {
850 Expr *e = (Expr *) lfirst(lc);
851
852 result = lappend(result, ExecPrepareExpr(e, estate));
853 }
854
855 MemoryContextSwitchTo(oldcontext);
856
857 return result;
858}
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:765

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

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

◆ ExecPrepareQual()

ExprState * ExecPrepareQual ( List qual,
EState estate 
)

Definition at line 793 of file execExpr.c.

794{
795 ExprState *result;
796 MemoryContext oldcontext;
797
798 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
799
800 qual = (List *) expression_planner((Expr *) qual);
801
802 result = ExecInitQual(qual, NULL);
803
804 MemoryContextSwitchTo(oldcontext);
805
806 return result;
807}
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:229

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

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

◆ ExecPushExprSetupSteps()

static void ExecPushExprSetupSteps ( ExprState state,
ExprSetupInfo info 
)
static

Definition at line 2890 of file execExpr.c.

2891{
2892 ExprEvalStep scratch = {0};
2893 ListCell *lc;
2894
2895 scratch.resvalue = NULL;
2896 scratch.resnull = NULL;
2897
2898 /*
2899 * Add steps deforming the ExprState's inner/outer/scan/old/new slots as
2900 * much as required by any Vars appearing in the expression.
2901 */
2902 if (info->last_inner > 0)
2903 {
2904 scratch.opcode = EEOP_INNER_FETCHSOME;
2905 scratch.d.fetch.last_var = info->last_inner;
2906 scratch.d.fetch.fixed = false;
2907 scratch.d.fetch.kind = NULL;
2908 scratch.d.fetch.known_desc = NULL;
2909 if (ExecComputeSlotInfo(state, &scratch))
2910 ExprEvalPushStep(state, &scratch);
2911 }
2912 if (info->last_outer > 0)
2913 {
2914 scratch.opcode = EEOP_OUTER_FETCHSOME;
2915 scratch.d.fetch.last_var = info->last_outer;
2916 scratch.d.fetch.fixed = false;
2917 scratch.d.fetch.kind = NULL;
2918 scratch.d.fetch.known_desc = NULL;
2919 if (ExecComputeSlotInfo(state, &scratch))
2920 ExprEvalPushStep(state, &scratch);
2921 }
2922 if (info->last_scan > 0)
2923 {
2924 scratch.opcode = EEOP_SCAN_FETCHSOME;
2925 scratch.d.fetch.last_var = info->last_scan;
2926 scratch.d.fetch.fixed = false;
2927 scratch.d.fetch.kind = NULL;
2928 scratch.d.fetch.known_desc = NULL;
2929 if (ExecComputeSlotInfo(state, &scratch))
2930 ExprEvalPushStep(state, &scratch);
2931 }
2932 if (info->last_old > 0)
2933 {
2934 scratch.opcode = EEOP_OLD_FETCHSOME;
2935 scratch.d.fetch.last_var = info->last_old;
2936 scratch.d.fetch.fixed = false;
2937 scratch.d.fetch.kind = NULL;
2938 scratch.d.fetch.known_desc = NULL;
2939 if (ExecComputeSlotInfo(state, &scratch))
2940 ExprEvalPushStep(state, &scratch);
2941 }
2942 if (info->last_new > 0)
2943 {
2944 scratch.opcode = EEOP_NEW_FETCHSOME;
2945 scratch.d.fetch.last_var = info->last_new;
2946 scratch.d.fetch.fixed = false;
2947 scratch.d.fetch.kind = NULL;
2948 scratch.d.fetch.known_desc = NULL;
2949 if (ExecComputeSlotInfo(state, &scratch))
2950 ExprEvalPushStep(state, &scratch);
2951 }
2952
2953 /*
2954 * Add steps to execute any MULTIEXPR SubPlans appearing in the
2955 * expression. We need to evaluate these before any of the Params
2956 * referencing their outputs are used, but after we've prepared for any
2957 * Var references they may contain. (There cannot be cross-references
2958 * between MULTIEXPR SubPlans, so we needn't worry about their order.)
2959 */
2960 foreach(lc, info->multiexpr_subplans)
2961 {
2962 SubPlan *subplan = (SubPlan *) lfirst(lc);
2963
2965
2966 /* The result can be ignored, but we better put it somewhere */
2967 ExecInitSubPlanExpr(subplan, state,
2968 &state->resvalue, &state->resnull);
2969 }
2970}
AttrNumber last_inner
Definition: execExpr.c:62
AttrNumber last_new
Definition: execExpr.c:66
List * multiexpr_subplans
Definition: execExpr.c:68
AttrNumber last_old
Definition: execExpr.c:65

References Assert(), ExprEvalStep::d, EEOP_INNER_FETCHSOME, EEOP_NEW_FETCHSOME, EEOP_OLD_FETCHSOME, EEOP_OUTER_FETCHSOME, EEOP_SCAN_FETCHSOME, ExecComputeSlotInfo(), ExecInitSubPlanExpr(), ExprEvalPushStep(), ExprEvalStep::fetch, ExprEvalStep::fixed, ExprEvalStep::kind, ExprEvalStep::known_desc, ExprSetupInfo::last_inner, ExprSetupInfo::last_new, ExprSetupInfo::last_old, ExprSetupInfo::last_outer, ExprSetupInfo::last_scan, ExprEvalStep::last_var, lfirst, MULTIEXPR_SUBLINK, ExprSetupInfo::multiexpr_subplans, ExprEvalStep::opcode, ExprEvalStep::resnull, ExprEvalStep::resvalue, and SubPlan::subLinkType.

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

◆ ExecReadyExpr()

static void ExecReadyExpr ( ExprState state)
static

◆ expr_setup_walker()

static bool expr_setup_walker ( Node node,
ExprSetupInfo info 
)
static

Definition at line 2976 of file execExpr.c.

2977{
2978 if (node == NULL)
2979 return false;
2980 if (IsA(node, Var))
2981 {
2982 Var *variable = (Var *) node;
2983 AttrNumber attnum = variable->varattno;
2984
2985 switch (variable->varno)
2986 {
2987 case INNER_VAR:
2988 info->last_inner = Max(info->last_inner, attnum);
2989 break;
2990
2991 case OUTER_VAR:
2992 info->last_outer = Max(info->last_outer, attnum);
2993 break;
2994
2995 /* INDEX_VAR is handled by default case */
2996
2997 default:
2998 switch (variable->varreturningtype)
2999 {
3001 info->last_scan = Max(info->last_scan, attnum);
3002 break;
3003 case VAR_RETURNING_OLD:
3004 info->last_old = Max(info->last_old, attnum);
3005 break;
3006 case VAR_RETURNING_NEW:
3007 info->last_new = Max(info->last_new, attnum);
3008 break;
3009 }
3010 break;
3011 }
3012 return false;
3013 }
3014
3015 /* Collect all MULTIEXPR SubPlans, too */
3016 if (IsA(node, SubPlan))
3017 {
3018 SubPlan *subplan = (SubPlan *) node;
3019
3020 if (subplan->subLinkType == MULTIEXPR_SUBLINK)
3022 subplan);
3023 }
3024
3025 /*
3026 * Don't examine the arguments or filters of Aggrefs or WindowFuncs,
3027 * because those do not represent expressions to be evaluated within the
3028 * calling expression's econtext. GroupingFunc arguments are never
3029 * evaluated at all.
3030 */
3031 if (IsA(node, Aggref))
3032 return false;
3033 if (IsA(node, WindowFunc))
3034 return false;
3035 if (IsA(node, GroupingFunc))
3036 return false;
3037 return expression_tree_walker(node, expr_setup_walker, info);
3038}
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:153

References attnum, expr_setup_walker(), expression_tree_walker, INNER_VAR, IsA, lappend(), ExprSetupInfo::last_inner, ExprSetupInfo::last_new, ExprSetupInfo::last_old, ExprSetupInfo::last_outer, ExprSetupInfo::last_scan, Max, MULTIEXPR_SUBLINK, ExprSetupInfo::multiexpr_subplans, OUTER_VAR, SubPlan::subLinkType, VAR_RETURNING_DEFAULT, VAR_RETURNING_NEW, and VAR_RETURNING_OLD.

Referenced by ExecBuildAggTrans(), ExecBuildUpdateProjection(), ExecCreateExprSetupSteps(), and expr_setup_walker().

◆ ExprEvalPushStep()

◆ isAssignmentIndirectionExpr()

static bool isAssignmentIndirectionExpr ( Expr expr)
static

Definition at line 3478 of file execExpr.c.

3479{
3480 if (expr == NULL)
3481 return false; /* just paranoia */
3482 if (IsA(expr, FieldStore))
3483 {
3484 FieldStore *fstore = (FieldStore *) expr;
3485
3486 if (fstore->arg && IsA(fstore->arg, CaseTestExpr))
3487 return true;
3488 }
3489 else if (IsA(expr, SubscriptingRef))
3490 {
3491 SubscriptingRef *sbsRef = (SubscriptingRef *) expr;
3492
3493 if (sbsRef->refexpr && IsA(sbsRef->refexpr, CaseTestExpr))
3494 return true;
3495 }
3496 else if (IsA(expr, CoerceToDomain))
3497 {
3498 CoerceToDomain *cd = (CoerceToDomain *) expr;
3499
3500 return isAssignmentIndirectionExpr(cd->arg);
3501 }
3502 else if (IsA(expr, RelabelType))
3503 {
3504 RelabelType *r = (RelabelType *) expr;
3505
3507 }
3508 return false;
3509}

References FieldStore::arg, RelabelType::arg, CoerceToDomain::arg, IsA, isAssignmentIndirectionExpr(), and SubscriptingRef::refexpr.

Referenced by ExecInitSubscriptingRef(), and isAssignmentIndirectionExpr().