diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index 5a6950e0bee..c9a02814bff 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 - * $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, 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; @@ -84,7 +84,7 @@ ExecSubPlan(SubPlanState *node, * 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.) @@ -107,7 +107,7 @@ ExecSubPlan(SubPlanState *node, { HeapTuple tup = slot->val; TupleDesc tdesc = slot->ttc_tupleDescriptor; - Datum rowresult = BoolGetDatum(!useor); + Datum rowresult = BoolGetDatum(!useOr); bool rownull = false; int col = 1; @@ -212,7 +212,7 @@ ExecSubPlan(SubPlanState *node, rowresult = expresult; rownull = expnull; } - else if (useor) + else if (useOr) { /* combine within row per OR semantics */ if (expnull) diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index c3abcfc9e80..4b326b75224 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -809,7 +809,8 @@ _copySubLink(SubLink *from) 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); @@ -826,7 +827,7 @@ _copySubPlan(SubPlan *from) 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); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 5fc333df3de..affa7f48a88 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -18,7 +18,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -287,7 +287,8 @@ static bool _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); @@ -299,7 +300,7 @@ static bool _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); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 97fc9462a27..204c00ad674 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -8,7 +8,7 @@ * * * 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* @@ -658,7 +658,8 @@ _outSubLink(StringInfo str, SubLink *node) 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); @@ -670,7 +671,7 @@ _outSubPlan(StringInfo str, SubPlan *node) 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); diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 9ecd40f2e1d..99afc0438c3 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -8,7 +8,7 @@ * * * 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 @@ -531,7 +531,8 @@ _readSubLink(void) 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); diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 840ba975a34..f8086d9ab6e 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -225,7 +225,7 @@ make_subplan(SubLink *slink, List *lefthand) * 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; @@ -283,7 +283,7 @@ make_subplan(SubLink *slink, List *lefthand) &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); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 1809d515461..7626fe0e449 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * 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 @@ -5420,28 +5420,30 @@ opt_interval: /* 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 @@ -5449,11 +5451,8 @@ r_expr: row IN_P select_with_parens 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; } @@ -5463,11 +5462,8 @@ r_expr: row IN_P select_with_parens 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; } @@ -5850,8 +5846,8 @@ a_expr: c_expr { $$ = $1; } 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 @@ -5875,12 +5871,14 @@ a_expr: c_expr { $$ = $1; } /* 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 { @@ -5903,8 +5901,8 @@ a_expr: c_expr { $$ = $1; } 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; } @@ -6447,7 +6445,6 @@ c_expr: columnref { $$ = (Node *) $1; } SubLink *n = makeNode(SubLink); n->lefthand = NIL; n->oper = NIL; - n->useor = FALSE; n->subLinkType = EXPR_SUBLINK; n->subselect = $1; $$ = (Node *)n; @@ -6457,7 +6454,6 @@ c_expr: columnref { $$ = (Node *) $1; } SubLink *n = makeNode(SubLink); n->lefthand = NIL; n->oper = NIL; - n->useor = FALSE; n->subLinkType = EXISTS_SUBLINK; n->subselect = $2; $$ = (Node *)n; diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 9705ca5d7de..3701f41dca0 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * 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) */ sublink->lefthand = NIL; sublink->oper = NIL; + sublink->operIsEquals = FALSE; + sublink->useOr = FALSE; } else if (sublink->subLinkType == EXPR_SUBLINK) { @@ -391,27 +393,60 @@ transformExpr(ParseState *pstate, Node *expr) */ 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); @@ -474,6 +509,13 @@ transformExpr(ParseState *pstate, Node *expr) } 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; diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 0275d8424ac..a8679463670 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -3,7 +3,7 @@ * 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. * @@ -2660,8 +2660,16 @@ get_sublink_expr(SubLink *sublink, deparse_context *context) 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: diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 710b5c71ac8..9c3e5906ade 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200212121 +#define CATALOG_VERSION_NO 200301091 #endif diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 285a0008fdc..d9ea05994dd 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -10,7 +10,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -374,7 +374,7 @@ typedef struct BoolExpr * 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; @@ -395,7 +395,11 @@ typedef struct BoolExpr * 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 @@ -408,7 +412,8 @@ typedef struct SubLink { 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 */ @@ -446,7 +451,7 @@ typedef struct SubPlan 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) */