diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2003-01-09 20:50:53 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2003-01-09 20:50:53 +0000 |
commit | 6bc61fc046961cfc2b3901ab38ac74b45f8c6cd3 (patch) | |
tree | a29a0825d52ba55e9971b8df6c4a530cc90a5bff /src/backend/parser/parse_expr.c | |
parent | 59779c81ba9e6ea29cec1a59d0cfdbe76fa016ff (diff) | |
download | postgresql-6bc61fc046961cfc2b3901ab38ac74b45f8c6cd3.tar.gz postgresql-6bc61fc046961cfc2b3901ab38ac74b45f8c6cd3.zip |
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.
Diffstat (limited to 'src/backend/parser/parse_expr.c')
-rw-r--r-- | src/backend/parser/parse_expr.c | 48 |
1 files changed, 45 insertions, 3 deletions
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; |