aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/nodes/outfuncs.c12
-rw-r--r--src/backend/parser/gram.y52
-rw-r--r--src/backend/parser/parse_expr.c12
-rw-r--r--src/include/nodes/parsenodes.h3
-rw-r--r--src/include/nodes/primnodes.h1
5 files changed, 63 insertions, 17 deletions
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 98aa5f03102..2f417fee20a 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -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);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 76b0affff06..6c210028753 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -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
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index f314745818b..7829bcbac16 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -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:
@@ -1649,6 +1655,12 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
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
*/
lefthand = transformExprRecurse(pstate, sublink->testexpr);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index d7b6148cd5e..ac133023b4f 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -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" */
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index b004da6dc4c..dbc5a35cc8f 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -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
{