Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

PostgreSQL Source Code git master
nodeSubplan.c File Reference
#include "postgres.h"
#include <math.h>
#include "access/htup_details.h"
#include "executor/executor.h"
#include "executor/nodeSubplan.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "utils/array.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
Include dependency graph for nodeSubplan.c:

Go to the source code of this file.

Functions

static Datum ExecHashSubPlan (SubPlanState *node, ExprContext *econtext, bool *isNull)
 
static Datum ExecScanSubPlan (SubPlanState *node, ExprContext *econtext, bool *isNull)
 
static void buildSubPlanHash (SubPlanState *node, ExprContext *econtext)
 
static bool findPartialMatch (TupleHashTable hashtable, TupleTableSlot *slot, FmgrInfo *eqfunctions)
 
static bool slotAllNulls (TupleTableSlot *slot)
 
static bool slotNoNulls (TupleTableSlot *slot)
 
Datum ExecSubPlan (SubPlanState *node, ExprContext *econtext, bool *isNull)
 
static bool execTuplesUnequal (TupleTableSlot *slot1, TupleTableSlot *slot2, int numCols, AttrNumber *matchColIdx, FmgrInfo *eqfunctions, const Oid *collations, MemoryContext evalContext)
 
SubPlanStateExecInitSubPlan (SubPlan *subplan, PlanState *parent)
 
void ExecSetParamPlan (SubPlanState *node, ExprContext *econtext)
 
void ExecSetParamPlanMulti (const Bitmapset *params, ExprContext *econtext)
 
void ExecReScanSetParamPlan (SubPlanState *node, PlanState *parent)
 

Function Documentation

◆ buildSubPlanHash()

static void buildSubPlanHash ( SubPlanState node,
ExprContext econtext 
)
static

Definition at line 477 of file nodeSubplan.c.

478{
479 SubPlan *subplan = node->subplan;
480 PlanState *planstate = node->planstate;
481 int ncols = node->numCols;
482 ExprContext *innerecontext = node->innerecontext;
483 MemoryContext oldcontext;
484 long nbuckets;
485 TupleTableSlot *slot;
486
487 Assert(subplan->subLinkType == ANY_SUBLINK);
488
489 /*
490 * If we already had any hash tables, reset 'em; otherwise create empty
491 * hash table(s).
492 *
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.)
500 *
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.
503 *
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().
508 */
510 node->havehashrows = false;
511 node->havenullrows = false;
512
513 nbuckets = clamp_cardinality_to_long(planstate->plan->plan_rows);
514 if (nbuckets < 1)
515 nbuckets = 1;
516
517 if (node->hashtable)
519 else
521 node->descRight,
523 ncols,
524 node->keyColIdx,
525 node->tab_eq_funcoids,
526 node->tab_hash_funcs,
527 node->tab_collations,
528 nbuckets,
529 0,
531 node->hashtablecxt,
532 innerecontext->ecxt_per_tuple_memory,
533 false);
534
535 if (!subplan->unknownEqFalse)
536 {
537 if (ncols == 1)
538 nbuckets = 1; /* there can only be one entry */
539 else
540 {
541 nbuckets /= 16;
542 if (nbuckets < 1)
543 nbuckets = 1;
544 }
545
546 if (node->hashnulls)
548 else
550 node->descRight,
552 ncols,
553 node->keyColIdx,
554 node->tab_eq_funcoids,
555 node->tab_hash_funcs,
556 node->tab_collations,
557 nbuckets,
558 0,
560 node->hashtablecxt,
561 innerecontext->ecxt_per_tuple_memory,
562 false);
563 }
564 else
565 node->hashnulls = NULL;
566
567 /*
568 * We are probably in a short-lived expression-evaluation context. Switch
569 * to the per-query context for manipulating the child plan.
570 */
571 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
572
573 /*
574 * Reset subplan to start.
575 */
576 ExecReScan(planstate);
577
578 /*
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.
581 */
582 for (slot = ExecProcNode(planstate);
583 !TupIsNull(slot);
584 slot = ExecProcNode(planstate))
585 {
586 int col = 1;
587 ListCell *plst;
588 bool isnew;
589
590 /*
591 * Load up the Params representing the raw sub-select outputs, then
592 * form the projection tuple to store in the hashtable.
593 */
594 foreach(plst, subplan->paramIds)
595 {
596 int paramid = lfirst_int(plst);
597 ParamExecData *prmdata;
598
599 prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
600 Assert(prmdata->execPlan == NULL);
601 prmdata->value = slot_getattr(slot, col,
602 &(prmdata->isnull));
603 col++;
604 }
605 slot = ExecProject(node->projRight);
606
607 /*
608 * If result contains any nulls, store separately or not at all.
609 */
610 if (slotNoNulls(slot))
611 {
612 (void) LookupTupleHashEntry(node->hashtable, slot, &isnew, NULL);
613 node->havehashrows = true;
614 }
615 else if (node->hashnulls)
616 {
617 (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew, NULL);
618 node->havenullrows = true;
619 }
620
621 /*
622 * Reset innerecontext after each inner tuple to free any memory used
623 * during ExecProject and hashtable lookup.
624 */
625 ResetExprContext(innerecontext);
626 }
627
628 /*
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,
633 * but can't hurt.)
634 */
636
637 MemoryContextSwitchTo(oldcontext);
638}
long clamp_cardinality_to_long(Cardinality x)
Definition: costsize.c:265
void ExecReScan(PlanState *node)
Definition: execAmi.c:77
TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew, uint32 *hash)
Definition: execGrouping.c:301
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)
Definition: execGrouping.c:167
void ResetTupleHashTable(TupleHashTable hashtable)
Definition: execGrouping.c:280
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:84
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:480
#define ResetExprContext(econtext)
Definition: executor.h:647
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:311
Assert(PointerIsAligned(start, uint64))
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:400
static bool slotNoNulls(TupleTableSlot *slot)
Definition: nodeSubplan.c:779
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define lfirst_int(lc)
Definition: pg_list.h:173
@ ANY_SUBLINK
Definition: primnodes.h:1018
MemoryContext es_query_cxt
Definition: execnodes.h:710
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:281
ParamExecData * ecxt_param_exec_vals
Definition: execnodes.h:284
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:280
TupleTableSlot * resultslot
Definition: execnodes.h:104
bool isnull
Definition: params.h:149
Datum value
Definition: params.h:148
void * execPlan
Definition: params.h:147
Plan * plan
Definition: execnodes.h:1159
EState * state
Definition: execnodes.h:1161
Cardinality plan_rows
Definition: plannodes.h:196
ExprState pi_state
Definition: execnodes.h:386
TupleHashTable hashtable
Definition: execnodes.h:1016
PlanState * parent
Definition: execnodes.h:1008
MemoryContext hashtablecxt
Definition: execnodes.h:1020
Oid * tab_eq_funcoids
Definition: execnodes.h:1025
ExprContext * innerecontext
Definition: execnodes.h:1021
FmgrInfo * tab_hash_funcs
Definition: execnodes.h:1028
PlanState * planstate
Definition: execnodes.h:1007
AttrNumber * keyColIdx
Definition: execnodes.h:1024
TupleDesc descRight
Definition: execnodes.h:1013
SubPlan * subplan
Definition: execnodes.h:1006
ProjectionInfo * projRight
Definition: execnodes.h:1015
bool havenullrows
Definition: execnodes.h:1019
Oid * tab_collations
Definition: execnodes.h:1027
TupleHashTable hashnulls
Definition: execnodes.h:1017
bool havehashrows
Definition: execnodes.h:1018
List * paramIds
Definition: primnodes.h:1087
bool unknownEqFalse
Definition: primnodes.h:1100
SubLinkType subLinkType
Definition: primnodes.h:1084
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:399
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:458
#define TupIsNull(slot)
Definition: tuptable.h:310

References ANY_SUBLINK, Assert(), BuildTupleHashTable(), clamp_cardinality_to_long(), SubPlanState::descRight, ExprContext::ecxt_param_exec_vals, ExprContext::ecxt_per_query_memory, ExprContext::ecxt_per_tuple_memory, EState::es_query_cxt, ExecClearTuple(), ParamExecData::execPlan, ExecProcNode(), ExecProject(), ExecReScan(), SubPlanState::hashnulls, SubPlanState::hashtable, SubPlanState::hashtablecxt, SubPlanState::havehashrows, SubPlanState::havenullrows, SubPlanState::innerecontext, ParamExecData::isnull, SubPlanState::keyColIdx, lfirst_int, LookupTupleHashEntry(), MemoryContextReset(), MemoryContextSwitchTo(), SubPlanState::numCols, SubPlan::paramIds, SubPlanState::parent, ProjectionInfo::pi_state, PlanState::plan, Plan::plan_rows, SubPlanState::planstate, SubPlanState::projRight, ResetExprContext, ResetTupleHashTable(), ExprState::resultslot, slot_getattr(), slotNoNulls(), PlanState::state, SubPlan::subLinkType, SubPlanState::subplan, SubPlanState::tab_collations, SubPlanState::tab_eq_funcoids, SubPlanState::tab_hash_funcs, TTSOpsVirtual, TupIsNull, SubPlan::unknownEqFalse, and ParamExecData::value.

Referenced by ExecHashSubPlan().

◆ ExecHashSubPlan()

static Datum ExecHashSubPlan ( SubPlanState node,
ExprContext econtext,
bool *  isNull 
)
static

Definition at line 101 of file nodeSubplan.c.

104{
105 bool result = false;
106 SubPlan *subplan = node->subplan;
107 PlanState *planstate = node->planstate;
108 TupleTableSlot *slot;
109
110 /* Shouldn't have any direct correlation Vars */
111 if (subplan->parParam != NIL || subplan->args != NIL)
112 elog(ERROR, "hashed subplan with direct correlation not supported");
113
114 /*
115 * If first time through or we need to rescan the subplan, build the hash
116 * table.
117 */
118 if (node->hashtable == NULL || planstate->chgParam != NULL)
119 buildSubPlanHash(node, econtext);
120
121 /*
122 * The result for an empty subplan is always FALSE; no need to evaluate
123 * lefthand side.
124 */
125 *isNull = false;
126 if (!node->havehashrows && !node->havenullrows)
127 return BoolGetDatum(false);
128
129 /*
130 * Evaluate lefthand expressions and form a projection tuple. First we
131 * have to set the econtext to use (hack alert!).
132 */
133 node->projLeft->pi_exprContext = econtext;
134 slot = ExecProject(node->projLeft);
135
136 /*
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.
142 *
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.
149 */
150 if (slotNoNulls(slot))
151 {
152 if (node->havehashrows &&
154 slot,
155 node->cur_eq_comp,
156 node->lhs_hash_expr) != NULL)
157 result = true;
158 else if (node->havenullrows &&
159 findPartialMatch(node->hashnulls, slot, node->cur_eq_funcs))
160 *isNull = true;
161 }
162
163 /*
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.
172 */
173 else if (node->hashnulls == NULL)
174 /* just return FALSE */ ;
175 else if (slotAllNulls(slot))
176 *isNull = true;
177 /* Scan partly-null table first, since more likely to get a match */
178 else if (node->havenullrows &&
179 findPartialMatch(node->hashnulls, slot, node->cur_eq_funcs))
180 *isNull = true;
181 else if (node->havehashrows &&
182 findPartialMatch(node->hashtable, slot, node->cur_eq_funcs))
183 *isNull = true;
184
185 /*
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.
191 */
192 ExecClearTuple(slot);
193
194 /* Also must reset the innerecontext after each hashtable lookup. */
196
197 return BoolGetDatum(result);
198}
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
TupleHashEntry FindTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, ExprState *eqcomp, ExprState *hashexpr)
Definition: execGrouping.c:388
static void buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
Definition: nodeSubplan.c:477
static bool slotAllNulls(TupleTableSlot *slot)
Definition: nodeSubplan.c:759
static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot, FmgrInfo *eqfunctions)
Definition: nodeSubplan.c:724
#define NIL
Definition: pg_list.h:68
static Datum BoolGetDatum(bool X)
Definition: postgres.h:112
Bitmapset * chgParam
Definition: execnodes.h:1191
ExprContext * pi_exprContext
Definition: execnodes.h:388
ExprState * lhs_hash_expr
Definition: execnodes.h:1029
ExprState * cur_eq_comp
Definition: execnodes.h:1031
FmgrInfo * cur_eq_funcs
Definition: execnodes.h:1030
ProjectionInfo * projLeft
Definition: execnodes.h:1014
List * args
Definition: primnodes.h:1110
List * parParam
Definition: primnodes.h:1109

References SubPlan::args, BoolGetDatum(), buildSubPlanHash(), PlanState::chgParam, SubPlanState::cur_eq_comp, SubPlanState::cur_eq_funcs, elog, ERROR, ExecClearTuple(), ExecProject(), findPartialMatch(), FindTupleHashEntry(), SubPlanState::hashnulls, SubPlanState::hashtable, SubPlanState::havehashrows, SubPlanState::havenullrows, SubPlanState::innerecontext, SubPlanState::lhs_hash_expr, NIL, SubPlan::parParam, ProjectionInfo::pi_exprContext, SubPlanState::planstate, SubPlanState::projLeft, ResetExprContext, slotAllNulls(), slotNoNulls(), and SubPlanState::subplan.

Referenced by ExecSubPlan().

◆ ExecInitSubPlan()

SubPlanState * ExecInitSubPlan ( SubPlan subplan,
PlanState parent 
)

Definition at line 807 of file nodeSubplan.c.

808{
810 EState *estate = parent->state;
811
812 sstate->subplan = subplan;
813
814 /* Link the SubPlanState to already-initialized subplan */
815 sstate->planstate = (PlanState *) list_nth(estate->es_subplanstates,
816 subplan->plan_id - 1);
817
818 /*
819 * This check can fail if the planner mistakenly puts a parallel-unsafe
820 * subplan into a parallelized subquery; see ExecSerializePlan.
821 */
822 if (sstate->planstate == NULL)
823 elog(ERROR, "subplan \"%s\" was not initialized",
824 subplan->plan_name);
825
826 /* Link to parent's state, too */
827 sstate->parent = parent;
828
829 /* Initialize subexpressions */
830 sstate->testexpr = ExecInitExpr((Expr *) subplan->testexpr, parent);
831
832 /*
833 * initialize my state
834 */
835 sstate->curTuple = NULL;
836 sstate->curArray = PointerGetDatum(NULL);
837 sstate->projLeft = NULL;
838 sstate->projRight = NULL;
839 sstate->hashtable = NULL;
840 sstate->hashnulls = NULL;
841 sstate->hashtablecxt = NULL;
842 sstate->innerecontext = NULL;
843 sstate->keyColIdx = NULL;
844 sstate->tab_eq_funcoids = NULL;
845 sstate->tab_hash_funcs = NULL;
846 sstate->tab_collations = NULL;
847 sstate->cur_eq_funcs = NULL;
848
849 /*
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.
853 *
854 * A CTE subplan's output parameter is never to be evaluated in the normal
855 * way, so skip this in that case.
856 *
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.
859 */
860 if (subplan->setParam != NIL && subplan->parParam == NIL &&
861 subplan->subLinkType != CTE_SUBLINK)
862 {
863 ListCell *lst;
864
865 foreach(lst, subplan->setParam)
866 {
867 int paramid = lfirst_int(lst);
868 ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
869
870 prm->execPlan = sstate;
871 }
872 }
873
874 /*
875 * If we are going to hash the subquery output, initialize relevant stuff.
876 * (We don't create the hashtable until needed, though.)
877 */
878 if (subplan->useHashTable)
879 {
880 int ncols,
881 i;
882 TupleDesc tupDescLeft;
883 TupleDesc tupDescRight;
884 Oid *cross_eq_funcoids;
885 TupleTableSlot *slot;
886 FmgrInfo *lhs_hash_funcs;
887 List *oplist,
888 *lefttlist,
889 *righttlist;
890 ListCell *l;
891
892 /* We need a memory context to hold the hash table(s) */
893 sstate->hashtablecxt =
895 "Subplan HashTable Context",
897 /* and a short-lived exprcontext for function evaluation */
898 sstate->innerecontext = CreateExprContext(estate);
899
900 /*
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
908 * righthand sides.
909 *
910 * We also extract the combining operators themselves to initialize
911 * the equality and hashing functions for the hash tables.
912 */
913 if (IsA(subplan->testexpr, OpExpr))
914 {
915 /* single combining operator */
916 oplist = list_make1(subplan->testexpr);
917 }
918 else if (is_andclause(subplan->testexpr))
919 {
920 /* multiple combining operators */
921 oplist = castNode(BoolExpr, subplan->testexpr)->args;
922 }
923 else
924 {
925 /* shouldn't see anything else in a hashable subplan */
926 elog(ERROR, "unrecognized testexpr type: %d",
927 (int) nodeTag(subplan->testexpr));
928 oplist = NIL; /* keep compiler quiet */
929 }
930 ncols = list_length(oplist);
931
932 lefttlist = righttlist = NIL;
933 sstate->numCols = ncols;
934 sstate->keyColIdx = (AttrNumber *) palloc(ncols * sizeof(AttrNumber));
935 sstate->tab_eq_funcoids = (Oid *) palloc(ncols * sizeof(Oid));
936 sstate->tab_collations = (Oid *) palloc(ncols * sizeof(Oid));
937 sstate->tab_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
938 lhs_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
939 sstate->cur_eq_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
940 /* we'll need the cross-type equality fns below, but not in sstate */
941 cross_eq_funcoids = (Oid *) palloc(ncols * sizeof(Oid));
942
943 i = 1;
944 foreach(l, oplist)
945 {
946 OpExpr *opexpr = lfirst_node(OpExpr, l);
947 Expr *expr;
948 TargetEntry *tle;
949 Oid rhs_eq_oper;
950 Oid left_hashfn;
951 Oid right_hashfn;
952
953 Assert(list_length(opexpr->args) == 2);
954
955 /* Process lefthand argument */
956 expr = (Expr *) linitial(opexpr->args);
957 tle = makeTargetEntry(expr,
958 i,
959 NULL,
960 false);
961 lefttlist = lappend(lefttlist, tle);
962
963 /* Process righthand argument */
964 expr = (Expr *) lsecond(opexpr->args);
965 tle = makeTargetEntry(expr,
966 i,
967 NULL,
968 false);
969 righttlist = lappend(righttlist, tle);
970
971 /* Lookup the equality function (potentially cross-type) */
972 cross_eq_funcoids[i - 1] = opexpr->opfuncid;
973 fmgr_info(opexpr->opfuncid, &sstate->cur_eq_funcs[i - 1]);
974 fmgr_info_set_expr((Node *) opexpr, &sstate->cur_eq_funcs[i - 1]);
975
976 /* Look up the equality function for the RHS type */
978 NULL, &rhs_eq_oper))
979 elog(ERROR, "could not find compatible hash operator for operator %u",
980 opexpr->opno);
981 sstate->tab_eq_funcoids[i - 1] = get_opcode(rhs_eq_oper);
982
983 /* Lookup the associated hash functions */
984 if (!get_op_hash_functions(opexpr->opno,
985 &left_hashfn, &right_hashfn))
986 elog(ERROR, "could not find hash function for hash operator %u",
987 opexpr->opno);
988 fmgr_info(left_hashfn, &lhs_hash_funcs[i - 1]);
989 fmgr_info(right_hashfn, &sstate->tab_hash_funcs[i - 1]);
990
991 /* Set collation */
992 sstate->tab_collations[i - 1] = opexpr->inputcollid;
993
994 /* keyColIdx is just column numbers 1..n */
995 sstate->keyColIdx[i - 1] = i;
996
997 i++;
998 }
999
1000 /*
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.
1007 */
1008 tupDescLeft = ExecTypeFromTL(lefttlist);
1009 slot = ExecInitExtraTupleSlot(estate, tupDescLeft, &TTSOpsVirtual);
1010 sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
1011 NULL,
1012 slot,
1013 parent,
1014 NULL);
1015
1016 sstate->descRight = tupDescRight = ExecTypeFromTL(righttlist);
1017 slot = ExecInitExtraTupleSlot(estate, tupDescRight, &TTSOpsVirtual);
1018 sstate->projRight = ExecBuildProjectionInfo(righttlist,
1019 sstate->innerecontext,
1020 slot,
1021 sstate->planstate,
1022 NULL);
1023
1024 /* Build the ExprState for generating hash values */
1025 sstate->lhs_hash_expr = ExecBuildHash32FromAttrs(tupDescLeft,
1027 lhs_hash_funcs,
1028 sstate->tab_collations,
1029 sstate->numCols,
1030 sstate->keyColIdx,
1031 parent,
1032 0);
1033
1034 /*
1035 * Create comparator for lookups of rows in the table (potentially
1036 * cross-type comparisons).
1037 */
1038 sstate->cur_eq_comp = ExecBuildGroupingEqual(tupDescLeft, tupDescRight,
1040 ncols,
1041 sstate->keyColIdx,
1042 cross_eq_funcoids,
1043 sstate->tab_collations,
1044 parent);
1045 }
1046
1047 return sstate;
1048}
int16 AttrNumber
Definition: attnum.h:21
ExprState * ExecBuildHash32FromAttrs(TupleDesc desc, const TupleTableSlotOps *ops, FmgrInfo *hashfunctions, Oid *collations, int numCols, AttrNumber *keyColIdx, PlanState *parent, uint32 init_value)
Definition: execExpr.c:4141
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:143
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
Definition: execExpr.c:370
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: execExpr.c:4465
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:2020
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:86
TupleDesc ExecTypeFromTL(List *targetList)
Definition: execTuples.c:2127
ExprContext * CreateExprContext(EState *estate)
Definition: execUtils.c:307
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
int i
Definition: isn.c:77
List * lappend(List *list, void *datum)
Definition: list.c:339
bool get_compatible_hash_operators(Oid opno, Oid *lhs_opno, Oid *rhs_opno)
Definition: lsyscache.c:482
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1452
bool get_op_hash_functions(Oid opno, RegProcedure *lhs_procno, RegProcedure *rhs_procno)
Definition: lsyscache.c:582
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:289
void * palloc(Size size)
Definition: mcxt.c:1365
MemoryContext CurrentMemoryContext
Definition: mcxt.c:160
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
static bool is_andclause(const void *clause)
Definition: nodeFuncs.h:107
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define nodeTag(nodeptr)
Definition: nodes.h:139
#define makeNode(_type_)
Definition: nodes.h:161
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
#define list_make1(x1)
Definition: pg_list.h:212
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
#define linitial(l)
Definition: pg_list.h:178
#define lsecond(l)
Definition: pg_list.h:183
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:332
unsigned int Oid
Definition: postgres_ext.h:32
@ CTE_SUBLINK
Definition: primnodes.h:1023
ParamExecData * es_param_exec_vals
Definition: execnodes.h:705
List * es_subplanstates
Definition: execnodes.h:725
Definition: fmgr.h:57
Definition: pg_list.h:54
Definition: nodes.h:135
Oid opno
Definition: primnodes.h:837
List * args
Definition: primnodes.h:855
HeapTuple curTuple
Definition: execnodes.h:1010
ExprState * testexpr
Definition: execnodes.h:1009
Datum curArray
Definition: execnodes.h:1011
int plan_id
Definition: primnodes.h:1089
char * plan_name
Definition: primnodes.h:1091
bool useHashTable
Definition: primnodes.h:1098
Node * testexpr
Definition: primnodes.h:1086
List * setParam
Definition: primnodes.h:1107

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, OpExpr::args, Assert(), castNode, CreateExprContext(), CTE_SUBLINK, SubPlanState::cur_eq_comp, SubPlanState::cur_eq_funcs, SubPlanState::curArray, CurrentMemoryContext, SubPlanState::curTuple, SubPlanState::descRight, elog, ERROR, EState::es_param_exec_vals, EState::es_subplanstates, ExecBuildGroupingEqual(), ExecBuildHash32FromAttrs(), ExecBuildProjectionInfo(), ExecInitExpr(), ExecInitExtraTupleSlot(), ParamExecData::execPlan, ExecTypeFromTL(), fmgr_info(), fmgr_info_set_expr, get_compatible_hash_operators(), get_op_hash_functions(), get_opcode(), SubPlanState::hashnulls, SubPlanState::hashtable, SubPlanState::hashtablecxt, i, SubPlanState::innerecontext, is_andclause(), IsA, SubPlanState::keyColIdx, lappend(), lfirst_int, lfirst_node, SubPlanState::lhs_hash_expr, linitial, list_length(), list_make1, list_nth(), lsecond, makeNode, makeTargetEntry(), NIL, nodeTag, SubPlanState::numCols, OpExpr::opno, palloc(), SubPlanState::parent, SubPlan::parParam, SubPlan::plan_id, SubPlan::plan_name, SubPlanState::planstate, PointerGetDatum(), SubPlanState::projLeft, SubPlanState::projRight, SubPlan::setParam, PlanState::state, SubPlan::subLinkType, SubPlanState::subplan, SubPlanState::tab_collations, SubPlanState::tab_eq_funcoids, SubPlanState::tab_hash_funcs, SubPlanState::testexpr, SubPlan::testexpr, TTSOpsMinimalTuple, TTSOpsVirtual, and SubPlan::useHashTable.

Referenced by ExecInitNode(), and ExecInitSubPlanExpr().

◆ ExecReScanSetParamPlan()

void ExecReScanSetParamPlan ( SubPlanState node,
PlanState parent 
)

Definition at line 1274 of file nodeSubplan.c.

1275{
1276 PlanState *planstate = node->planstate;
1277 SubPlan *subplan = node->subplan;
1278 EState *estate = parent->state;
1279 ListCell *l;
1280
1281 /* sanity checks */
1282 if (subplan->parParam != NIL)
1283 elog(ERROR, "direct correlated subquery unsupported as initplan");
1284 if (subplan->setParam == NIL)
1285 elog(ERROR, "setParam list of initplan is empty");
1286 if (bms_is_empty(planstate->plan->extParam))
1287 elog(ERROR, "extParam set of initplan is empty");
1288
1289 /*
1290 * Don't actually re-scan: it'll happen inside ExecSetParamPlan if needed.
1291 */
1292
1293 /*
1294 * Mark this subplan's output parameters as needing recalculation.
1295 *
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.
1300 */
1301 foreach(l, subplan->setParam)
1302 {
1303 int paramid = lfirst_int(l);
1304 ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
1305
1306 if (subplan->subLinkType != CTE_SUBLINK)
1307 prm->execPlan = node;
1308
1309 parent->chgParam = bms_add_member(parent->chgParam, paramid);
1310 }
1311}
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
#define bms_is_empty(a)
Definition: bitmapset.h:118
Bitmapset * extParam
Definition: plannodes.h:240

References bms_add_member(), bms_is_empty, PlanState::chgParam, CTE_SUBLINK, elog, ERROR, EState::es_param_exec_vals, ParamExecData::execPlan, Plan::extParam, lfirst_int, NIL, SubPlan::parParam, PlanState::plan, SubPlanState::planstate, SubPlan::setParam, PlanState::state, SubPlan::subLinkType, and SubPlanState::subplan.

Referenced by ExecReScan().

◆ ExecScanSubPlan()

static Datum ExecScanSubPlan ( SubPlanState node,
ExprContext econtext,
bool *  isNull 
)
static

Definition at line 204 of file nodeSubplan.c.

207{
208 SubPlan *subplan = node->subplan;
209 PlanState *planstate = node->planstate;
210 SubLinkType subLinkType = subplan->subLinkType;
211 MemoryContext oldcontext;
212 TupleTableSlot *slot;
213 Datum result;
214 bool found = false; /* true if got at least one subplan tuple */
215 ListCell *l;
216 ArrayBuildStateAny *astate = NULL;
217
218 /* Initialize ArrayBuildStateAny in caller's context, if needed */
219 if (subLinkType == ARRAY_SUBLINK)
220 astate = initArrayResultAny(subplan->firstColType,
222
223 /*
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.
227 */
228 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
229
230 /*
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.
235 */
236 foreach(l, subplan->parParam)
237 {
238 int paramid = lfirst_int(l);
239
240 planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
241 }
242
243 /* with that done, we can reset the subplan */
244 ExecReScan(planstate);
245
246 /*
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.
256 *
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).
261 *
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.
266 *
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).
271 */
272 result = BoolGetDatum(subLinkType == ALL_SUBLINK);
273 *isNull = false;
274
275 for (slot = ExecProcNode(planstate);
276 !TupIsNull(slot);
277 slot = ExecProcNode(planstate))
278 {
279 TupleDesc tdesc = slot->tts_tupleDescriptor;
280 Datum rowresult;
281 bool rownull;
282 int col;
283 ListCell *plst;
284
285 if (subLinkType == EXISTS_SUBLINK)
286 {
287 found = true;
288 result = BoolGetDatum(true);
289 break;
290 }
291
292 if (subLinkType == EXPR_SUBLINK)
293 {
294 /* cannot allow multiple input tuples for EXPR sublink */
295 if (found)
297 (errcode(ERRCODE_CARDINALITY_VIOLATION),
298 errmsg("more than one row returned by a subquery used as an expression")));
299 found = true;
300
301 /*
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
307 * freeing.
308 */
309 if (node->curTuple)
311 node->curTuple = ExecCopySlotHeapTuple(slot);
312
313 result = heap_getattr(node->curTuple, 1, tdesc, isNull);
314 /* keep scanning subplan to make sure there's only one tuple */
315 continue;
316 }
317
318 if (subLinkType == MULTIEXPR_SUBLINK)
319 {
320 /* cannot allow multiple input tuples for MULTIEXPR sublink */
321 if (found)
323 (errcode(ERRCODE_CARDINALITY_VIOLATION),
324 errmsg("more than one row returned by a subquery used as an expression")));
325 found = true;
326
327 /*
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
333 * freeing.
334 */
335 if (node->curTuple)
337 node->curTuple = ExecCopySlotHeapTuple(slot);
338
339 /*
340 * Now set all the setParam params from the columns of the tuple
341 */
342 col = 1;
343 foreach(plst, subplan->setParam)
344 {
345 int paramid = lfirst_int(plst);
346 ParamExecData *prmdata;
347
348 prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
349 Assert(prmdata->execPlan == NULL);
350 prmdata->value = heap_getattr(node->curTuple, col, tdesc,
351 &(prmdata->isnull));
352 col++;
353 }
354
355 /* keep scanning subplan to make sure there's only one tuple */
356 continue;
357 }
358
359 if (subLinkType == ARRAY_SUBLINK)
360 {
361 Datum dvalue;
362 bool disnull;
363
364 found = true;
365 /* stash away current value */
366 Assert(subplan->firstColType == TupleDescAttr(tdesc, 0)->atttypid);
367 dvalue = slot_getattr(slot, 1, &disnull);
368 astate = accumArrayResultAny(astate, dvalue, disnull,
369 subplan->firstColType, oldcontext);
370 /* keep scanning subplan to collect all values */
371 continue;
372 }
373
374 /* cannot allow multiple input tuples for ROWCOMPARE sublink either */
375 if (subLinkType == ROWCOMPARE_SUBLINK && found)
377 (errcode(ERRCODE_CARDINALITY_VIOLATION),
378 errmsg("more than one row returned by a subquery used as an expression")));
379
380 found = true;
381
382 /*
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.
386 */
387 col = 1;
388 foreach(plst, subplan->paramIds)
389 {
390 int paramid = lfirst_int(plst);
391 ParamExecData *prmdata;
392
393 prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
394 Assert(prmdata->execPlan == NULL);
395 prmdata->value = slot_getattr(slot, col, &(prmdata->isnull));
396 col++;
397 }
398
399 rowresult = ExecEvalExprSwitchContext(node->testexpr, econtext,
400 &rownull);
401
402 if (subLinkType == ANY_SUBLINK)
403 {
404 /* combine across rows per OR semantics */
405 if (rownull)
406 *isNull = true;
407 else if (DatumGetBool(rowresult))
408 {
409 result = BoolGetDatum(true);
410 *isNull = false;
411 break; /* needn't look at any more rows */
412 }
413 }
414 else if (subLinkType == ALL_SUBLINK)
415 {
416 /* combine across rows per AND semantics */
417 if (rownull)
418 *isNull = true;
419 else if (!DatumGetBool(rowresult))
420 {
421 result = BoolGetDatum(false);
422 *isNull = false;
423 break; /* needn't look at any more rows */
424 }
425 }
426 else
427 {
428 /* must be ROWCOMPARE_SUBLINK */
429 result = rowresult;
430 *isNull = rownull;
431 }
432 }
433
434 MemoryContextSwitchTo(oldcontext);
435
436 if (subLinkType == ARRAY_SUBLINK)
437 {
438 /* We return the result in the caller's context */
439 result = makeArrayResultAny(astate, oldcontext, true);
440 }
441 else if (!found)
442 {
443 /*
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.
447 */
448 if (subLinkType == EXPR_SUBLINK ||
449 subLinkType == ROWCOMPARE_SUBLINK)
450 {
451 result = (Datum) 0;
452 *isNull = true;
453 }
454 else if (subLinkType == MULTIEXPR_SUBLINK)
455 {
456 /* We don't care about function result, but set the setParams */
457 foreach(l, subplan->setParam)
458 {
459 int paramid = lfirst_int(l);
460 ParamExecData *prmdata;
461
462 prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
463 Assert(prmdata->execPlan == NULL);
464 prmdata->value = (Datum) 0;
465 prmdata->isnull = true;
466 }
467 }
468 }
469
470 return result;
471}
ArrayBuildStateAny * initArrayResultAny(Oid input_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5782
ArrayBuildStateAny * accumArrayResultAny(ArrayBuildStateAny *astate, Datum dvalue, bool disnull, Oid input_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5829
Datum makeArrayResultAny(ArrayBuildStateAny *astate, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5857
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ereport(elevel,...)
Definition: elog.h:150
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:433
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:904
static bool DatumGetBool(Datum X)
Definition: postgres.h:100
uint64_t Datum
Definition: postgres.h:70
SubLinkType
Definition: primnodes.h:1015
@ ARRAY_SUBLINK
Definition: primnodes.h:1022
@ MULTIEXPR_SUBLINK
Definition: primnodes.h:1021
@ EXPR_SUBLINK
Definition: primnodes.h:1020
@ ROWCOMPARE_SUBLINK
Definition: primnodes.h:1019
@ ALL_SUBLINK
Definition: primnodes.h:1017
@ EXISTS_SUBLINK
Definition: primnodes.h:1016
Oid firstColType
Definition: primnodes.h:1093
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:123
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160
static HeapTuple ExecCopySlotHeapTuple(TupleTableSlot *slot)
Definition: tuptable.h:485

References accumArrayResultAny(), ALL_SUBLINK, ANY_SUBLINK, ARRAY_SUBLINK, Assert(), bms_add_member(), BoolGetDatum(), PlanState::chgParam, CurrentMemoryContext, SubPlanState::curTuple, DatumGetBool(), ExprContext::ecxt_param_exec_vals, ExprContext::ecxt_per_query_memory, ereport, errcode(), errmsg(), ERROR, ExecCopySlotHeapTuple(), ExecEvalExprSwitchContext(), ParamExecData::execPlan, ExecProcNode(), ExecReScan(), EXISTS_SUBLINK, EXPR_SUBLINK, SubPlan::firstColType, heap_freetuple(), heap_getattr(), initArrayResultAny(), ParamExecData::isnull, lfirst_int, makeArrayResultAny(), MemoryContextSwitchTo(), MULTIEXPR_SUBLINK, SubPlan::paramIds, SubPlan::parParam, SubPlanState::planstate, ROWCOMPARE_SUBLINK, SubPlan::setParam, slot_getattr(), SubPlan::subLinkType, SubPlanState::subplan, SubPlanState::testexpr, TupleTableSlot::tts_tupleDescriptor, TupIsNull, TupleDescAttr(), and ParamExecData::value.

Referenced by ExecSubPlan().

◆ ExecSetParamPlan()

void ExecSetParamPlan ( SubPlanState node,
ExprContext econtext 
)

Definition at line 1075 of file nodeSubplan.c.

1076{
1077 SubPlan *subplan = node->subplan;
1078 PlanState *planstate = node->planstate;
1079 SubLinkType subLinkType = subplan->subLinkType;
1080 EState *estate = planstate->state;
1081 ScanDirection dir = estate->es_direction;
1082 MemoryContext oldcontext;
1083 TupleTableSlot *slot;
1084 ListCell *l;
1085 bool found = false;
1086 ArrayBuildStateAny *astate = NULL;
1087
1088 if (subLinkType == ANY_SUBLINK ||
1089 subLinkType == ALL_SUBLINK)
1090 elog(ERROR, "ANY/ALL subselect unsupported as initplan");
1091 if (subLinkType == CTE_SUBLINK)
1092 elog(ERROR, "CTE subplans should not be executed via ExecSetParamPlan");
1093 if (subplan->parParam || subplan->args)
1094 elog(ERROR, "correlated subplans should not be executed via ExecSetParamPlan");
1095
1096 /*
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.
1099 */
1101
1102 /* Initialize ArrayBuildStateAny in caller's context, if needed */
1103 if (subLinkType == ARRAY_SUBLINK)
1104 astate = initArrayResultAny(subplan->firstColType,
1105 CurrentMemoryContext, true);
1106
1107 /*
1108 * Must switch to per-query memory context.
1109 */
1110 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
1111
1112 /*
1113 * Run the plan. (If it needs to be rescanned, the first ExecProcNode
1114 * call will take care of that.)
1115 */
1116 for (slot = ExecProcNode(planstate);
1117 !TupIsNull(slot);
1118 slot = ExecProcNode(planstate))
1119 {
1120 TupleDesc tdesc = slot->tts_tupleDescriptor;
1121 int i = 1;
1122
1123 if (subLinkType == EXISTS_SUBLINK)
1124 {
1125 /* There can be only one setParam... */
1126 int paramid = linitial_int(subplan->setParam);
1127 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1128
1129 prm->execPlan = NULL;
1130 prm->value = BoolGetDatum(true);
1131 prm->isnull = false;
1132 found = true;
1133 break;
1134 }
1135
1136 if (subLinkType == ARRAY_SUBLINK)
1137 {
1138 Datum dvalue;
1139 bool disnull;
1140
1141 found = true;
1142 /* stash away current value */
1143 Assert(subplan->firstColType == TupleDescAttr(tdesc, 0)->atttypid);
1144 dvalue = slot_getattr(slot, 1, &disnull);
1145 astate = accumArrayResultAny(astate, dvalue, disnull,
1146 subplan->firstColType, oldcontext);
1147 /* keep scanning subplan to collect all values */
1148 continue;
1149 }
1150
1151 if (found &&
1152 (subLinkType == EXPR_SUBLINK ||
1153 subLinkType == MULTIEXPR_SUBLINK ||
1154 subLinkType == ROWCOMPARE_SUBLINK))
1155 ereport(ERROR,
1156 (errcode(ERRCODE_CARDINALITY_VIOLATION),
1157 errmsg("more than one row returned by a subquery used as an expression")));
1158
1159 found = true;
1160
1161 /*
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.
1166 */
1167 if (node->curTuple)
1168 heap_freetuple(node->curTuple);
1169 node->curTuple = ExecCopySlotHeapTuple(slot);
1170
1171 /*
1172 * Now set all the setParam params from the columns of the tuple
1173 */
1174 foreach(l, subplan->setParam)
1175 {
1176 int paramid = lfirst_int(l);
1177 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1178
1179 prm->execPlan = NULL;
1180 prm->value = heap_getattr(node->curTuple, i, tdesc,
1181 &(prm->isnull));
1182 i++;
1183 }
1184 }
1185
1186 if (subLinkType == ARRAY_SUBLINK)
1187 {
1188 /* There can be only one setParam... */
1189 int paramid = linitial_int(subplan->setParam);
1190 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1191
1192 /*
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.
1196 */
1197 if (node->curArray != PointerGetDatum(NULL))
1199 node->curArray = makeArrayResultAny(astate,
1200 econtext->ecxt_per_query_memory,
1201 true);
1202 prm->execPlan = NULL;
1203 prm->value = node->curArray;
1204 prm->isnull = false;
1205 }
1206 else if (!found)
1207 {
1208 if (subLinkType == EXISTS_SUBLINK)
1209 {
1210 /* There can be only one setParam... */
1211 int paramid = linitial_int(subplan->setParam);
1212 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1213
1214 prm->execPlan = NULL;
1215 prm->value = BoolGetDatum(false);
1216 prm->isnull = false;
1217 }
1218 else
1219 {
1220 /* For other sublink types, set all the output params to NULL */
1221 foreach(l, subplan->setParam)
1222 {
1223 int paramid = lfirst_int(l);
1224 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1225
1226 prm->execPlan = NULL;
1227 prm->value = (Datum) 0;
1228 prm->isnull = true;
1229 }
1230 }
1231 }
1232
1233 MemoryContextSwitchTo(oldcontext);
1234
1235 /* restore scan direction */
1236 estate->es_direction = dir;
1237}
void pfree(void *pointer)
Definition: mcxt.c:1594
#define linitial_int(l)
Definition: pg_list.h:179
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:322
ScanDirection
Definition: sdir.h:25
@ ForwardScanDirection
Definition: sdir.h:28
ScanDirection es_direction
Definition: execnodes.h:659

References accumArrayResultAny(), ALL_SUBLINK, ANY_SUBLINK, SubPlan::args, ARRAY_SUBLINK, Assert(), BoolGetDatum(), CTE_SUBLINK, SubPlanState::curArray, CurrentMemoryContext, SubPlanState::curTuple, DatumGetPointer(), ExprContext::ecxt_param_exec_vals, ExprContext::ecxt_per_query_memory, elog, ereport, errcode(), errmsg(), ERROR, EState::es_direction, ExecCopySlotHeapTuple(), ParamExecData::execPlan, ExecProcNode(), EXISTS_SUBLINK, EXPR_SUBLINK, SubPlan::firstColType, ForwardScanDirection, heap_freetuple(), heap_getattr(), i, initArrayResultAny(), ParamExecData::isnull, lfirst_int, linitial_int, makeArrayResultAny(), MemoryContextSwitchTo(), MULTIEXPR_SUBLINK, SubPlan::parParam, pfree(), SubPlanState::planstate, PointerGetDatum(), ROWCOMPARE_SUBLINK, SubPlan::setParam, slot_getattr(), PlanState::state, SubPlan::subLinkType, SubPlanState::subplan, TupleTableSlot::tts_tupleDescriptor, TupIsNull, TupleDescAttr(), and ParamExecData::value.

Referenced by ExecEvalParamExec(), and ExecSetParamPlanMulti().

◆ ExecSetParamPlanMulti()

void ExecSetParamPlanMulti ( const Bitmapset params,
ExprContext econtext 
)

Definition at line 1251 of file nodeSubplan.c.

1252{
1253 int paramid;
1254
1255 paramid = -1;
1256 while ((paramid = bms_next_member(params, paramid)) >= 0)
1257 {
1258 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1259
1260 if (prm->execPlan != NULL)
1261 {
1262 /* Parameter not evaluated yet, so go do it */
1263 ExecSetParamPlan(prm->execPlan, econtext);
1264 /* ExecSetParamPlan should have processed this param... */
1265 Assert(prm->execPlan == NULL);
1266 }
1267 }
1268}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
void ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
Definition: nodeSubplan.c:1075

References Assert(), bms_next_member(), ExprContext::ecxt_param_exec_vals, ParamExecData::execPlan, and ExecSetParamPlan().

Referenced by EvalPlanQualBegin(), EvalPlanQualStart(), ExecInitParallelPlan(), and ExecParallelReinitialize().

◆ ExecSubPlan()

Datum ExecSubPlan ( SubPlanState node,
ExprContext econtext,
bool *  isNull 
)

Definition at line 62 of file nodeSubplan.c.

65{
66 SubPlan *subplan = node->subplan;
67 EState *estate = node->planstate->state;
68 ScanDirection dir = estate->es_direction;
69 Datum retval;
70
72
73 /* Set non-null as default */
74 *isNull = false;
75
76 /* Sanity checks */
77 if (subplan->subLinkType == CTE_SUBLINK)
78 elog(ERROR, "CTE subplans should not be executed via ExecSubPlan");
79 if (subplan->setParam != NIL && subplan->subLinkType != MULTIEXPR_SUBLINK)
80 elog(ERROR, "cannot set parent params from subquery");
81
82 /* Force forward-scan mode for evaluation */
84
85 /* Select appropriate evaluation strategy */
86 if (subplan->useHashTable)
87 retval = ExecHashSubPlan(node, econtext, isNull);
88 else
89 retval = ExecScanSubPlan(node, econtext, isNull);
90
91 /* restore scan direction */
92 estate->es_direction = dir;
93
94 return retval;
95}
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
static Datum ExecHashSubPlan(SubPlanState *node, ExprContext *econtext, bool *isNull)
Definition: nodeSubplan.c:101
static Datum ExecScanSubPlan(SubPlanState *node, ExprContext *econtext, bool *isNull)
Definition: nodeSubplan.c:204

References CHECK_FOR_INTERRUPTS, CTE_SUBLINK, elog, ERROR, EState::es_direction, ExecHashSubPlan(), ExecScanSubPlan(), ForwardScanDirection, MULTIEXPR_SUBLINK, NIL, SubPlanState::planstate, SubPlan::setParam, PlanState::state, SubPlan::subLinkType, SubPlanState::subplan, and SubPlan::useHashTable.

Referenced by ExecEvalSubPlan().

◆ execTuplesUnequal()

static bool execTuplesUnequal ( TupleTableSlot slot1,
TupleTableSlot slot2,
int  numCols,
AttrNumber matchColIdx,
FmgrInfo eqfunctions,
const Oid collations,
MemoryContext  evalContext 
)
static

Definition at line 655 of file nodeSubplan.c.

662{
663 MemoryContext oldContext;
664 bool result;
665 int i;
666
667 /* Reset and switch into the temp context. */
668 MemoryContextReset(evalContext);
669 oldContext = MemoryContextSwitchTo(evalContext);
670
671 /*
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.
676 */
677 result = false;
678
679 for (i = numCols; --i >= 0;)
680 {
681 AttrNumber att = matchColIdx[i];
682 Datum attr1,
683 attr2;
684 bool isNull1,
685 isNull2;
686
687 attr1 = slot_getattr(slot1, att, &isNull1);
688
689 if (isNull1)
690 continue; /* can't prove anything here */
691
692 attr2 = slot_getattr(slot2, att, &isNull2);
693
694 if (isNull2)
695 continue; /* can't prove anything here */
696
697 /* Apply the type-specific equality function */
698 if (!DatumGetBool(FunctionCall2Coll(&eqfunctions[i],
699 collations[i],
700 attr1, attr2)))
701 {
702 result = true; /* they are unequal */
703 break;
704 }
705 }
706
707 MemoryContextSwitchTo(oldContext);
708
709 return result;
710}
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1149

References DatumGetBool(), FunctionCall2Coll(), i, MemoryContextReset(), MemoryContextSwitchTo(), and slot_getattr().

Referenced by findPartialMatch().

◆ findPartialMatch()

static bool findPartialMatch ( TupleHashTable  hashtable,
TupleTableSlot slot,
FmgrInfo eqfunctions 
)
static

Definition at line 724 of file nodeSubplan.c.

726{
727 int numCols = hashtable->numCols;
728 AttrNumber *keyColIdx = hashtable->keyColIdx;
729 TupleHashIterator hashiter;
730 TupleHashEntry entry;
731
732 InitTupleHashIterator(hashtable, &hashiter);
733 while ((entry = ScanTupleHashTable(hashtable, &hashiter)) != NULL)
734 {
736
737 ExecStoreMinimalTuple(TupleHashEntryGetTuple(entry), hashtable->tableslot, false);
738 if (!execTuplesUnequal(slot, hashtable->tableslot,
739 numCols, keyColIdx,
740 eqfunctions,
741 hashtable->tab_collations,
742 hashtable->tempcxt))
743 {
744 TermTupleHashIterator(&hashiter);
745 return true;
746 }
747 }
748 /* No TermTupleHashIterator call needed here */
749 return false;
750}
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1635
#define ScanTupleHashTable(htable, iter)
Definition: execnodes.h:894
#define TermTupleHashIterator(iter)
Definition: execnodes.h:890
#define InitTupleHashIterator(htable, iter)
Definition: execnodes.h:888
tuplehash_iterator TupleHashIterator
Definition: execnodes.h:881
static MinimalTuple TupleHashEntryGetTuple(TupleHashEntry entry)
Definition: executor.h:175
static bool execTuplesUnequal(TupleTableSlot *slot1, TupleTableSlot *slot2, int numCols, AttrNumber *matchColIdx, FmgrInfo *eqfunctions, const Oid *collations, MemoryContext evalContext)
Definition: nodeSubplan.c:655
AttrNumber * keyColIdx
Definition: execnodes.h:866
MemoryContext tempcxt
Definition: execnodes.h:871
TupleTableSlot * tableslot
Definition: execnodes.h:873

References CHECK_FOR_INTERRUPTS, ExecStoreMinimalTuple(), execTuplesUnequal(), InitTupleHashIterator, TupleHashTableData::keyColIdx, TupleHashTableData::numCols, ScanTupleHashTable, TupleHashTableData::tab_collations, TupleHashTableData::tableslot, TupleHashTableData::tempcxt, TermTupleHashIterator, and TupleHashEntryGetTuple().

Referenced by ExecHashSubPlan().

◆ slotAllNulls()

static bool slotAllNulls ( TupleTableSlot slot)
static

Definition at line 759 of file nodeSubplan.c.

760{
761 int ncols = slot->tts_tupleDescriptor->natts;
762 int i;
763
764 for (i = 1; i <= ncols; i++)
765 {
766 if (!slot_attisnull(slot, i))
767 return false;
768 }
769 return true;
770}
static bool slot_attisnull(TupleTableSlot *slot, int attnum)
Definition: tuptable.h:385

References i, TupleDescData::natts, slot_attisnull(), and TupleTableSlot::tts_tupleDescriptor.

Referenced by ExecHashSubPlan().

◆ slotNoNulls()

static bool slotNoNulls ( TupleTableSlot slot)
static

Definition at line 779 of file nodeSubplan.c.

780{
781 int ncols = slot->tts_tupleDescriptor->natts;
782 int i;
783
784 for (i = 1; i <= ncols; i++)
785 {
786 if (slot_attisnull(slot, i))
787 return false;
788 }
789 return true;
790}

References i, TupleDescData::natts, slot_attisnull(), and TupleTableSlot::tts_tupleDescriptor.

Referenced by buildSubPlanHash(), and ExecHashSubPlan().