diff options
Diffstat (limited to 'src/backend/executor/nodeSubplan.c')
-rw-r--r-- | src/backend/executor/nodeSubplan.c | 243 |
1 files changed, 117 insertions, 126 deletions
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index 5bed87aea9b..0e7b6df7225 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.69 2005/05/06 17:24:54 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.70 2005/10/15 02:49:17 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -86,15 +86,15 @@ ExecHashSubPlan(SubPlanState *node, elog(ERROR, "hashed subplan with direct correlation not supported"); /* - * If first time through or we need to rescan the subplan, build the - * hash table. + * If first time through or we need to rescan the subplan, build the hash + * table. */ if (node->hashtable == NULL || planstate->chgParam != NULL) buildSubPlanHash(node); /* - * The result for an empty subplan is always FALSE; no need to - * evaluate lefthand side. + * The result for an empty subplan is always FALSE; no need to evaluate + * lefthand side. */ *isNull = false; if (!node->havehashrows && !node->havenullrows) @@ -108,34 +108,32 @@ ExecHashSubPlan(SubPlanState *node, slot = ExecProject(node->projLeft, NULL); /* - * Note: because we are typically called in a per-tuple context, we - * have to explicitly clear the projected tuple before returning. - * Otherwise, we'll have a double-free situation: the per-tuple - * context will probably be reset before we're called again, and then - * the tuple slot will think it still needs to free the tuple. + * Note: because we are typically called in a per-tuple context, we have + * to explicitly clear the projected tuple before returning. Otherwise, + * we'll have a double-free situation: the per-tuple context will probably + * be reset before we're called again, and then the tuple slot will think + * it still needs to free the tuple. */ /* - * Since the hashtable routines will use innerecontext's per-tuple - * memory as working memory, be sure to reset it for each tuple. + * Since the hashtable routines will use innerecontext's per-tuple memory + * as working memory, be sure to reset it for each tuple. */ ResetExprContext(innerecontext); /* - * If the LHS is all non-null, probe for an exact match in the main - * hash table. If we find one, the result is TRUE. Otherwise, scan - * the partly-null table to see if there are any rows that aren't - * provably unequal to the LHS; if so, the result is UNKNOWN. (We - * skip that part if we don't care about UNKNOWN.) Otherwise, the - * result is FALSE. + * If the LHS is all non-null, probe for an exact match in the main hash + * table. If we find one, the result is TRUE. Otherwise, scan the + * partly-null table to see if there are any rows that aren't provably + * unequal to the LHS; if so, the result is UNKNOWN. (We skip that part + * if we don't care about UNKNOWN.) Otherwise, the result is FALSE. * - * Note: the reason we can avoid a full scan of the main hash table is - * that the combining operators are assumed never to yield NULL when - * both inputs are non-null. If they were to do so, we might need to - * produce UNKNOWN instead of FALSE because of an UNKNOWN result in - * comparing the LHS to some main-table entry --- which is a - * comparison we will not even make, unless there's a chance match of - * hash keys. + * Note: the reason we can avoid a full scan of the main hash table is that + * the combining operators are assumed never to yield NULL when both + * inputs are non-null. If they were to do so, we might need to produce + * UNKNOWN instead of FALSE because of an UNKNOWN result in comparing the + * LHS to some main-table entry --- which is a comparison we will not even + * make, unless there's a chance match of hash keys. */ if (slotNoNulls(slot)) { @@ -157,14 +155,14 @@ ExecHashSubPlan(SubPlanState *node, } /* - * When the LHS is partly or wholly NULL, we can never return TRUE. If - * we don't care about UNKNOWN, just return FALSE. Otherwise, if the - * LHS is wholly NULL, immediately return UNKNOWN. (Since the - * combining operators are strict, the result could only be FALSE if - * the sub-select were empty, but we already handled that case.) - * Otherwise, we must scan both the main and partly-null tables to see - * if there are any rows that aren't provably unequal to the LHS; if - * so, the result is UNKNOWN. Otherwise, the result is FALSE. + * When the LHS is partly or wholly NULL, we can never return TRUE. If we + * don't care about UNKNOWN, just return FALSE. Otherwise, if the LHS is + * wholly NULL, immediately return UNKNOWN. (Since the combining + * operators are strict, the result could only be FALSE if the sub-select + * were empty, but we already handled that case.) Otherwise, we must scan + * both the main and partly-null tables to see if there are any rows that + * aren't provably unequal to the LHS; if so, the result is UNKNOWN. + * Otherwise, the result is FALSE. */ if (node->hashnulls == NULL) { @@ -217,9 +215,9 @@ ExecScanSubPlan(SubPlanState *node, ArrayBuildState *astate = NULL; /* - * We are probably in a short-lived expression-evaluation context. - * Switch to the child plan's per-query context for manipulating its - * chgParam, calling ExecProcNode on it, etc. + * We are probably in a short-lived expression-evaluation context. Switch + * to the child plan's per-query context for manipulating its chgParam, + * calling ExecProcNode on it, etc. */ oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt); @@ -245,24 +243,23 @@ ExecScanSubPlan(SubPlanState *node, ExecReScan(planstate, NULL); /* - * For all sublink types except EXPR_SUBLINK and ARRAY_SUBLINK, the - * result is boolean as are the results of the combining operators. We - * combine results within a tuple (if there are multiple columns) - * using OR semantics if "useOr" is true, AND semantics if not. We - * then combine results across tuples (if the subplan produces more - * than one) using OR semantics for ANY_SUBLINK or AND semantics for - * ALL_SUBLINK. (MULTIEXPR_SUBLINK doesn't allow multiple tuples from - * the subplan.) NULL results from the combining operators are handled - * according to the usual SQL semantics for OR and AND. The result - * for no input tuples is FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, - * NULL for MULTIEXPR_SUBLINK. + * For all sublink types except EXPR_SUBLINK and ARRAY_SUBLINK, the result + * is boolean as are the results of the combining operators. We combine + * results within a tuple (if there are multiple columns) using OR + * semantics if "useOr" is true, AND semantics if not. We then combine + * results across tuples (if the subplan produces more than one) using OR + * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK. + * (MULTIEXPR_SUBLINK doesn't allow multiple tuples from the subplan.) + * NULL results from the combining operators are handled according to the + * usual SQL semantics for OR and AND. The result for no input tuples is + * FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for + * MULTIEXPR_SUBLINK. * - * For EXPR_SUBLINK we require the subplan to produce no more than one - * tuple, else an error is raised. For ARRAY_SUBLINK we allow the - * subplan to produce more than one tuple. In either case, if zero - * tuples are produced, we return NULL. Assuming we get a tuple, we - * just use its first column (there can be only one non-junk column in - * this case). + * For EXPR_SUBLINK we require the subplan to produce no more than one tuple, + * else an error is raised. For ARRAY_SUBLINK we allow the subplan to + * produce more than one tuple. In either case, if zero tuples are + * produced, we return NULL. Assuming we get a tuple, we just use its + * first column (there can be only one non-junk column in this case). */ result = BoolGetDatum(subLinkType == ALL_SUBLINK); *isNull = false; @@ -294,12 +291,12 @@ ExecScanSubPlan(SubPlanState *node, found = true; /* - * We need to copy the subplan's tuple in case the result is - * of pass-by-ref type --- our return value will point into - * this copied tuple! Can't use the subplan's instance of the - * tuple since it won't still be valid after next - * ExecProcNode() call. node->curTuple keeps track of the - * copied tuple for eventual freeing. + * We need to copy the subplan's tuple in case the result is of + * pass-by-ref type --- our return value will point into this + * copied tuple! Can't use the subplan's instance of the tuple + * since it won't still be valid after next ExecProcNode() call. + * node->curTuple keeps track of the copied tuple for eventual + * freeing. */ MemoryContextSwitchTo(econtext->ecxt_per_query_memory); if (node->curTuple) @@ -350,8 +347,7 @@ ExecScanSubPlan(SubPlanState *node, bool expnull; /* - * Load up the Param representing this column of the - * sub-select. + * Load up the Param representing this column of the sub-select. */ prmdata = &(econtext->ecxt_param_exec_vals[paramid]); Assert(prmdata->execPlan == NULL); @@ -436,8 +432,8 @@ ExecScanSubPlan(SubPlanState *node, { /* * deal with empty subplan result. result/isNull were previously - * initialized correctly for all sublink types except EXPR, ARRAY, - * and MULTIEXPR; for those, return NULL. + * initialized correctly for all sublink types except EXPR, ARRAY, and + * MULTIEXPR; for those, return NULL. */ if (subLinkType == EXPR_SUBLINK || subLinkType == ARRAY_SUBLINK || @@ -478,19 +474,19 @@ buildSubPlanHash(SubPlanState *node) Assert(!subplan->useOr); /* - * If we already had any hash tables, destroy 'em; then create empty - * hash table(s). + * If we already had any hash tables, destroy 'em; then create empty hash + * table(s). * * If we need to distinguish accurately between FALSE and UNKNOWN (i.e., - * NULL) results of the IN operation, then we have to store subplan - * output rows that are partly or wholly NULL. We store such rows in - * a separate hash table that we expect will be much smaller than the - * main table. (We can use hashing to eliminate partly-null rows that - * are not distinct. We keep them separate to minimize the cost of - * the inevitable full-table searches; see findPartialMatch.) + * NULL) results of the IN operation, then we have to store subplan output + * rows that are partly or wholly NULL. We store such rows in a separate + * hash table that we expect will be much smaller than the main table. + * (We can use hashing to eliminate partly-null rows that are not + * distinct. We keep them separate to minimize the cost of the inevitable + * full-table searches; see findPartialMatch.) * - * If it's not necessary to distinguish FALSE and UNKNOWN, then we don't - * need to store subplan output rows that contain NULL. + * If it's not necessary to distinguish FALSE and UNKNOWN, then we don't need + * to store subplan output rows that contain NULL. */ MemoryContextReset(node->tablecxt); node->hashtable = NULL; @@ -532,9 +528,8 @@ buildSubPlanHash(SubPlanState *node) } /* - * We are probably in a short-lived expression-evaluation context. - * Switch to the child plan's per-query context for calling - * ExecProcNode. + * We are probably in a short-lived expression-evaluation context. Switch + * to the child plan's per-query context for calling ExecProcNode. */ oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt); @@ -544,9 +539,8 @@ buildSubPlanHash(SubPlanState *node) ExecReScan(planstate, NULL); /* - * Scan the subplan and load the hash table(s). Note that when there - * are duplicate rows coming out of the sub-select, only one copy is - * stored. + * Scan the subplan and load the hash table(s). Note that when there are + * duplicate rows coming out of the sub-select, only one copy is stored. */ for (slot = ExecProcNode(planstate); !TupIsNull(slot); @@ -557,8 +551,8 @@ buildSubPlanHash(SubPlanState *node) bool isnew; /* - * Load up the Params representing the raw sub-select outputs, - * then form the projection tuple to store in the hashtable. + * Load up the Params representing the raw sub-select outputs, then + * form the projection tuple to store in the hashtable. */ foreach(plst, subplan->paramIds) { @@ -588,18 +582,18 @@ buildSubPlanHash(SubPlanState *node) } /* - * Reset innerecontext after each inner tuple to free any memory - * used in hash computation or comparison routines. + * Reset innerecontext after each inner tuple to free any memory used + * in hash computation or comparison routines. */ ResetExprContext(innerecontext); } /* - * Since the projected tuples are in the sub-query's context and not - * the main context, we'd better clear the tuple slot before there's - * any chance of a reset of the sub-query's context. Else we will - * have the potential for a double free attempt. (XXX possibly - * no longer needed, but can't hurt.) + * Since the projected tuples are in the sub-query's context and not the + * main context, we'd better clear the tuple slot before there's any + * chance of a reset of the sub-query's context. Else we will have the + * potential for a double free attempt. (XXX possibly no longer needed, + * but can't hurt.) */ ExecClearTuple(node->projRight->pi_slot); @@ -710,10 +704,10 @@ ExecInitSubPlan(SubPlanState *node, EState *estate) /* * create an EState for the subplan * - * The subquery needs its own EState because it has its own rangetable. - * It shares our Param ID space, however. XXX if rangetable access - * were done differently, the subquery could share our EState, which - * would eliminate some thrashing about in this module... + * The subquery needs its own EState because it has its own rangetable. It + * shares our Param ID space, however. XXX if rangetable access were done + * differently, the subquery could share our EState, which would eliminate + * some thrashing about in this module... */ sp_estate = CreateExecutorState(); node->sub_estate = sp_estate; @@ -739,13 +733,12 @@ ExecInitSubPlan(SubPlanState *node, EState *estate) MemoryContextSwitchTo(oldcontext); /* - * If this plan is un-correlated or undirect correlated one and want - * to set params for parent plan then mark parameters as needing - * evaluation. + * If this plan is un-correlated or undirect correlated one and want to + * set params for parent plan then mark parameters as needing evaluation. * * Note that in the case of un-correlated subqueries we don't care about - * setting parent->chgParam here: indices take care about it, for - * others - it doesn't matter... + * setting parent->chgParam here: indices take care about it, for others - + * it doesn't matter... */ if (subplan->setParam != NIL) { @@ -761,8 +754,8 @@ ExecInitSubPlan(SubPlanState *node, EState *estate) } /* - * If we are going to hash the subquery output, initialize relevant - * stuff. (We don't create the hashtable until needed, though.) + * If we are going to hash the subquery output, initialize relevant stuff. + * (We don't create the hashtable until needed, though.) */ if (subplan->useHashTable) { @@ -794,18 +787,17 @@ ExecInitSubPlan(SubPlanState *node, EState *estate) /* * We use ExecProject to evaluate the lefthand and righthand - * expression lists and form tuples. (You might think that we - * could use the sub-select's output tuples directly, but that is - * not the case if we had to insert any run-time coercions of the - * sub-select's output datatypes; anyway this avoids storing any - * resjunk columns that might be in the sub-select's output.) Run - * through the combining expressions to build tlists for the - * lefthand and righthand sides. We need both the ExprState list - * (for ExecProject) and the underlying parse Exprs (for - * ExecTypeFromTL). + * expression lists and form tuples. (You might think that we could + * use the sub-select's output tuples directly, but that is not the + * case if we had to insert any run-time coercions of the sub-select's + * output datatypes; anyway this avoids storing any resjunk columns + * that might be in the sub-select's output.) Run through the + * combining expressions to build tlists for the lefthand and + * righthand sides. We need both the ExprState list (for ExecProject) + * and the underlying parse Exprs (for ExecTypeFromTL). * - * We also extract the combining operators themselves to initialize - * the equality and hashing functions for the hash tables. + * We also extract the combining operators themselves to initialize the + * equality and hashing functions for the hash tables. */ lefttlist = righttlist = NIL; leftptlist = rightptlist = NIL; @@ -869,21 +861,21 @@ ExecInitSubPlan(SubPlanState *node, EState *estate) } /* - * Create a tupletable to hold these tuples. (Note: we never - * bother to free the tupletable explicitly; that's okay because - * it will never store raw disk tuples that might have associated - * buffer pins. The only resource involved is memory, which will - * be cleaned up by freeing the query context.) + * Create a tupletable to hold these tuples. (Note: we never bother + * to free the tupletable explicitly; that's okay because it will + * never store raw disk tuples that might have associated buffer pins. + * The only resource involved is memory, which will be cleaned up by + * freeing the query context.) */ tupTable = ExecCreateTupleTable(2); /* - * Construct tupdescs, slots and projection nodes for left and - * right sides. The lefthand expressions will be evaluated in the - * parent plan node's exprcontext, which we don't have access to - * here. Fortunately we can just pass NULL for now and fill it in - * later (hack alert!). The righthand expressions will be - * evaluated in our own innerecontext. + * Construct tupdescs, slots and projection nodes for left and right + * sides. The lefthand expressions will be evaluated in the parent + * plan node's exprcontext, which we don't have access to here. + * Fortunately we can just pass NULL for now and fill it in later + * (hack alert!). The righthand expressions will be evaluated in our + * own innerecontext. */ tupDesc = ExecTypeFromTL(leftptlist, false); slot = ExecAllocTableSlot(tupTable); @@ -983,11 +975,10 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext) found = true; /* - * We need to copy the subplan's tuple into our own context, in - * case any of the params are pass-by-ref type --- the pointers - * stored in the param structs will point at this copied tuple! - * node->curTuple keeps track of the copied tuple for eventual - * freeing. + * We need to copy the subplan's tuple into our own context, in case + * any of the params are pass-by-ref type --- the pointers stored in + * the param structs will point at this copied tuple! node->curTuple + * keeps track of the copied tuple for eventual freeing. */ MemoryContextSwitchTo(econtext->ecxt_per_query_memory); if (node->curTuple) |