]> granicus.if.org Git - postgresql/commitdiff
Further tweaking of raw grammar output to distinguish different inputs.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 23 Feb 2015 17:46:46 +0000 (12:46 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 23 Feb 2015 17:46:50 +0000 (12:46 -0500)
Use a different A_Expr_Kind for LIKE/ILIKE/SIMILAR TO constructs, so that
they can be distinguished from direct invocation of the underlying
operators.  Also, postpone selection of the operator name when transforming
"x IN (select)" to "x = ANY (select)", so that those syntaxes can be told
apart at parse analysis time.

I had originally thought I'd also have to do something special for the
syntaxes IS NOT DISTINCT FROM, IS NOT DOCUMENT, and x NOT IN (SELECT...),
which the grammar translates as though they were NOT (construct).
On reflection though, we can distinguish those cases reliably by noting
whether the parse location shown for the NOT is the same as for its child
node.  This only requires tweaking the parse locations for NOT IN, which
I've done here.

These changes should have no effect outside the parser; they're just in
support of being able to give accurate warnings for planned operator
precedence changes.

src/backend/nodes/outfuncs.c
src/backend/parser/gram.y
src/backend/parser/parse_expr.c
src/include/nodes/parsenodes.h
src/include/nodes/primnodes.h

index 98aa5f0310293ef3015162933c4af133295735d9..2f417fee20a16dca7a10ffe274a50204f55c36e6 100644 (file)
@@ -2516,6 +2516,18 @@ _outAExpr(StringInfo str, const A_Expr *node)
                        appendStringInfoString(str, " IN ");
                        WRITE_NODE_FIELD(name);
                        break;
+               case AEXPR_LIKE:
+                       appendStringInfoString(str, " LIKE ");
+                       WRITE_NODE_FIELD(name);
+                       break;
+               case AEXPR_ILIKE:
+                       appendStringInfoString(str, " ILIKE ");
+                       WRITE_NODE_FIELD(name);
+                       break;
+               case AEXPR_SIMILAR:
+                       appendStringInfoString(str, " SIMILAR ");
+                       WRITE_NODE_FIELD(name);
+                       break;
                case AEXPR_BETWEEN:
                        appendStringInfoString(str, " BETWEEN ");
                        WRITE_NODE_FIELD(name);
index 76b0affff069d54476e4e63dec536f7d643a3500..6c21002875394b9b8f04800cc81b994ebafbe705 100644 (file)
@@ -11220,40 +11220,56 @@ a_expr:               c_expr                                                                  { $$ = $1; }
                                { $$ = makeNotExpr($2, @1); }
 
                        | a_expr LIKE a_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, $3, @2); }
+                               {
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "~~",
+                                                                                                  $1, $3, @2);
+                               }
                        | a_expr LIKE a_expr ESCAPE a_expr
                                {
                                        FuncCall *n = makeFuncCall(SystemFuncName("like_escape"),
                                                                                           list_make2($3, $5),
                                                                                           @2);
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, (Node *) n, @2);
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "~~",
+                                                                                                  $1, (Node *) n, @2);
                                }
                        | a_expr NOT LIKE a_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, $4, @2); }
+                               {
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "!~~",
+                                                                                                  $1, $4, @2);
+                               }
                        | a_expr NOT LIKE a_expr ESCAPE a_expr
                                {
                                        FuncCall *n = makeFuncCall(SystemFuncName("like_escape"),
                                                                                           list_make2($4, $6),
                                                                                           @2);
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, (Node *) n, @2);
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "!~~",
+                                                                                                  $1, (Node *) n, @2);
                                }
                        | a_expr ILIKE a_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, $3, @2); }
+                               {
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "~~*",
+                                                                                                  $1, $3, @2);
+                               }
                        | a_expr ILIKE a_expr ESCAPE a_expr
                                {
                                        FuncCall *n = makeFuncCall(SystemFuncName("like_escape"),
                                                                                           list_make2($3, $5),
                                                                                           @2);
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, (Node *) n, @2);
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "~~*",
+                                                                                                  $1, (Node *) n, @2);
                                }
                        | a_expr NOT ILIKE a_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, $4, @2); }
+                               {
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "!~~*",
+                                                                                                  $1, $4, @2);
+                               }
                        | a_expr NOT ILIKE a_expr ESCAPE a_expr
                                {
                                        FuncCall *n = makeFuncCall(SystemFuncName("like_escape"),
                                                                                           list_make2($4, $6),
                                                                                           @2);
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, (Node *) n, @2);
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "!~~*",
+                                                                                                  $1, (Node *) n, @2);
                                }
 
                        | a_expr SIMILAR TO a_expr                              %prec SIMILAR
@@ -11261,28 +11277,32 @@ a_expr:               c_expr                                                                  { $$ = $1; }
                                        FuncCall *n = makeFuncCall(SystemFuncName("similar_escape"),
                                                                                           list_make2($4, makeNullAConst(-1)),
                                                                                           @2);
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2);
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "~",
+                                                                                                  $1, (Node *) n, @2);
                                }
                        | a_expr SIMILAR TO a_expr ESCAPE a_expr
                                {
                                        FuncCall *n = makeFuncCall(SystemFuncName("similar_escape"),
                                                                                           list_make2($4, $6),
                                                                                           @2);
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2);
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "~",
+                                                                                                  $1, (Node *) n, @2);
                                }
                        | a_expr NOT SIMILAR TO a_expr                  %prec SIMILAR
                                {
                                        FuncCall *n = makeFuncCall(SystemFuncName("similar_escape"),
                                                                                           list_make2($5, makeNullAConst(-1)),
                                                                                           @2);
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2);
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "!~",
+                                                                                                  $1, (Node *) n, @2);
                                }
                        | a_expr NOT SIMILAR TO a_expr ESCAPE a_expr
                                {
                                        FuncCall *n = makeFuncCall(SystemFuncName("similar_escape"),
                                                                                           list_make2($5, $7),
                                                                                           @2);
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2);
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "!~",
+                                                                                                  $1, (Node *) n, @2);
                                }
 
                        /* NullTest clause
@@ -11450,7 +11470,7 @@ a_expr:         c_expr                                                                  { $$ = $1; }
                                                n->subLinkType = ANY_SUBLINK;
                                                n->subLinkId = 0;
                                                n->testexpr = $1;
-                                               n->operName = list_make1(makeString("="));
+                                               n->operName = NIL;              /* show it's IN not = ANY */
                                                n->location = @2;
                                                $$ = (Node *)n;
                                        }
@@ -11471,9 +11491,9 @@ a_expr:         c_expr                                                                  { $$ = $1; }
                                                n->subLinkType = ANY_SUBLINK;
                                                n->subLinkId = 0;
                                                n->testexpr = $1;
-                                               n->operName = list_make1(makeString("="));
-                                               n->location = @3;
-                                               /* Stick a NOT on top */
+                                               n->operName = NIL;              /* show it's IN not = ANY */
+                                               n->location = @2;
+                                               /* Stick a NOT on top; must have same parse location */
                                                $$ = makeNotExpr((Node *) n, @2);
                                        }
                                        else
index f314745818b233e159540e3aa3658814a3354027..7829bcbac160b80186736e725d1b0053881be7a3 100644 (file)
@@ -182,6 +182,12 @@ transformExprRecurse(ParseState *pstate, Node *expr)
                                        case AEXPR_IN:
                                                result = transformAExprIn(pstate, a);
                                                break;
+                                       case AEXPR_LIKE:
+                                       case AEXPR_ILIKE:
+                                       case AEXPR_SIMILAR:
+                                               /* we can transform these just like AEXPR_OP */
+                                               result = transformAExprOp(pstate, a);
+                                               break;
                                        case AEXPR_BETWEEN:
                                        case AEXPR_NOT_BETWEEN:
                                        case AEXPR_BETWEEN_SYM:
@@ -1648,6 +1654,12 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
                List       *right_list;
                ListCell   *l;
 
+               /*
+                * If the source was "x IN (select)", convert to "x = ANY (select)".
+                */
+               if (sublink->operName == NIL)
+                       sublink->operName = list_make1(makeString("="));
+
                /*
                 * Transform lefthand expression, and convert to a list
                 */
index d7b6148cd5e26e30656678d87cf1215666141914..ac133023b4f6b750ad43b444bbd9536058f1ed9d 100644 (file)
@@ -233,6 +233,9 @@ typedef enum A_Expr_Kind
        AEXPR_NULLIF,                           /* NULLIF - name must be "=" */
        AEXPR_OF,                                       /* IS [NOT] OF - name must be "=" or "<>" */
        AEXPR_IN,                                       /* [NOT] IN - name must be "=" or "<>" */
+       AEXPR_LIKE,                                     /* [NOT] LIKE - name must be "~~" or "!~~" */
+       AEXPR_ILIKE,                            /* [NOT] ILIKE - name must be "~~*" or "!~~*" */
+       AEXPR_SIMILAR,                          /* [NOT] SIMILAR - name must be "~" or "!~" */
        AEXPR_BETWEEN,                          /* name must be "BETWEEN" */
        AEXPR_NOT_BETWEEN,                      /* name must be "NOT BETWEEN" */
        AEXPR_BETWEEN_SYM,                      /* name must be "BETWEEN SYMMETRIC" */
index b004da6dc4c7d138afd61bcb7b40e7b5bbc17b98..dbc5a35cc8f646d791995a6370cc15e1d1956bdd 100644 (file)
@@ -994,7 +994,6 @@ typedef struct MinMaxExpr
  * Note: result type/typmod/collation are not stored, but can be deduced
  * from the XmlExprOp.  The type/typmod fields are just used for display
  * purposes, and are NOT necessarily the true result type of the node.
- * (We also use type == InvalidOid to mark a not-yet-parse-analyzed XmlExpr.)
  */
 typedef enum XmlExprOp
 {