aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execQual.c148
-rw-r--r--src/backend/executor/nodeSubplan.c126
2 files changed, 194 insertions, 80 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 2df9f1685cb..fe78a0fa084 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.186 2005/12/14 16:28:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.187 2005/12/28 01:29:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -37,6 +37,7 @@
#include "postgres.h"
#include "access/heapam.h"
+#include "access/nbtree.h"
#include "catalog/pg_type.h"
#include "commands/typecmds.h"
#include "executor/execdebug.h"
@@ -104,6 +105,9 @@ static Datum ExecEvalArray(ArrayExprState *astate,
static Datum ExecEvalRow(RowExprState *rstate,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
+static Datum ExecEvalRowCompare(RowCompareExprState *rstate,
+ ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
@@ -2307,6 +2311,76 @@ ExecEvalRow(RowExprState *rstate,
}
/* ----------------------------------------------------------------
+ * ExecEvalRowCompare - ROW() comparison-op ROW()
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalRowCompare(RowCompareExprState *rstate,
+ ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ bool result;
+ RowCompareType rctype = ((RowCompareExpr *) rstate->xprstate.expr)->rctype;
+ int32 cmpresult = 0;
+ ListCell *l;
+ ListCell *r;
+ int i;
+
+ if (isDone)
+ *isDone = ExprSingleResult;
+ *isNull = true; /* until we get a result */
+
+ i = 0;
+ forboth(l, rstate->largs, r, rstate->rargs)
+ {
+ ExprState *le = (ExprState *) lfirst(l);
+ ExprState *re = (ExprState *) lfirst(r);
+ FunctionCallInfoData locfcinfo;
+
+ InitFunctionCallInfoData(locfcinfo, &(rstate->funcs[i]), 2,
+ NULL, NULL);
+ locfcinfo.arg[0] = ExecEvalExpr(le, econtext,
+ &locfcinfo.argnull[0], NULL);
+ locfcinfo.arg[1] = ExecEvalExpr(re, econtext,
+ &locfcinfo.argnull[1], NULL);
+ if (rstate->funcs[i].fn_strict &&
+ (locfcinfo.argnull[0] || locfcinfo.argnull[1]))
+ return (Datum) 0; /* force NULL result */
+ locfcinfo.isnull = false;
+ cmpresult = DatumGetInt32(FunctionCallInvoke(&locfcinfo));
+ if (locfcinfo.isnull)
+ return (Datum) 0; /* force NULL result */
+ if (cmpresult != 0)
+ break; /* no need to compare remaining columns */
+ i++;
+ }
+
+ switch (rctype)
+ {
+ /* EQ and NE cases aren't allowed here */
+ case ROWCOMPARE_LT:
+ result = (cmpresult < 0);
+ break;
+ case ROWCOMPARE_LE:
+ result = (cmpresult <= 0);
+ break;
+ case ROWCOMPARE_GE:
+ result = (cmpresult >= 0);
+ break;
+ case ROWCOMPARE_GT:
+ result = (cmpresult > 0);
+ break;
+ default:
+ elog(ERROR, "unrecognized RowCompareType: %d", (int) rctype);
+ result = 0; /* keep compiler quiet */
+ break;
+ }
+
+ *isNull = false;
+ return BoolGetDatum(result);
+}
+
+/* ----------------------------------------------------------------
* ExecEvalCoalesce
* ----------------------------------------------------------------
*/
@@ -3118,8 +3192,8 @@ ExecInitExpr(Expr *node, PlanState *parent)
sstate->sub_estate = NULL;
sstate->planstate = NULL;
- sstate->exprs = (List *)
- ExecInitExpr((Expr *) subplan->exprs, parent);
+ sstate->testexpr =
+ ExecInitExpr((Expr *) subplan->testexpr, parent);
sstate->args = (List *)
ExecInitExpr((Expr *) subplan->args, parent);
@@ -3336,6 +3410,66 @@ ExecInitExpr(Expr *node, PlanState *parent)
state = (ExprState *) rstate;
}
break;
+ case T_RowCompareExpr:
+ {
+ RowCompareExpr *rcexpr = (RowCompareExpr *) node;
+ RowCompareExprState *rstate = makeNode(RowCompareExprState);
+ int nopers = list_length(rcexpr->opnos);
+ List *outlist;
+ ListCell *l;
+ ListCell *l2;
+ int i;
+
+ rstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalRowCompare;
+ Assert(list_length(rcexpr->largs) == nopers);
+ outlist = NIL;
+ foreach(l, rcexpr->largs)
+ {
+ Expr *e = (Expr *) lfirst(l);
+ ExprState *estate;
+
+ estate = ExecInitExpr(e, parent);
+ outlist = lappend(outlist, estate);
+ }
+ rstate->largs = outlist;
+ Assert(list_length(rcexpr->rargs) == nopers);
+ outlist = NIL;
+ foreach(l, rcexpr->rargs)
+ {
+ Expr *e = (Expr *) lfirst(l);
+ ExprState *estate;
+
+ estate = ExecInitExpr(e, parent);
+ outlist = lappend(outlist, estate);
+ }
+ rstate->rargs = outlist;
+ Assert(list_length(rcexpr->opclasses) == nopers);
+ rstate->funcs = (FmgrInfo *) palloc(nopers * sizeof(FmgrInfo));
+ i = 0;
+ forboth(l, rcexpr->opnos, l2, rcexpr->opclasses)
+ {
+ Oid opno = lfirst_oid(l);
+ Oid opclass = lfirst_oid(l2);
+ int strategy;
+ Oid subtype;
+ bool recheck;
+ Oid proc;
+
+ get_op_opclass_properties(opno, opclass,
+ &strategy, &subtype, &recheck);
+ proc = get_opclass_proc(opclass, subtype, BTORDER_PROC);
+ /*
+ * If we enforced permissions checks on index support
+ * functions, we'd need to make a check here. But the
+ * index support machinery doesn't do that, and neither
+ * does this code.
+ */
+ fmgr_info(proc, &(rstate->funcs[i]));
+ i++;
+ }
+ state = (ExprState *) rstate;
+ }
+ break;
case T_CoalesceExpr:
{
CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
@@ -3382,6 +3516,12 @@ ExecInitExpr(Expr *node, PlanState *parent)
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("could not identify a comparison function for type %s",
format_type_be(minmaxexpr->minmaxtype))));
+ /*
+ * If we enforced permissions checks on index support
+ * functions, we'd need to make a check here. But the
+ * index support machinery doesn't do that, and neither
+ * does this code.
+ */
fmgr_info(typentry->cmp_proc, &(mstate->cfunc));
state = (ExprState *) mstate;
}
@@ -3484,7 +3624,7 @@ ExecInitExprInitPlan(SubPlan *node, PlanState *parent)
sstate->sub_estate = NULL;
sstate->planstate = NULL;
- sstate->exprs = (List *) ExecInitExpr((Expr *) node->exprs, parent);
+ sstate->testexpr = ExecInitExpr((Expr *) node->testexpr, parent);
sstate->args = (List *) ExecInitExpr((Expr *) node->args, parent);
sstate->xprstate.expr = (Expr *) node;
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")));