1/*-------------------------------------------------------------------------
4 * routines to support sub-selects appearing in expressions
6 * This module is concerned with executing SubPlan expression nodes, which
7 * should not be confused with sub-SELECTs appearing in FROM. SubPlans are
8 * divided into "initplans", which are those that need only one evaluation per
9 * query (among other restrictions, this requires that they don't use any
10 * direct correlation variables from the parent plan level), and "regular"
11 * subplans, which are re-evaluated every time their result is required.
14 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
15 * Portions Copyright (c) 1994, Regents of the University of California
18 * src/backend/executor/nodeSubplan.c
20 *-------------------------------------------------------------------------
24 * ExecSubPlan - process a subselect
25 * ExecInitSubPlan - initialize a subselect
55/* ----------------------------------------------------------------
58 * This is the main entry point for execution of a regular SubPlan.
59 * ----------------------------------------------------------------
73 /* Set non-null as default */
78 elog(
ERROR,
"CTE subplans should not be executed via ExecSubPlan");
80 elog(
ERROR,
"cannot set parent params from subquery");
82 /* Force forward-scan mode for evaluation */
85 /* Select appropriate evaluation strategy */
91 /* restore scan direction */
98 * ExecHashSubPlan: store subselect result in an in-memory hash table
110 /* Shouldn't have any direct correlation Vars */
112 elog(
ERROR,
"hashed subplan with direct correlation not supported");
115 * If first time through or we need to rescan the subplan, build the hash
122 * The result for an empty subplan is always FALSE; no need to evaluate
130 * Evaluate lefthand expressions and form a projection tuple. First we
131 * have to set the econtext to use (hack alert!).
137 * If the LHS is all non-null, probe for an exact match in the main hash
138 * table. If we find one, the result is TRUE. Otherwise, scan the
139 * partly-null table to see if there are any rows that aren't provably
140 * unequal to the LHS; if so, the result is UNKNOWN. (We skip that part
141 * if we don't care about UNKNOWN.) Otherwise, the result is FALSE.
143 * Note: the reason we can avoid a full scan of the main hash table is
144 * that the combining operators are assumed never to yield NULL when both
145 * inputs are non-null. If they were to do so, we might need to produce
146 * UNKNOWN instead of FALSE because of an UNKNOWN result in comparing the
147 * LHS to some main-table entry --- which is a comparison we will not even
148 * make, unless there's a chance match of hash keys.
164 * When the LHS is partly or wholly NULL, we can never return TRUE. If we
165 * don't care about UNKNOWN, just return FALSE. Otherwise, if the LHS is
166 * wholly NULL, immediately return UNKNOWN. (Since the combining
167 * operators are strict, the result could only be FALSE if the sub-select
168 * were empty, but we already handled that case.) Otherwise, we must scan
169 * both the main and partly-null tables to see if there are any rows that
170 * aren't provably unequal to the LHS; if so, the result is UNKNOWN.
171 * Otherwise, the result is FALSE.
174 /* just return FALSE */ ;
177 /* Scan partly-null table first, since more likely to get a match */
186 * Note: because we are typically called in a per-tuple context, we have
187 * to explicitly clear the projected tuple before returning. Otherwise,
188 * we'll have a double-free situation: the per-tuple context will probably
189 * be reset before we're called again, and then the tuple slot will think
190 * it still needs to free the tuple.
194 /* Also must reset the innerecontext after each hashtable lookup. */
201 * ExecScanSubPlan: default case where we have to rescan subplan each time
214 bool found =
false;
/* true if got at least one subplan tuple */
218 /* Initialize ArrayBuildStateAny in caller's context, if needed */
224 * We are probably in a short-lived expression-evaluation context. Switch
225 * to the per-query context for manipulating the child plan's chgParam,
226 * calling ExecProcNode on it, etc.
231 * We rely on the caller to evaluate plan correlation values, if
232 * necessary. However we still need to record the fact that the values
233 * (might have) changed, otherwise the ExecReScan() below won't know that
234 * nodes need to be rescanned.
243 /* with that done, we can reset the subplan */
247 * For all sublink types except EXPR_SUBLINK and ARRAY_SUBLINK, the result
248 * is boolean as are the results of the combining operators. We combine
249 * results across tuples (if the subplan produces more than one) using OR
250 * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK.
251 * (ROWCOMPARE_SUBLINK doesn't allow multiple tuples from the subplan.)
252 * NULL results from the combining operators are handled according to the
253 * usual SQL semantics for OR and AND. The result for no input tuples is
254 * FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for
255 * ROWCOMPARE_SUBLINK.
257 * For EXPR_SUBLINK we require the subplan to produce no more than one
258 * tuple, else an error is raised. If zero tuples are produced, we return
259 * NULL. Assuming we get a tuple, we just use its first column (there can
260 * be only one non-junk column in this case).
262 * For MULTIEXPR_SUBLINK, we push the per-column subplan outputs out to
263 * the setParams and then return a dummy false value. There must not be
264 * multiple tuples returned from the subplan; if zero tuples are produced,
265 * set the setParams to NULL.
267 * For ARRAY_SUBLINK we allow the subplan to produce any number of tuples,
268 * and form an array of the first column's values. Note in particular
269 * that we produce a zero-element array if no tuples are produced (this is
270 * a change from pre-8.3 behavior of returning NULL).
294 /* cannot allow multiple input tuples for EXPR sublink */
297 (
errcode(ERRCODE_CARDINALITY_VIOLATION),
298 errmsg(
"more than one row returned by a subquery used as an expression")));
302 * We need to copy the subplan's tuple in case the result is of
303 * pass-by-ref type --- our return value will point into this
304 * copied tuple! Can't use the subplan's instance of the tuple
305 * since it won't still be valid after next ExecProcNode() call.
306 * node->curTuple keeps track of the copied tuple for eventual
314 /* keep scanning subplan to make sure there's only one tuple */
320 /* cannot allow multiple input tuples for MULTIEXPR sublink */
323 (
errcode(ERRCODE_CARDINALITY_VIOLATION),
324 errmsg(
"more than one row returned by a subquery used as an expression")));
328 * We need to copy the subplan's tuple in case any result is of
329 * pass-by-ref type --- our output values will point into this
330 * copied tuple! Can't use the subplan's instance of the tuple
331 * since it won't still be valid after next ExecProcNode() call.
332 * node->curTuple keeps track of the copied tuple for eventual
340 * Now set all the setParam params from the columns of the tuple
355 /* keep scanning subplan to make sure there's only one tuple */
365 /* stash away current value */
370 /* keep scanning subplan to collect all values */
374 /* cannot allow multiple input tuples for ROWCOMPARE sublink either */
377 (
errcode(ERRCODE_CARDINALITY_VIOLATION),
378 errmsg(
"more than one row returned by a subquery used as an expression")));
383 * For ALL, ANY, and ROWCOMPARE sublinks, load up the Params
384 * representing the columns of the sub-select, and then evaluate the
385 * combining expression.
404 /* combine across rows per OR semantics */
411 break;
/* needn't look at any more rows */
416 /* combine across rows per AND semantics */
423 break;
/* needn't look at any more rows */
428 /* must be ROWCOMPARE_SUBLINK */
438 /* We return the result in the caller's context */
444 * deal with empty subplan result. result/isNull were previously
445 * initialized correctly for all sublink types except EXPR and
446 * ROWCOMPARE; for those, return NULL.
456 /* We don't care about function result, but set the setParams */
474 * buildSubPlanHash: load hash table by scanning subplan output.
490 * If we already had any hash tables, reset 'em; otherwise create empty
493 * If we need to distinguish accurately between FALSE and UNKNOWN (i.e.,
494 * NULL) results of the IN operation, then we have to store subplan output
495 * rows that are partly or wholly NULL. We store such rows in a separate
496 * hash table that we expect will be much smaller than the main table. (We
497 * can use hashing to eliminate partly-null rows that are not distinct. We
498 * keep them separate to minimize the cost of the inevitable full-table
499 * searches; see findPartialMatch.)
501 * If it's not necessary to distinguish FALSE and UNKNOWN, then we don't
502 * need to store subplan output rows that contain NULL.
504 * Because the input slot for each hash table is always the slot resulting
505 * from an ExecProject(), we can use TTSOpsVirtual for the input ops. This
506 * saves a needless fetch inner op step for the hashing ExprState created
507 * in BuildTupleHashTable().
538 nbuckets = 1;
/* there can only be one entry */
568 * We are probably in a short-lived expression-evaluation context. Switch
569 * to the per-query context for manipulating the child plan.
574 * Reset subplan to start.
579 * Scan the subplan and load the hash table(s). Note that when there are
580 * duplicate rows coming out of the sub-select, only one copy is stored.
591 * Load up the Params representing the raw sub-select outputs, then
592 * form the projection tuple to store in the hashtable.
608 * If result contains any nulls, store separately or not at all.
622 * Reset innerecontext after each inner tuple to free any memory used
623 * during ExecProject and hashtable lookup.
629 * Since the projected tuples are in the sub-query's context and not the
630 * main context, we'd better clear the tuple slot before there's any
631 * chance of a reset of the sub-query's context. Else we will have the
632 * potential for a double free attempt. (XXX possibly no longer needed,
642 * Return true if two tuples are definitely unequal in the indicated
645 * Nulls are neither equal nor unequal to anything else. A true result
646 * is obtained only if there are non-null fields that compare not-equal.
648 * slot1, slot2: the tuples to compare (must have same columns!)
649 * numCols: the number of attributes to be examined
650 * matchColIdx: array of attribute column numbers
651 * eqFunctions: array of fmgr lookup info for the equality functions to use
652 * evalContext: short-term memory context for executing the functions
660 const Oid *collations,
667 /* Reset and switch into the temp context. */
672 * We cannot report a match without checking all the fields, but we can
673 * report a non-match as soon as we find unequal fields. So, start
674 * comparing at the last field (least significant sort key). That's the
675 * most likely to be different if we are dealing with sorted input.
679 for (
i = numCols; --
i >= 0;)
690 continue;
/* can't prove anything here */
695 continue;
/* can't prove anything here */
697 /* Apply the type-specific equality function */
702 result =
true;
/* they are unequal */
713 * findPartialMatch: does the hashtable contain an entry that is not
714 * provably distinct from the tuple?
716 * We have to scan the whole hashtable; we can't usefully use hashkeys
717 * to guide probing, since we might get partial matches on tuples with
718 * hashkeys quite unrelated to what we'd get from the given tuple.
720 * Caller must provide the equality functions to use, since in cross-type
721 * cases these are different from the hashtable's internal functions.
727 int numCols = hashtable->
numCols;
748 /* No TermTupleHashIterator call needed here */
753 * slotAllNulls: is the slot completely NULL?
755 * This does not test for dropped columns, which is OK because we only
756 * use it on projected tuples.
764 for (
i = 1;
i <= ncols;
i++)
773 * slotNoNulls: is the slot entirely not NULL?
775 * This does not test for dropped columns, which is OK because we only
776 * use it on projected tuples.
784 for (
i = 1;
i <= ncols;
i++)
792/* ----------------------------------------------------------------
795 * Create a SubPlanState for a SubPlan; this is the SubPlan-specific part
796 * of ExecInitExpr(). We split it out so that it can be used for InitPlans
797 * as well as regular SubPlans. Note that we don't link the SubPlan into
798 * the parent's subPlan list, because that shouldn't happen for InitPlans.
799 * Instead, ExecInitExpr() does that one part.
801 * We also rely on ExecInitExpr(), more precisely ExecInitSubPlanExpr(), to
802 * evaluate input parameters, as that allows them to be evaluated as part of
803 * the expression referencing the SubPlan.
804 * ----------------------------------------------------------------
814 /* Link the SubPlanState to already-initialized subplan */
819 * This check can fail if the planner mistakenly puts a parallel-unsafe
820 * subplan into a parallelized subquery; see ExecSerializePlan.
823 elog(
ERROR,
"subplan \"%s\" was not initialized",
826 /* Link to parent's state, too */
829 /* Initialize subexpressions */
833 * initialize my state
850 * If this is an initplan, it has output parameters that the parent plan
851 * will use, so mark those parameters as needing evaluation. We don't
852 * actually run the subplan until we first need one of its outputs.
854 * A CTE subplan's output parameter is never to be evaluated in the normal
855 * way, so skip this in that case.
857 * Note that we don't set parent->chgParam here: the parent plan hasn't
858 * been run yet, so no need to force it to re-run.
875 * If we are going to hash the subquery output, initialize relevant stuff.
876 * (We don't create the hashtable until needed, though.)
884 Oid *cross_eq_funcoids;
892 /* We need a memory context to hold the hash table(s) */
895 "Subplan HashTable Context",
897 /* and a short-lived exprcontext for function evaluation */
901 * We use ExecProject to evaluate the lefthand and righthand
902 * expression lists and form tuples. (You might think that we could
903 * use the sub-select's output tuples directly, but that is not the
904 * case if we had to insert any run-time coercions of the sub-select's
905 * output datatypes; anyway this avoids storing any resjunk columns
906 * that might be in the sub-select's output.) Run through the
907 * combining expressions to build tlists for the lefthand and
910 * We also extract the combining operators themselves to initialize
911 * the equality and hashing functions for the hash tables.
915 /* single combining operator */
920 /* multiple combining operators */
925 /* shouldn't see anything else in a hashable subplan */
926 elog(
ERROR,
"unrecognized testexpr type: %d",
928 oplist =
NIL;
/* keep compiler quiet */
932 lefttlist = righttlist =
NIL;
940 /* we'll need the cross-type equality fns below, but not in sstate */
941 cross_eq_funcoids = (
Oid *)
palloc(ncols *
sizeof(
Oid));
955 /* Process lefthand argument */
961 lefttlist =
lappend(lefttlist, tle);
963 /* Process righthand argument */
969 righttlist =
lappend(righttlist, tle);
971 /* Lookup the equality function (potentially cross-type) */
972 cross_eq_funcoids[
i - 1] = opexpr->opfuncid;
976 /* Look up the equality function for the RHS type */
979 elog(
ERROR,
"could not find compatible hash operator for operator %u",
983 /* Lookup the associated hash functions */
985 &left_hashfn, &right_hashfn))
986 elog(
ERROR,
"could not find hash function for hash operator %u",
988 fmgr_info(left_hashfn, &lhs_hash_funcs[
i - 1]);
994 /* keyColIdx is just column numbers 1..n */
1001 * Construct tupdescs, slots and projection nodes for left and right
1002 * sides. The lefthand expressions will be evaluated in the parent
1003 * plan node's exprcontext, which we don't have access to here.
1004 * Fortunately we can just pass NULL for now and fill it in later
1005 * (hack alert!). The righthand expressions will be evaluated in our
1006 * own innerecontext.
1024 /* Build the ExprState for generating hash values */
1035 * Create comparator for lookups of rows in the table (potentially
1036 * cross-type comparisons).
1050/* ----------------------------------------------------------------
1053 * Executes a subplan and sets its output parameters.
1055 * This is called from ExecEvalParamExec() when the value of a PARAM_EXEC
1056 * parameter is requested and the param's execPlan field is set (indicating
1057 * that the param has not yet been evaluated). This allows lazy evaluation
1058 * of initplans: we don't run the subplan until/unless we need its output.
1059 * Note that this routine MUST clear the execPlan fields of the plan's
1060 * output parameters after evaluating them!
1062 * The results of this function are stored in the EState associated with the
1063 * ExprContext (particularly, its ecxt_param_exec_vals); any pass-by-ref
1064 * result Datums are allocated in the EState's per-query memory. The passed
1065 * econtext can be any ExprContext belonging to that EState; which one is
1066 * important only to the extent that the ExprContext's per-tuple memory
1067 * context is used to evaluate any parameters passed down to the subplan.
1068 * (Thus in principle, the shorter-lived the ExprContext the better, since
1069 * that data isn't needed after we return. In practice, because initplan
1070 * parameters are never more complex than Vars, Aggrefs, etc, evaluating them
1071 * currently never leaks any memory anyway.)
1072 * ----------------------------------------------------------------
1090 elog(
ERROR,
"ANY/ALL subselect unsupported as initplan");
1092 elog(
ERROR,
"CTE subplans should not be executed via ExecSetParamPlan");
1094 elog(
ERROR,
"correlated subplans should not be executed via ExecSetParamPlan");
1097 * Enforce forward scan direction regardless of caller. It's hard but not
1098 * impossible to get here in backward scan, so make it work anyway.
1102 /* Initialize ArrayBuildStateAny in caller's context, if needed */
1108 * Must switch to per-query memory context.
1113 * Run the plan. (If it needs to be rescanned, the first ExecProcNode
1114 * call will take care of that.)
1125 /* There can be only one setParam... */
1142 /* stash away current value */
1147 /* keep scanning subplan to collect all values */
1156 (
errcode(ERRCODE_CARDINALITY_VIOLATION),
1157 errmsg(
"more than one row returned by a subquery used as an expression")));
1162 * We need to copy the subplan's tuple into our own context, in case
1163 * any of the params are pass-by-ref type --- the pointers stored in
1164 * the param structs will point at this copied tuple! node->curTuple
1165 * keeps track of the copied tuple for eventual freeing.
1172 * Now set all the setParam params from the columns of the tuple
1188 /* There can be only one setParam... */
1193 * We build the result array in query context so it won't disappear;
1194 * to avoid leaking memory across repeated calls, we have to remember
1195 * the latest value, much as for curTuple above.
1210 /* There can be only one setParam... */
1220 /* For other sublink types, set all the output params to NULL */
1235 /* restore scan direction */
1240 * ExecSetParamPlanMulti
1242 * Apply ExecSetParamPlan to evaluate any not-yet-evaluated initplan output
1243 * parameters whose ParamIDs are listed in "params". Any listed params that
1244 * are not initplan outputs are ignored.
1246 * As with ExecSetParamPlan, any ExprContext belonging to the current EState
1247 * can be used, but in principle a shorter-lived ExprContext is better than a
1262 /* Parameter not evaluated yet, so go do it */
1264 /* ExecSetParamPlan should have processed this param... */
1271 * Mark an initplan as needing recalculation
1283 elog(
ERROR,
"direct correlated subquery unsupported as initplan");
1285 elog(
ERROR,
"setParam list of initplan is empty");
1287 elog(
ERROR,
"extParam set of initplan is empty");
1290 * Don't actually re-scan: it'll happen inside ExecSetParamPlan if needed.
1294 * Mark this subplan's output parameters as needing recalculation.
1296 * CTE subplans are never executed via parameter recalculation; instead
1297 * they get run when called by nodeCtescan.c. So don't mark the output
1298 * parameter of a CTE subplan as dirty, but do set the chgParam bit for it
1299 * so that dependent plan nodes will get told to rescan.
ArrayBuildStateAny * initArrayResultAny(Oid input_type, MemoryContext rcontext, bool subcontext)
ArrayBuildStateAny * accumArrayResultAny(ArrayBuildStateAny *astate, Datum dvalue, bool disnull, Oid input_type, MemoryContext rcontext)
Datum makeArrayResultAny(ArrayBuildStateAny *astate, MemoryContext rcontext, bool release)
int bms_next_member(const Bitmapset *a, int prevbit)
Bitmapset * bms_add_member(Bitmapset *a, int x)
long clamp_cardinality_to_long(Cardinality x)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
void ExecReScan(PlanState *node)
ExprState * ExecBuildHash32FromAttrs(TupleDesc desc, const TupleTableSlotOps *ops, FmgrInfo *hashfunctions, Oid *collations, int numCols, AttrNumber *keyColIdx, PlanState *parent, uint32 init_value)
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
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)
TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew, uint32 *hash)
TupleHashEntry FindTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, ExprState *eqcomp, ExprState *hashexpr)
TupleHashTable BuildTupleHashTable(PlanState *parent, TupleDesc inputDesc, const TupleTableSlotOps *inputOps, int numCols, AttrNumber *keyColIdx, const Oid *eqfuncoids, FmgrInfo *hashfunctions, Oid *collations, long nbuckets, Size additionalsize, MemoryContext metacxt, MemoryContext tablecxt, MemoryContext tempcxt, bool use_variable_hash_iv)
void ResetTupleHashTable(TupleHashTable hashtable)
const TupleTableSlotOps TTSOpsVirtual
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
const TupleTableSlotOps TTSOpsMinimalTuple
TupleDesc ExecTypeFromTL(List *targetList)
ExprContext * CreateExprContext(EState *estate)
#define ScanTupleHashTable(htable, iter)
#define TermTupleHashIterator(iter)
#define InitTupleHashIterator(htable, iter)
tuplehash_iterator TupleHashIterator
static MinimalTuple TupleHashEntryGetTuple(TupleHashEntry entry)
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
#define ResetExprContext(econtext)
static TupleTableSlot * ExecProcNode(PlanState *node)
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
void fmgr_info(Oid functionId, FmgrInfo *finfo)
#define fmgr_info_set_expr(expr, finfo)
Assert(PointerIsAligned(start, uint64))
void heap_freetuple(HeapTuple htup)
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
List * lappend(List *list, void *datum)
bool get_compatible_hash_operators(Oid opno, Oid *lhs_opno, Oid *rhs_opno)
RegProcedure get_opcode(Oid opno)
bool get_op_hash_functions(Oid opno, RegProcedure *lhs_procno, RegProcedure *rhs_procno)
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
void MemoryContextReset(MemoryContext context)
void pfree(void *pointer)
MemoryContext CurrentMemoryContext
#define AllocSetContextCreate
#define ALLOCSET_DEFAULT_SIZES
#define CHECK_FOR_INTERRUPTS()
static bool is_andclause(const void *clause)
static Datum ExecHashSubPlan(SubPlanState *node, ExprContext *econtext, bool *isNull)
SubPlanState * ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
static void buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
static bool execTuplesUnequal(TupleTableSlot *slot1, TupleTableSlot *slot2, int numCols, AttrNumber *matchColIdx, FmgrInfo *eqfunctions, const Oid *collations, MemoryContext evalContext)
void ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
static bool slotNoNulls(TupleTableSlot *slot)
static Datum ExecScanSubPlan(SubPlanState *node, ExprContext *econtext, bool *isNull)
void ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
void ExecSetParamPlanMulti(const Bitmapset *params, ExprContext *econtext)
static bool slotAllNulls(TupleTableSlot *slot)
Datum ExecSubPlan(SubPlanState *node, ExprContext *econtext, bool *isNull)
static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot, FmgrInfo *eqfunctions)
#define IsA(nodeptr, _type_)
#define castNode(_type_, nodeptr)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
#define lfirst_node(type, lc)
static int list_length(const List *l)
static void * list_nth(const List *list, int n)
static bool DatumGetBool(Datum X)
static Datum PointerGetDatum(const void *X)
static Datum BoolGetDatum(bool X)
static Pointer DatumGetPointer(Datum X)
ParamExecData * es_param_exec_vals
MemoryContext es_query_cxt
ScanDirection es_direction
MemoryContext ecxt_per_tuple_memory
ParamExecData * ecxt_param_exec_vals
MemoryContext ecxt_per_query_memory
TupleTableSlot * resultslot
ExprContext * pi_exprContext
ExprState * lhs_hash_expr
MemoryContext hashtablecxt
ExprContext * innerecontext
FmgrInfo * tab_hash_funcs
ProjectionInfo * projLeft
ProjectionInfo * projRight
TupleTableSlot * tableslot
TupleDesc tts_tupleDescriptor
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
static HeapTuple ExecCopySlotHeapTuple(TupleTableSlot *slot)
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
static bool slot_attisnull(TupleTableSlot *slot, int attnum)