* ExecHashSubPlan: store subselect result in an in-memory hash table */
| 110 | * ExecHashSubPlan: store subselect result in an in-memory hash table |
| 111 | */ |
| 112 | static Datum |
| 113 | ExecHashSubPlan(SubPlanState *node, |
| 114 | ExprContext *econtext, |
| 115 | bool *isNull) |
| 116 | { |
| 117 | SubPlan *subplan = node->subplan; |
| 118 | PlanState *planstate = node->planstate; |
| 119 | TupleTableSlot *slot; |
| 120 | |
| 121 | /* Shouldn't have any direct correlation Vars */ |
| 122 | if (subplan->parParam != NIL || node->args != NIL) |
| 123 | elog(ERROR, "hashed subplan with direct correlation not supported"); |
| 124 | |
| 125 | /* |
| 126 | * If first time through or we need to rescan the subplan, build the hash |
| 127 | * table. |
| 128 | */ |
| 129 | if (node->hashtable == NULL || planstate->chgParam != NULL) |
| 130 | buildSubPlanHash(node, econtext); |
| 131 | |
| 132 | /* |
| 133 | * The result for an empty subplan is always FALSE; no need to evaluate |
| 134 | * lefthand side. |
| 135 | */ |
| 136 | *isNull = false; |
| 137 | if (!node->havehashrows && !node->havenullrows) |
| 138 | return BoolGetDatum(false); |
| 139 | |
| 140 | /* |
| 141 | * Evaluate lefthand expressions and form a projection tuple. First we |
| 142 | * have to set the econtext to use (hack alert!). |
| 143 | */ |
| 144 | node->projLeft->pi_exprContext = econtext; |
| 145 | slot = ExecProject(node->projLeft); |
| 146 | |
| 147 | /* |
| 148 | * Note: because we are typically called in a per-tuple context, we have |
| 149 | * to explicitly clear the projected tuple before returning. Otherwise, |
| 150 | * we'll have a double-free situation: the per-tuple context will probably |
| 151 | * be reset before we're called again, and then the tuple slot will think |
| 152 | * it still needs to free the tuple. |
| 153 | */ |
| 154 | |
| 155 | /* |
| 156 | * If the LHS is all non-null, probe for an exact match in the main hash |
| 157 | * table. If we find one, the result is TRUE. Otherwise, scan the |
| 158 | * partly-null table to see if there are any rows that aren't provably |
| 159 | * unequal to the LHS; if so, the result is UNKNOWN. (We skip that part |
| 160 | * if we don't care about UNKNOWN.) Otherwise, the result is FALSE. |
| 161 | * |
| 162 | * Note: the reason we can avoid a full scan of the main hash table is |
| 163 | * that the combining operators are assumed never to yield NULL when both |
| 164 | * inputs are non-null. If they were to do so, we might need to produce |
| 165 | * UNKNOWN instead of FALSE because of an UNKNOWN result in comparing the |
| 166 | * LHS to some main-table entry --- which is a comparison we will not even |
| 167 | * make, unless there's a chance match of hash keys. |
| 168 | */ |
| 169 | if (slotNoNulls(slot)) |
no test coverage detected