Skip to content

Commit 56be925

Browse files
committed
Further tweaking of raw grammar output to distinguish different inputs.
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.
1 parent 296f3a6 commit 56be925

File tree

5 files changed

+63
-17
lines changed

5 files changed

+63
-17
lines changed

src/backend/nodes/outfuncs.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2516,6 +2516,18 @@ _outAExpr(StringInfo str, const A_Expr *node)
25162516
appendStringInfoString(str, " IN ");
25172517
WRITE_NODE_FIELD(name);
25182518
break;
2519+
case AEXPR_LIKE:
2520+
appendStringInfoString(str, " LIKE ");
2521+
WRITE_NODE_FIELD(name);
2522+
break;
2523+
case AEXPR_ILIKE:
2524+
appendStringInfoString(str, " ILIKE ");
2525+
WRITE_NODE_FIELD(name);
2526+
break;
2527+
case AEXPR_SIMILAR:
2528+
appendStringInfoString(str, " SIMILAR ");
2529+
WRITE_NODE_FIELD(name);
2530+
break;
25192531
case AEXPR_BETWEEN:
25202532
appendStringInfoString(str, " BETWEEN ");
25212533
WRITE_NODE_FIELD(name);

src/backend/parser/gram.y

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11220,69 +11220,89 @@ a_expr: c_expr { $$ = $1; }
1122011220
{ $$ = makeNotExpr($2, @1); }
1122111221

1122211222
| a_expr LIKE a_expr
11223-
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, $3, @2); }
11223+
{
11224+
$$ = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "~~",
11225+
$1, $3, @2);
11226+
}
1122411227
| a_expr LIKE a_expr ESCAPE a_expr
1122511228
{
1122611229
FuncCall *n = makeFuncCall(SystemFuncName("like_escape"),
1122711230
list_make2($3, $5),
1122811231
@2);
11229-
$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, (Node *) n, @2);
11232+
$$ = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "~~",
11233+
$1, (Node *) n, @2);
1123011234
}
1123111235
| a_expr NOT LIKE a_expr
11232-
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, $4, @2); }
11236+
{
11237+
$$ = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "!~~",
11238+
$1, $4, @2);
11239+
}
1123311240
| a_expr NOT LIKE a_expr ESCAPE a_expr
1123411241
{
1123511242
FuncCall *n = makeFuncCall(SystemFuncName("like_escape"),
1123611243
list_make2($4, $6),
1123711244
@2);
11238-
$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, (Node *) n, @2);
11245+
$$ = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "!~~",
11246+
$1, (Node *) n, @2);
1123911247
}
1124011248
| a_expr ILIKE a_expr
11241-
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, $3, @2); }
11249+
{
11250+
$$ = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "~~*",
11251+
$1, $3, @2);
11252+
}
1124211253
| a_expr ILIKE a_expr ESCAPE a_expr
1124311254
{
1124411255
FuncCall *n = makeFuncCall(SystemFuncName("like_escape"),
1124511256
list_make2($3, $5),
1124611257
@2);
11247-
$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, (Node *) n, @2);
11258+
$$ = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "~~*",
11259+
$1, (Node *) n, @2);
1124811260
}
1124911261
| a_expr NOT ILIKE a_expr
11250-
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, $4, @2); }
11262+
{
11263+
$$ = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "!~~*",
11264+
$1, $4, @2);
11265+
}
1125111266
| a_expr NOT ILIKE a_expr ESCAPE a_expr
1125211267
{
1125311268
FuncCall *n = makeFuncCall(SystemFuncName("like_escape"),
1125411269
list_make2($4, $6),
1125511270
@2);
11256-
$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, (Node *) n, @2);
11271+
$$ = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "!~~*",
11272+
$1, (Node *) n, @2);
1125711273
}
1125811274

1125911275
| a_expr SIMILAR TO a_expr %prec SIMILAR
1126011276
{
1126111277
FuncCall *n = makeFuncCall(SystemFuncName("similar_escape"),
1126211278
list_make2($4, makeNullAConst(-1)),
1126311279
@2);
11264-
$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2);
11280+
$$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "~",
11281+
$1, (Node *) n, @2);
1126511282
}
1126611283
| a_expr SIMILAR TO a_expr ESCAPE a_expr
1126711284
{
1126811285
FuncCall *n = makeFuncCall(SystemFuncName("similar_escape"),
1126911286
list_make2($4, $6),
1127011287
@2);
11271-
$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2);
11288+
$$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "~",
11289+
$1, (Node *) n, @2);
1127211290
}
1127311291
| a_expr NOT SIMILAR TO a_expr %prec SIMILAR
1127411292
{
1127511293
FuncCall *n = makeFuncCall(SystemFuncName("similar_escape"),
1127611294
list_make2($5, makeNullAConst(-1)),
1127711295
@2);
11278-
$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2);
11296+
$$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "!~",
11297+
$1, (Node *) n, @2);
1127911298
}
1128011299
| a_expr NOT SIMILAR TO a_expr ESCAPE a_expr
1128111300
{
1128211301
FuncCall *n = makeFuncCall(SystemFuncName("similar_escape"),
1128311302
list_make2($5, $7),
1128411303
@2);
11285-
$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2);
11304+
$$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "!~",
11305+
$1, (Node *) n, @2);
1128611306
}
1128711307

1128811308
/* NullTest clause
@@ -11450,7 +11470,7 @@ a_expr: c_expr { $$ = $1; }
1145011470
n->subLinkType = ANY_SUBLINK;
1145111471
n->subLinkId = 0;
1145211472
n->testexpr = $1;
11453-
n->operName = list_make1(makeString("="));
11473+
n->operName = NIL; /* show it's IN not = ANY */
1145411474
n->location = @2;
1145511475
$$ = (Node *)n;
1145611476
}
@@ -11471,9 +11491,9 @@ a_expr: c_expr { $$ = $1; }
1147111491
n->subLinkType = ANY_SUBLINK;
1147211492
n->subLinkId = 0;
1147311493
n->testexpr = $1;
11474-
n->operName = list_make1(makeString("="));
11475-
n->location = @3;
11476-
/* Stick a NOT on top */
11494+
n->operName = NIL; /* show it's IN not = ANY */
11495+
n->location = @2;
11496+
/* Stick a NOT on top; must have same parse location */
1147711497
$$ = makeNotExpr((Node *) n, @2);
1147811498
}
1147911499
else

src/backend/parser/parse_expr.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,12 @@ transformExprRecurse(ParseState *pstate, Node *expr)
182182
case AEXPR_IN:
183183
result = transformAExprIn(pstate, a);
184184
break;
185+
case AEXPR_LIKE:
186+
case AEXPR_ILIKE:
187+
case AEXPR_SIMILAR:
188+
/* we can transform these just like AEXPR_OP */
189+
result = transformAExprOp(pstate, a);
190+
break;
185191
case AEXPR_BETWEEN:
186192
case AEXPR_NOT_BETWEEN:
187193
case AEXPR_BETWEEN_SYM:
@@ -1648,6 +1654,12 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
16481654
List *right_list;
16491655
ListCell *l;
16501656

1657+
/*
1658+
* If the source was "x IN (select)", convert to "x = ANY (select)".
1659+
*/
1660+
if (sublink->operName == NIL)
1661+
sublink->operName = list_make1(makeString("="));
1662+
16511663
/*
16521664
* Transform lefthand expression, and convert to a list
16531665
*/

src/include/nodes/parsenodes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,9 @@ typedef enum A_Expr_Kind
233233
AEXPR_NULLIF, /* NULLIF - name must be "=" */
234234
AEXPR_OF, /* IS [NOT] OF - name must be "=" or "<>" */
235235
AEXPR_IN, /* [NOT] IN - name must be "=" or "<>" */
236+
AEXPR_LIKE, /* [NOT] LIKE - name must be "~~" or "!~~" */
237+
AEXPR_ILIKE, /* [NOT] ILIKE - name must be "~~*" or "!~~*" */
238+
AEXPR_SIMILAR, /* [NOT] SIMILAR - name must be "~" or "!~" */
236239
AEXPR_BETWEEN, /* name must be "BETWEEN" */
237240
AEXPR_NOT_BETWEEN, /* name must be "NOT BETWEEN" */
238241
AEXPR_BETWEEN_SYM, /* name must be "BETWEEN SYMMETRIC" */

src/include/nodes/primnodes.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -994,7 +994,6 @@ typedef struct MinMaxExpr
994994
* Note: result type/typmod/collation are not stored, but can be deduced
995995
* from the XmlExprOp. The type/typmod fields are just used for display
996996
* purposes, and are NOT necessarily the true result type of the node.
997-
* (We also use type == InvalidOid to mark a not-yet-parse-analyzed XmlExpr.)
998997
*/
999998
typedef enum XmlExprOp
1000999
{

0 commit comments

Comments
 (0)