aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeSubplan.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2005-12-28 01:30:02 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2005-12-28 01:30:02 +0000
commit6e07709760a29d8dbfb93b9846c905bd40689082 (patch)
tree9bf0084587d7e313ba087ce53c24bc748c63a456 /src/backend/executor/nodeSubplan.c
parenta37422e042a6114ab0e513f50dac4a47fab22313 (diff)
downloadpostgresql-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.c126
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")));