Commit 6bc61fc0 authored by Tom Lane's avatar Tom Lane

Adjust parser so that 'x NOT IN (subselect)' is converted to

'NOT (x IN (subselect))', that is 'NOT (x = ANY (subselect))',
rather than 'x <> ALL (subselect)' as we formerly did.  This
opens the door to optimizing NOT IN the same way as IN, whereas
there's no hope of optimizing the expression using <>.  Also,
convert 'x <> ALL (subselect)' to the NOT(IN) style, so that
the optimization will be available when processing rules dumped
by older Postgres versions.
initdb forced due to small change in SubLink node representation.
parent 59779c81
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -37,7 +37,7 @@ ExecSubPlan(SubPlanState *node, ...@@ -37,7 +37,7 @@ ExecSubPlan(SubPlanState *node,
SubPlan *subplan = (SubPlan *) node->xprstate.expr; SubPlan *subplan = (SubPlan *) node->xprstate.expr;
PlanState *planstate = node->planstate; PlanState *planstate = node->planstate;
SubLinkType subLinkType = subplan->subLinkType; SubLinkType subLinkType = subplan->subLinkType;
bool useor = subplan->useor; bool useOr = subplan->useOr;
MemoryContext oldcontext; MemoryContext oldcontext;
TupleTableSlot *slot; TupleTableSlot *slot;
Datum result; Datum result;
...@@ -84,7 +84,7 @@ ExecSubPlan(SubPlanState *node, ...@@ -84,7 +84,7 @@ ExecSubPlan(SubPlanState *node,
* For all sublink types except EXPR_SUBLINK, the result is boolean as * For all sublink types except EXPR_SUBLINK, the result is boolean as
* are the results of the combining operators. We combine results * are the results of the combining operators. We combine results
* within a tuple (if there are multiple columns) using OR semantics * 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 * across tuples (if the subplan produces more than one) using OR
* semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK. * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK.
* (MULTIEXPR_SUBLINK doesn't allow multiple tuples from the subplan.) * (MULTIEXPR_SUBLINK doesn't allow multiple tuples from the subplan.)
...@@ -107,7 +107,7 @@ ExecSubPlan(SubPlanState *node, ...@@ -107,7 +107,7 @@ ExecSubPlan(SubPlanState *node,
{ {
HeapTuple tup = slot->val; HeapTuple tup = slot->val;
TupleDesc tdesc = slot->ttc_tupleDescriptor; TupleDesc tdesc = slot->ttc_tupleDescriptor;
Datum rowresult = BoolGetDatum(!useor); Datum rowresult = BoolGetDatum(!useOr);
bool rownull = false; bool rownull = false;
int col = 1; int col = 1;
...@@ -212,7 +212,7 @@ ExecSubPlan(SubPlanState *node, ...@@ -212,7 +212,7 @@ ExecSubPlan(SubPlanState *node,
rowresult = expresult; rowresult = expresult;
rownull = expnull; rownull = expnull;
} }
else if (useor) else if (useOr)
{ {
/* combine within row per OR semantics */ /* combine within row per OR semantics */
if (expnull) if (expnull)
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -809,7 +809,8 @@ _copySubLink(SubLink *from) ...@@ -809,7 +809,8 @@ _copySubLink(SubLink *from)
SubLink *newnode = makeNode(SubLink); SubLink *newnode = makeNode(SubLink);
COPY_SCALAR_FIELD(subLinkType); COPY_SCALAR_FIELD(subLinkType);
COPY_SCALAR_FIELD(useor); COPY_SCALAR_FIELD(operIsEquals);
COPY_SCALAR_FIELD(useOr);
COPY_NODE_FIELD(lefthand); COPY_NODE_FIELD(lefthand);
COPY_NODE_FIELD(oper); COPY_NODE_FIELD(oper);
COPY_NODE_FIELD(subselect); COPY_NODE_FIELD(subselect);
...@@ -826,7 +827,7 @@ _copySubPlan(SubPlan *from) ...@@ -826,7 +827,7 @@ _copySubPlan(SubPlan *from)
SubPlan *newnode = makeNode(SubPlan); SubPlan *newnode = makeNode(SubPlan);
COPY_SCALAR_FIELD(subLinkType); COPY_SCALAR_FIELD(subLinkType);
COPY_SCALAR_FIELD(useor); COPY_SCALAR_FIELD(useOr);
COPY_NODE_FIELD(oper); COPY_NODE_FIELD(oper);
COPY_NODE_FIELD(plan); COPY_NODE_FIELD(plan);
COPY_SCALAR_FIELD(plan_id); COPY_SCALAR_FIELD(plan_id);
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -287,7 +287,8 @@ static bool ...@@ -287,7 +287,8 @@ static bool
_equalSubLink(SubLink *a, SubLink *b) _equalSubLink(SubLink *a, SubLink *b)
{ {
COMPARE_SCALAR_FIELD(subLinkType); COMPARE_SCALAR_FIELD(subLinkType);
COMPARE_SCALAR_FIELD(useor); COMPARE_SCALAR_FIELD(operIsEquals);
COMPARE_SCALAR_FIELD(useOr);
COMPARE_NODE_FIELD(lefthand); COMPARE_NODE_FIELD(lefthand);
COMPARE_NODE_FIELD(oper); COMPARE_NODE_FIELD(oper);
COMPARE_NODE_FIELD(subselect); COMPARE_NODE_FIELD(subselect);
...@@ -299,7 +300,7 @@ static bool ...@@ -299,7 +300,7 @@ static bool
_equalSubPlan(SubPlan *a, SubPlan *b) _equalSubPlan(SubPlan *a, SubPlan *b)
{ {
COMPARE_SCALAR_FIELD(subLinkType); COMPARE_SCALAR_FIELD(subLinkType);
COMPARE_SCALAR_FIELD(useor); COMPARE_SCALAR_FIELD(useOr);
COMPARE_NODE_FIELD(oper); COMPARE_NODE_FIELD(oper);
/* should compare plans, but have to settle for comparing plan IDs */ /* should compare plans, but have to settle for comparing plan IDs */
COMPARE_SCALAR_FIELD(plan_id); COMPARE_SCALAR_FIELD(plan_id);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
...@@ -658,7 +658,8 @@ _outSubLink(StringInfo str, SubLink *node) ...@@ -658,7 +658,8 @@ _outSubLink(StringInfo str, SubLink *node)
WRITE_NODE_TYPE("SUBLINK"); WRITE_NODE_TYPE("SUBLINK");
WRITE_ENUM_FIELD(subLinkType, SubLinkType); WRITE_ENUM_FIELD(subLinkType, SubLinkType);
WRITE_BOOL_FIELD(useor); WRITE_BOOL_FIELD(operIsEquals);
WRITE_BOOL_FIELD(useOr);
WRITE_NODE_FIELD(lefthand); WRITE_NODE_FIELD(lefthand);
WRITE_NODE_FIELD(oper); WRITE_NODE_FIELD(oper);
WRITE_NODE_FIELD(subselect); WRITE_NODE_FIELD(subselect);
...@@ -670,7 +671,7 @@ _outSubPlan(StringInfo str, SubPlan *node) ...@@ -670,7 +671,7 @@ _outSubPlan(StringInfo str, SubPlan *node)
WRITE_NODE_TYPE("SUBPLAN"); WRITE_NODE_TYPE("SUBPLAN");
WRITE_ENUM_FIELD(subLinkType, SubLinkType); WRITE_ENUM_FIELD(subLinkType, SubLinkType);
WRITE_BOOL_FIELD(useor); WRITE_BOOL_FIELD(useOr);
WRITE_NODE_FIELD(oper); WRITE_NODE_FIELD(oper);
WRITE_NODE_FIELD(plan); WRITE_NODE_FIELD(plan);
WRITE_INT_FIELD(plan_id); WRITE_INT_FIELD(plan_id);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Path and Plan nodes do not have any readfuncs support, because we * Path and Plan nodes do not have any readfuncs support, because we
...@@ -531,7 +531,8 @@ _readSubLink(void) ...@@ -531,7 +531,8 @@ _readSubLink(void)
READ_LOCALS(SubLink); READ_LOCALS(SubLink);
READ_ENUM_FIELD(subLinkType, SubLinkType); READ_ENUM_FIELD(subLinkType, SubLinkType);
READ_BOOL_FIELD(useor); READ_BOOL_FIELD(operIsEquals);
READ_BOOL_FIELD(useOr);
READ_NODE_FIELD(lefthand); READ_NODE_FIELD(lefthand);
READ_NODE_FIELD(oper); READ_NODE_FIELD(oper);
READ_NODE_FIELD(subselect); READ_NODE_FIELD(subselect);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -225,7 +225,7 @@ make_subplan(SubLink *slink, List *lefthand) ...@@ -225,7 +225,7 @@ make_subplan(SubLink *slink, List *lefthand)
* Fill in other fields of the SubPlan node. * Fill in other fields of the SubPlan node.
*/ */
node->subLinkType = slink->subLinkType; node->subLinkType = slink->subLinkType;
node->useor = slink->useor; node->useOr = slink->useOr;
node->oper = NIL; node->oper = NIL;
node->setParam = NIL; node->setParam = NIL;
node->parParam = NIL; node->parParam = NIL;
...@@ -283,7 +283,7 @@ make_subplan(SubLink *slink, List *lefthand) ...@@ -283,7 +283,7 @@ make_subplan(SubLink *slink, List *lefthand)
&node->setParam); &node->setParam);
PlannerInitPlan = lappend(PlannerInitPlan, node); PlannerInitPlan = lappend(PlannerInitPlan, node);
if (length(oper) > 1) if (length(oper) > 1)
result = (Node *) (node->useor ? make_orclause(oper) : result = (Node *) (node->useOr ? make_orclause(oper) :
make_andclause(oper)); make_andclause(oper));
else else
result = (Node *) lfirst(oper); result = (Node *) lfirst(oper);
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * 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 * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -5420,28 +5420,30 @@ opt_interval: ...@@ -5420,28 +5420,30 @@ opt_interval:
/* Expressions using row descriptors /* Expressions using row descriptors
* Define row_descriptor to allow yacc to break the reduce/reduce conflict * Define row_descriptor to allow yacc to break the reduce/reduce conflict
* with singleton expressions. Use SQL99's ROW keyword to allow rows of * with singleton expressions. Use SQL99's ROW keyword to allow rows of
* one element. * one element.
*/ */
r_expr: row IN_P select_with_parens r_expr: row IN_P select_with_parens
{ {
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->lefthand = $1; n->lefthand = $1;
n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL); n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL);
n->useor = FALSE;
n->subLinkType = ANY_SUBLINK; n->subLinkType = ANY_SUBLINK;
/* operIsEquals and useOr will be set later */
n->subselect = $3; n->subselect = $3;
$$ = (Node *)n; $$ = (Node *)n;
} }
| row NOT IN_P select_with_parens | row NOT IN_P select_with_parens
{ {
/* Make an IN node */
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->lefthand = $1; n->lefthand = $1;
n->oper = (List *) makeSimpleA_Expr(OP, "<>", NULL, NULL); n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL);
n->useor = TRUE; n->subLinkType = ANY_SUBLINK;
n->subLinkType = ALL_SUBLINK; /* operIsEquals and useOr will be set later */
n->subselect = $4; 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 | row qual_all_Op sub_type select_with_parens
%prec Op %prec Op
...@@ -5449,11 +5451,8 @@ r_expr: row IN_P select_with_parens ...@@ -5449,11 +5451,8 @@ r_expr: row IN_P select_with_parens
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->lefthand = $1; n->lefthand = $1;
n->oper = (List *) makeA_Expr(OP, $2, NULL, NULL); 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; n->subLinkType = $3;
/* operIsEquals and useOr will be set later */
n->subselect = $4; n->subselect = $4;
$$ = (Node *)n; $$ = (Node *)n;
} }
...@@ -5463,11 +5462,8 @@ r_expr: row IN_P select_with_parens ...@@ -5463,11 +5462,8 @@ r_expr: row IN_P select_with_parens
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->lefthand = $1; n->lefthand = $1;
n->oper = (List *) makeA_Expr(OP, $2, NULL, NULL); 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; n->subLinkType = MULTIEXPR_SUBLINK;
/* operIsEquals and useOr will be set later */
n->subselect = $3; n->subselect = $3;
$$ = (Node *)n; $$ = (Node *)n;
} }
...@@ -5850,8 +5846,8 @@ a_expr: c_expr { $$ = $1; } ...@@ -5850,8 +5846,8 @@ a_expr: c_expr { $$ = $1; }
SubLink *n = (SubLink *)$3; SubLink *n = (SubLink *)$3;
n->lefthand = makeList1($1); n->lefthand = makeList1($1);
n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL); n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL);
n->useor = FALSE;
n->subLinkType = ANY_SUBLINK; n->subLinkType = ANY_SUBLINK;
/* operIsEquals and useOr will be set later */
$$ = (Node *)n; $$ = (Node *)n;
} }
else else
...@@ -5875,12 +5871,14 @@ a_expr: c_expr { $$ = $1; } ...@@ -5875,12 +5871,14 @@ a_expr: c_expr { $$ = $1; }
/* in_expr returns a SubLink or a list of a_exprs */ /* in_expr returns a SubLink or a list of a_exprs */
if (IsA($4, SubLink)) if (IsA($4, SubLink))
{ {
/* Make an IN node */
SubLink *n = (SubLink *)$4; SubLink *n = (SubLink *)$4;
n->lefthand = makeList1($1); n->lefthand = makeList1($1);
n->oper = (List *) makeSimpleA_Expr(OP, "<>", NULL, NULL); n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL);
n->useor = FALSE; n->subLinkType = ANY_SUBLINK;
n->subLinkType = ALL_SUBLINK; /* operIsEquals and useOr will be set later */
$$ = (Node *)n; /* Stick a NOT on top */
$$ = (Node *) makeA_Expr(NOT, NIL, NULL, (Node *) n);
} }
else else
{ {
...@@ -5903,8 +5901,8 @@ a_expr: c_expr { $$ = $1; } ...@@ -5903,8 +5901,8 @@ a_expr: c_expr { $$ = $1; }
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->lefthand = makeList1($1); n->lefthand = makeList1($1);
n->oper = (List *) makeA_Expr(OP, $2, NULL, NULL); n->oper = (List *) makeA_Expr(OP, $2, NULL, NULL);
n->useor = FALSE; /* doesn't matter since only one col */
n->subLinkType = $3; n->subLinkType = $3;
/* operIsEquals and useOr will be set later */
n->subselect = $4; n->subselect = $4;
$$ = (Node *)n; $$ = (Node *)n;
} }
...@@ -6447,7 +6445,6 @@ c_expr: columnref { $$ = (Node *) $1; } ...@@ -6447,7 +6445,6 @@ c_expr: columnref { $$ = (Node *) $1; }
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->lefthand = NIL; n->lefthand = NIL;
n->oper = NIL; n->oper = NIL;
n->useor = FALSE;
n->subLinkType = EXPR_SUBLINK; n->subLinkType = EXPR_SUBLINK;
n->subselect = $1; n->subselect = $1;
$$ = (Node *)n; $$ = (Node *)n;
...@@ -6457,7 +6454,6 @@ c_expr: columnref { $$ = (Node *) $1; } ...@@ -6457,7 +6454,6 @@ c_expr: columnref { $$ = (Node *) $1; }
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->lefthand = NIL; n->lefthand = NIL;
n->oper = NIL; n->oper = NIL;
n->useor = FALSE;
n->subLinkType = EXISTS_SUBLINK; n->subLinkType = EXISTS_SUBLINK;
n->subselect = $2; n->subselect = $2;
$$ = (Node *)n; $$ = (Node *)n;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -367,6 +367,8 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -367,6 +367,8 @@ transformExpr(ParseState *pstate, Node *expr)
*/ */
sublink->lefthand = NIL; sublink->lefthand = NIL;
sublink->oper = NIL; sublink->oper = NIL;
sublink->operIsEquals = FALSE;
sublink->useOr = FALSE;
} }
else if (sublink->subLinkType == EXPR_SUBLINK) else if (sublink->subLinkType == EXPR_SUBLINK)
{ {
...@@ -391,27 +393,60 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -391,27 +393,60 @@ transformExpr(ParseState *pstate, Node *expr)
*/ */
sublink->lefthand = NIL; sublink->lefthand = NIL;
sublink->oper = NIL; sublink->oper = NIL;
sublink->operIsEquals = FALSE;
sublink->useOr = FALSE;
} }
else else
{ {
/* ALL, ANY, or MULTIEXPR: generate operator list */ /* ALL, ANY, or MULTIEXPR: generate operator list */
List *left_list = sublink->lefthand; List *left_list = sublink->lefthand;
List *right_list = qtree->targetList; List *right_list = qtree->targetList;
int row_length = length(left_list);
bool needNot = false;
List *op; List *op;
char *opname; char *opname;
List *elist; List *elist;
/* transform lefthand expressions */
foreach(elist, left_list) foreach(elist, left_list)
lfirst(elist) = transformExpr(pstate, lfirst(elist)); lfirst(elist) = transformExpr(pstate, lfirst(elist));
/* get the combining-operator name */
Assert(IsA(sublink->oper, A_Expr)); Assert(IsA(sublink->oper, A_Expr));
op = ((A_Expr *) sublink->oper)->name; op = ((A_Expr *) sublink->oper)->name;
opname = strVal(llast(op)); opname = strVal(llast(op));
sublink->oper = NIL; 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... */ /* Combining operators other than =/<> is dubious... */
if (length(left_list) != 1 && if (row_length != 1 &&
strcmp(opname, "=") != 0 && strcmp(opname, "<>") != 0) strcmp(opname, "=") != 0 &&
strcmp(opname, "<>") != 0)
elog(ERROR, "Row comparison cannot use operator %s", elog(ERROR, "Row comparison cannot use operator %s",
opname); opname);
...@@ -474,6 +509,13 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -474,6 +509,13 @@ transformExpr(ParseState *pstate, Node *expr)
} }
if (left_list != NIL) if (left_list != NIL)
elog(ERROR, "Subselect has too few fields"); 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; result = (Node *) expr;
break; break;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* back to source text * back to source text
* *
* IDENTIFICATION * 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. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -2660,8 +2660,16 @@ get_sublink_expr(SubLink *sublink, deparse_context *context) ...@@ -2660,8 +2660,16 @@ get_sublink_expr(SubLink *sublink, deparse_context *context)
break; break;
case ANY_SUBLINK: case ANY_SUBLINK:
oper = (OpExpr *) lfirst(sublink->oper); if (sublink->operIsEquals)
appendStringInfo(buf, "%s ANY ", get_opname(oper->opno)); {
/* Represent it as IN */
appendStringInfo(buf, "IN ");
}
else
{
oper = (OpExpr *) lfirst(sublink->oper);
appendStringInfo(buf, "%s ANY ", get_opname(oper->opno));
}
break; break;
case ALL_SUBLINK: case ALL_SUBLINK:
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200212121 #define CATALOG_VERSION_NO 200301091
#endif #endif
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -374,7 +374,7 @@ typedef struct BoolExpr ...@@ -374,7 +374,7 @@ typedef struct BoolExpr
* MULTIEXPR and EXPR require the subselect to deliver only one row. * MULTIEXPR and EXPR require the subselect to deliver only one row.
* ALL, ANY, and MULTIEXPR require the combining operators to deliver boolean * 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 * 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. * using AND and OR semantics respectively.
* *
* SubLink is classed as an Expr node, but it is not actually executable; * SubLink is classed as an Expr node, but it is not actually executable;
...@@ -395,7 +395,11 @@ typedef struct BoolExpr ...@@ -395,7 +395,11 @@ typedef struct BoolExpr
* rewriter. * rewriter.
* *
* In EXISTS and EXPR SubLinks, both lefthand and oper are unused and are * 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 typedef enum SubLinkType
...@@ -408,7 +412,8 @@ typedef struct SubLink ...@@ -408,7 +412,8 @@ typedef struct SubLink
{ {
Expr xpr; Expr xpr;
SubLinkType subLinkType; /* EXISTS, ALL, ANY, MULTIEXPR, EXPR */ 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" */ * "OR" not "AND" */
List *lefthand; /* list of outer-query expressions on the List *lefthand; /* list of outer-query expressions on the
* left */ * left */
...@@ -446,7 +451,7 @@ typedef struct SubPlan ...@@ -446,7 +451,7 @@ typedef struct SubPlan
Expr xpr; Expr xpr;
/* Fields copied from original SubLink: */ /* Fields copied from original SubLink: */
SubLinkType subLinkType; /* EXISTS, ALL, ANY, MULTIEXPR, EXPR */ 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" */ * "OR" not "AND" */
List *oper; /* list of executable expressions for List *oper; /* list of executable expressions for
* combining operators (with arguments) */ * combining operators (with arguments) */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment