diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2005-12-28 01:30:02 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2005-12-28 01:30:02 +0000 |
commit | 6e07709760a29d8dbfb93b9846c905bd40689082 (patch) | |
tree | 9bf0084587d7e313ba087ce53c24bc748c63a456 /src/backend/executor/nodeSubplan.c | |
parent | a37422e042a6114ab0e513f50dac4a47fab22313 (diff) | |
download | postgresql-6e07709760a29d8dbfb93b9846c905bd40689082.tar.gz postgresql-6e07709760a29d8dbfb93b9846c905bd40689082.zip |
Implement SQL-compliant treatment of row comparisons for < <= > >= cases
(previously we only did = and <> correctly). Also, allow row comparisons
with any operators that are in btree opclasses, not only those with these
specific names. This gets rid of a whole lot of indefensible assumptions
about the behavior of particular operators based on their names ... though
it's still true that IN and NOT IN expand to "= ANY". The patch adds a
RowCompareExpr expression node type, and makes some changes in the
representation of ANY/ALL/ROWCOMPARE SubLinks so that they can share code
with RowCompareExpr.
I have not yet done anything about making RowCompareExpr an indexable
operator, but will look at that soon.
initdb forced due to changes in stored rules.
Diffstat (limited to 'src/backend/executor/nodeSubplan.c')
-rw-r--r-- | src/backend/executor/nodeSubplan.c | 126 |
1 files changed, 50 insertions, 76 deletions
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index e35430d28b0..80679d9f63f 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.71 2005/11/22 18:17:10 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.72 2005/12/28 01:29:59 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -23,6 +23,7 @@ #include "executor/executor.h" #include "executor/nodeSubplan.h" #include "nodes/makefuncs.h" +#include "optimizer/clauses.h" #include "parser/parse_expr.h" #include "utils/array.h" #include "utils/datum.h" @@ -205,7 +206,6 @@ ExecScanSubPlan(SubPlanState *node, SubPlan *subplan = (SubPlan *) node->xprstate.expr; PlanState *planstate = node->planstate; SubLinkType subLinkType = subplan->subLinkType; - bool useOr = subplan->useOr; MemoryContext oldcontext; TupleTableSlot *slot; Datum result; @@ -245,15 +245,13 @@ ExecScanSubPlan(SubPlanState *node, /* * 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.) + * (ROWCOMPARE_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. + * ROWCOMPARE_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 @@ -269,9 +267,9 @@ ExecScanSubPlan(SubPlanState *node, slot = ExecProcNode(planstate)) { TupleDesc tdesc = slot->tts_tupleDescriptor; - Datum rowresult = BoolGetDatum(!useOr); - bool rownull = false; - int col = 1; + Datum rowresult; + bool rownull; + int col; ListCell *plst; if (subLinkType == EXISTS_SUBLINK) @@ -304,7 +302,7 @@ ExecScanSubPlan(SubPlanState *node, node->curTuple = ExecCopySlotTuple(slot); MemoryContextSwitchTo(node->sub_estate->es_query_cxt); - result = heap_getattr(node->curTuple, col, tdesc, isNull); + result = heap_getattr(node->curTuple, 1, tdesc, isNull); /* keep scanning subplan to make sure there's only one tuple */ continue; } @@ -324,8 +322,8 @@ ExecScanSubPlan(SubPlanState *node, continue; } - /* cannot allow multiple input tuples for MULTIEXPR sublink either */ - if (subLinkType == MULTIEXPR_SUBLINK && found) + /* cannot allow multiple input tuples for ROWCOMPARE sublink either */ + if (subLinkType == ROWCOMPARE_SUBLINK && found) ereport(ERROR, (errcode(ERRCODE_CARDINALITY_VIOLATION), errmsg("more than one row returned by a subquery used as an expression"))); @@ -333,69 +331,25 @@ ExecScanSubPlan(SubPlanState *node, found = true; /* - * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining - * operators for columns of tuple. + * For ALL, ANY, and ROWCOMPARE sublinks, load up the Params + * representing the columns of the sub-select, and then evaluate + * the combining expression. */ - Assert(list_length(node->exprs) == list_length(subplan->paramIds)); - - forboth(l, node->exprs, plst, subplan->paramIds) + col = 1; + foreach(plst, subplan->paramIds) { - ExprState *exprstate = (ExprState *) lfirst(l); int paramid = lfirst_int(plst); ParamExecData *prmdata; - Datum expresult; - bool expnull; - /* - * Load up the Param representing this column of the sub-select. - */ prmdata = &(econtext->ecxt_param_exec_vals[paramid]); Assert(prmdata->execPlan == NULL); - prmdata->value = slot_getattr(slot, col, - &(prmdata->isnull)); - - /* - * Now we can eval the combining operator for this column. - */ - expresult = ExecEvalExprSwitchContext(exprstate, econtext, - &expnull, NULL); - - /* - * Combine the result into the row result as appropriate. - */ - if (col == 1) - { - rowresult = expresult; - rownull = expnull; - } - else if (useOr) - { - /* combine within row per OR semantics */ - if (expnull) - rownull = true; - else if (DatumGetBool(expresult)) - { - rowresult = BoolGetDatum(true); - rownull = false; - break; /* needn't look at any more columns */ - } - } - else - { - /* combine within row per AND semantics */ - if (expnull) - rownull = true; - else if (!DatumGetBool(expresult)) - { - rowresult = BoolGetDatum(false); - rownull = false; - break; /* needn't look at any more columns */ - } - } - + prmdata->value = slot_getattr(slot, col, &(prmdata->isnull)); col++; } + rowresult = ExecEvalExprSwitchContext(node->testexpr, econtext, + &rownull, NULL); + if (subLinkType == ANY_SUBLINK) { /* combine across rows per OR semantics */ @@ -422,7 +376,7 @@ ExecScanSubPlan(SubPlanState *node, } else { - /* must be MULTIEXPR_SUBLINK */ + /* must be ROWCOMPARE_SUBLINK */ result = rowresult; *isNull = rownull; } @@ -433,11 +387,11 @@ 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. + * ROWCOMPARE; for those, return NULL. */ if (subLinkType == EXPR_SUBLINK || subLinkType == ARRAY_SUBLINK || - subLinkType == MULTIEXPR_SUBLINK) + subLinkType == ROWCOMPARE_SUBLINK) { result = (Datum) 0; *isNull = true; @@ -463,7 +417,7 @@ buildSubPlanHash(SubPlanState *node) { SubPlan *subplan = (SubPlan *) node->xprstate.expr; PlanState *planstate = node->planstate; - int ncols = list_length(node->exprs); + int ncols = list_length(subplan->paramIds); ExprContext *innerecontext = node->innerecontext; MemoryContext tempcxt = innerecontext->ecxt_per_tuple_memory; MemoryContext oldcontext; @@ -471,7 +425,6 @@ buildSubPlanHash(SubPlanState *node) TupleTableSlot *slot; Assert(subplan->subLinkType == ANY_SUBLINK); - Assert(!subplan->useOr); /* * If we already had any hash tables, destroy 'em; then create empty hash @@ -764,11 +717,12 @@ ExecInitSubPlan(SubPlanState *node, EState *estate) TupleDesc tupDesc; TupleTable tupTable; TupleTableSlot *slot; - List *lefttlist, + List *oplist, + *lefttlist, *righttlist, *leftptlist, *rightptlist; - ListCell *lexpr; + ListCell *l; /* We need a memory context to hold the hash table(s) */ node->tablecxt = @@ -780,7 +734,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate) /* and a short-lived exprcontext for function evaluation */ node->innerecontext = CreateExprContext(estate); /* Silly little array of column numbers 1..n */ - ncols = list_length(node->exprs); + ncols = list_length(subplan->paramIds); node->keyColIdx = (AttrNumber *) palloc(ncols * sizeof(AttrNumber)); for (i = 0; i < ncols; i++) node->keyColIdx[i] = i + 1; @@ -799,14 +753,34 @@ ExecInitSubPlan(SubPlanState *node, EState *estate) * We also extract the combining operators themselves to initialize * the equality and hashing functions for the hash tables. */ + if (IsA(node->testexpr->expr, OpExpr)) + { + /* single combining operator */ + oplist = list_make1(node->testexpr); + } + else if (and_clause((Node *) node->testexpr->expr)) + { + /* multiple combining operators */ + Assert(IsA(node->testexpr, BoolExprState)); + oplist = ((BoolExprState *) node->testexpr)->args; + } + else + { + /* shouldn't see anything else in a hashable subplan */ + elog(ERROR, "unrecognized testexpr type: %d", + (int) nodeTag(node->testexpr->expr)); + oplist = NIL; /* keep compiler quiet */ + } + Assert(list_length(oplist) == ncols); + lefttlist = righttlist = NIL; leftptlist = rightptlist = NIL; node->eqfunctions = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo)); node->hashfunctions = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo)); i = 1; - foreach(lexpr, node->exprs) + foreach(l, oplist) { - FuncExprState *fstate = (FuncExprState *) lfirst(lexpr); + FuncExprState *fstate = (FuncExprState *) lfirst(l); OpExpr *opexpr = (OpExpr *) fstate->xprstate.expr; ExprState *exstate; Expr *expr; @@ -967,7 +941,7 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext) if (found && (subLinkType == EXPR_SUBLINK || - subLinkType == MULTIEXPR_SUBLINK)) + subLinkType == ROWCOMPARE_SUBLINK)) ereport(ERROR, (errcode(ERRCODE_CARDINALITY_VIOLATION), errmsg("more than one row returned by a subquery used as an expression"))); |