* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.40 2002/12/26 22:37:42 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.41 2003/01/09 20:50:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
SubPlan *subplan = (SubPlan *) node->xprstate.expr;
PlanState *planstate = node->planstate;
SubLinkType subLinkType = subplan->subLinkType;
- bool useor = subplan->useor;
+ bool useOr = subplan->useOr;
MemoryContext oldcontext;
TupleTableSlot *slot;
Datum result;
* For all sublink types except EXPR_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
+ * 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.)
{
HeapTuple tup = slot->val;
TupleDesc tdesc = slot->ttc_tupleDescriptor;
- Datum rowresult = BoolGetDatum(!useor);
+ Datum rowresult = BoolGetDatum(!useOr);
bool rownull = false;
int col = 1;
rowresult = expresult;
rownull = expnull;
}
- else if (useor)
+ else if (useOr)
{
/* combine within row per OR semantics */
if (expnull)
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.233 2002/12/14 00:17:50 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.234 2003/01/09 20:50:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
SubLink *newnode = makeNode(SubLink);
COPY_SCALAR_FIELD(subLinkType);
- COPY_SCALAR_FIELD(useor);
+ COPY_SCALAR_FIELD(operIsEquals);
+ COPY_SCALAR_FIELD(useOr);
COPY_NODE_FIELD(lefthand);
COPY_NODE_FIELD(oper);
COPY_NODE_FIELD(subselect);
SubPlan *newnode = makeNode(SubPlan);
COPY_SCALAR_FIELD(subLinkType);
- COPY_SCALAR_FIELD(useor);
+ COPY_SCALAR_FIELD(useOr);
COPY_NODE_FIELD(oper);
COPY_NODE_FIELD(plan);
COPY_SCALAR_FIELD(plan_id);
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.177 2002/12/14 00:17:51 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.178 2003/01/09 20:50:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
_equalSubLink(SubLink *a, SubLink *b)
{
COMPARE_SCALAR_FIELD(subLinkType);
- COMPARE_SCALAR_FIELD(useor);
+ COMPARE_SCALAR_FIELD(operIsEquals);
+ COMPARE_SCALAR_FIELD(useOr);
COMPARE_NODE_FIELD(lefthand);
COMPARE_NODE_FIELD(oper);
COMPARE_NODE_FIELD(subselect);
_equalSubPlan(SubPlan *a, SubPlan *b)
{
COMPARE_SCALAR_FIELD(subLinkType);
- COMPARE_SCALAR_FIELD(useor);
+ COMPARE_SCALAR_FIELD(useOr);
COMPARE_NODE_FIELD(oper);
/* should compare plans, but have to settle for comparing plan IDs */
COMPARE_SCALAR_FIELD(plan_id);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.190 2002/12/14 00:17:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.191 2003/01/09 20:50:50 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
WRITE_NODE_TYPE("SUBLINK");
WRITE_ENUM_FIELD(subLinkType, SubLinkType);
- WRITE_BOOL_FIELD(useor);
+ WRITE_BOOL_FIELD(operIsEquals);
+ WRITE_BOOL_FIELD(useOr);
WRITE_NODE_FIELD(lefthand);
WRITE_NODE_FIELD(oper);
WRITE_NODE_FIELD(subselect);
WRITE_NODE_TYPE("SUBPLAN");
WRITE_ENUM_FIELD(subLinkType, SubLinkType);
- WRITE_BOOL_FIELD(useor);
+ WRITE_BOOL_FIELD(useOr);
WRITE_NODE_FIELD(oper);
WRITE_NODE_FIELD(plan);
WRITE_INT_FIELD(plan_id);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.144 2002/12/14 00:17:54 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.145 2003/01/09 20:50:51 tgl Exp $
*
* NOTES
* Path and Plan nodes do not have any readfuncs support, because we
READ_LOCALS(SubLink);
READ_ENUM_FIELD(subLinkType, SubLinkType);
- READ_BOOL_FIELD(useor);
+ READ_BOOL_FIELD(operIsEquals);
+ READ_BOOL_FIELD(useOr);
READ_NODE_FIELD(lefthand);
READ_NODE_FIELD(oper);
READ_NODE_FIELD(subselect);
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.61 2002/12/14 00:17:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.62 2003/01/09 20:50:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* Fill in other fields of the SubPlan node.
*/
node->subLinkType = slink->subLinkType;
- node->useor = slink->useor;
+ node->useOr = slink->useOr;
node->oper = NIL;
node->setParam = NIL;
node->parParam = NIL;
&node->setParam);
PlannerInitPlan = lappend(PlannerInitPlan, node);
if (length(oper) > 1)
- result = (Node *) (node->useor ? make_orclause(oper) :
+ result = (Node *) (node->useOr ? make_orclause(oper) :
make_andclause(oper));
else
result = (Node *) lfirst(oper);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.391 2003/01/08 00:22:27 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.392 2003/01/09 20:50:51 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
/* Expressions using row descriptors
* Define row_descriptor to allow yacc to break the reduce/reduce conflict
- * with singleton expressions. Use SQL99's ROW keyword to allow rows of
- * one element.
+ * with singleton expressions. Use SQL99's ROW keyword to allow rows of
+ * one element.
*/
r_expr: row IN_P select_with_parens
{
SubLink *n = makeNode(SubLink);
n->lefthand = $1;
n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL);
- n->useor = FALSE;
n->subLinkType = ANY_SUBLINK;
+ /* operIsEquals and useOr will be set later */
n->subselect = $3;
$$ = (Node *)n;
}
| row NOT IN_P select_with_parens
{
+ /* Make an IN node */
SubLink *n = makeNode(SubLink);
n->lefthand = $1;
- n->oper = (List *) makeSimpleA_Expr(OP, "<>", NULL, NULL);
- n->useor = TRUE;
- n->subLinkType = ALL_SUBLINK;
+ n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL);
+ n->subLinkType = ANY_SUBLINK;
+ /* operIsEquals and useOr will be set later */
n->subselect = $4;
- $$ = (Node *)n;
+ /* Stick a NOT on top */
+ $$ = (Node *) makeA_Expr(NOT, NIL, NULL, (Node *) n);
}
| row qual_all_Op sub_type select_with_parens
%prec Op
SubLink *n = makeNode(SubLink);
n->lefthand = $1;
n->oper = (List *) makeA_Expr(OP, $2, NULL, NULL);
- if (strcmp(strVal(llast($2)), "<>") == 0)
- n->useor = TRUE;
- else
- n->useor = FALSE;
n->subLinkType = $3;
+ /* operIsEquals and useOr will be set later */
n->subselect = $4;
$$ = (Node *)n;
}
SubLink *n = makeNode(SubLink);
n->lefthand = $1;
n->oper = (List *) makeA_Expr(OP, $2, NULL, NULL);
- if (strcmp(strVal(llast($2)), "<>") == 0)
- n->useor = TRUE;
- else
- n->useor = FALSE;
n->subLinkType = MULTIEXPR_SUBLINK;
+ /* operIsEquals and useOr will be set later */
n->subselect = $3;
$$ = (Node *)n;
}
SubLink *n = (SubLink *)$3;
n->lefthand = makeList1($1);
n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL);
- n->useor = FALSE;
n->subLinkType = ANY_SUBLINK;
+ /* operIsEquals and useOr will be set later */
$$ = (Node *)n;
}
else
/* in_expr returns a SubLink or a list of a_exprs */
if (IsA($4, SubLink))
{
+ /* Make an IN node */
SubLink *n = (SubLink *)$4;
n->lefthand = makeList1($1);
- n->oper = (List *) makeSimpleA_Expr(OP, "<>", NULL, NULL);
- n->useor = FALSE;
- n->subLinkType = ALL_SUBLINK;
- $$ = (Node *)n;
+ n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL);
+ n->subLinkType = ANY_SUBLINK;
+ /* operIsEquals and useOr will be set later */
+ /* Stick a NOT on top */
+ $$ = (Node *) makeA_Expr(NOT, NIL, NULL, (Node *) n);
}
else
{
SubLink *n = makeNode(SubLink);
n->lefthand = makeList1($1);
n->oper = (List *) makeA_Expr(OP, $2, NULL, NULL);
- n->useor = FALSE; /* doesn't matter since only one col */
n->subLinkType = $3;
+ /* operIsEquals and useOr will be set later */
n->subselect = $4;
$$ = (Node *)n;
}
SubLink *n = makeNode(SubLink);
n->lefthand = NIL;
n->oper = NIL;
- n->useor = FALSE;
n->subLinkType = EXPR_SUBLINK;
n->subselect = $1;
$$ = (Node *)n;
SubLink *n = makeNode(SubLink);
n->lefthand = NIL;
n->oper = NIL;
- n->useor = FALSE;
n->subLinkType = EXISTS_SUBLINK;
n->subselect = $2;
$$ = (Node *)n;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.138 2002/12/27 20:06:19 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.139 2003/01/09 20:50:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
sublink->lefthand = NIL;
sublink->oper = NIL;
+ sublink->operIsEquals = FALSE;
+ sublink->useOr = FALSE;
}
else if (sublink->subLinkType == EXPR_SUBLINK)
{
*/
sublink->lefthand = NIL;
sublink->oper = NIL;
+ sublink->operIsEquals = FALSE;
+ sublink->useOr = FALSE;
}
else
{
/* ALL, ANY, or MULTIEXPR: generate operator list */
List *left_list = sublink->lefthand;
List *right_list = qtree->targetList;
+ int row_length = length(left_list);
+ bool needNot = false;
List *op;
char *opname;
List *elist;
+ /* transform lefthand expressions */
foreach(elist, left_list)
lfirst(elist) = transformExpr(pstate, lfirst(elist));
+ /* get the combining-operator name */
Assert(IsA(sublink->oper, A_Expr));
op = ((A_Expr *) sublink->oper)->name;
opname = strVal(llast(op));
sublink->oper = NIL;
+ /*
+ * If the expression is "<> ALL" (with unqualified opname)
+ * then convert it to "NOT IN". This is a hack to improve
+ * efficiency of expressions output by pre-7.4 Postgres.
+ */
+ if (sublink->subLinkType == ALL_SUBLINK &&
+ length(op) == 1 && strcmp(opname, "<>") == 0)
+ {
+ sublink->subLinkType = ANY_SUBLINK;
+ opname = pstrdup("=");
+ op = makeList1(makeString(opname));
+ needNot = true;
+ }
+
+ /* Set operIsEquals if op is unqualified "=" */
+ if (length(op) == 1 && strcmp(opname, "=") == 0)
+ sublink->operIsEquals = TRUE;
+ else
+ sublink->operIsEquals = FALSE;
+
+ /* Set useOr if op is "<>" (possibly qualified) */
+ if (strcmp(opname, "<>") == 0)
+ sublink->useOr = TRUE;
+ else
+ sublink->useOr = FALSE;
+
/* Combining operators other than =/<> is dubious... */
- if (length(left_list) != 1 &&
- strcmp(opname, "=") != 0 && strcmp(opname, "<>") != 0)
+ if (row_length != 1 &&
+ strcmp(opname, "=") != 0 &&
+ strcmp(opname, "<>") != 0)
elog(ERROR, "Row comparison cannot use operator %s",
opname);
}
if (left_list != NIL)
elog(ERROR, "Subselect has too few fields");
+
+ if (needNot)
+ {
+ expr = coerce_to_boolean(expr, "NOT");
+ expr = (Node *) makeBoolExpr(NOT_EXPR,
+ makeList1(expr));
+ }
}
result = (Node *) expr;
break;
* back to source text
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.130 2003/01/08 22:54:06 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.131 2003/01/09 20:50:52 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
break;
case ANY_SUBLINK:
- oper = (OpExpr *) lfirst(sublink->oper);
- appendStringInfo(buf, "%s ANY ", get_opname(oper->opno));
+ if (sublink->operIsEquals)
+ {
+ /* Represent it as IN */
+ appendStringInfo(buf, "IN ");
+ }
+ else
+ {
+ oper = (OpExpr *) lfirst(sublink->oper);
+ appendStringInfo(buf, "%s ANY ", get_opname(oper->opno));
+ }
break;
case ALL_SUBLINK:
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: catversion.h,v 1.170 2002/12/12 21:02:25 momjian Exp $
+ * $Id: catversion.h,v 1.171 2003/01/09 20:50:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200212121
+#define CATALOG_VERSION_NO 200301091
#endif
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: primnodes.h,v 1.75 2002/12/14 00:17:59 tgl Exp $
+ * $Id: primnodes.h,v 1.76 2003/01/09 20:50:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* MULTIEXPR and EXPR require the subselect to deliver only one row.
* ALL, ANY, and MULTIEXPR require the combining operators to deliver boolean
* results. These are reduced to one result per row using OR or AND semantics
- * depending on the "useor" flag. ALL and ANY combine the per-row results
+ * depending on the "useOr" flag. ALL and ANY combine the per-row results
* using AND and OR semantics respectively.
*
* SubLink is classed as an Expr node, but it is not actually executable;
* rewriter.
*
* In EXISTS and EXPR SubLinks, both lefthand and oper are unused and are
- * always NIL. useor is not significant either for these sublink types.
+ * always NIL. useOr is not significant either for these sublink types.
+ *
+ * The operIsEquals field is TRUE when the combining operator was written as
+ * "=" --- if the subLinkType is ANY_SUBLINK, this means the operation is
+ * equivalent to "IN". This case allows special optimizations to be used.
* ----------------
*/
typedef enum SubLinkType
{
Expr xpr;
SubLinkType subLinkType; /* EXISTS, ALL, ANY, MULTIEXPR, EXPR */
- bool useor; /* TRUE to combine column results with
+ bool operIsEquals; /* TRUE if combining operator is "=" */
+ bool useOr; /* TRUE to combine column results with
* "OR" not "AND" */
List *lefthand; /* list of outer-query expressions on the
* left */
Expr xpr;
/* Fields copied from original SubLink: */
SubLinkType subLinkType; /* EXISTS, ALL, ANY, MULTIEXPR, EXPR */
- bool useor; /* TRUE to combine column results with
+ bool useOr; /* TRUE to combine column results with
* "OR" not "AND" */
List *oper; /* list of executable expressions for
* combining operators (with arguments) */