diff options
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/gram.y | 44 | ||||
-rw-r--r-- | src/backend/parser/parse_expr.c | 48 |
2 files changed, 65 insertions, 27 deletions
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; |