mirror of
https://github.com/postgres/postgres.git
synced 2025-07-05 07:21:24 +03:00
Fix issues around strictness of SIMILAR TO.
As a result of some long-ago quick hacks, the SIMILAR TO operator and the corresponding flavor of substring() interpreted "ESCAPE NULL" as selecting the default escape character '\'. This is both surprising and not per spec: the standard is clear that these functions should return NULL for NULL input. Additionally, because of inconsistency of the strictness markings of 3-argument substring() and similar_escape(), the planner could not inline the SQL definition of substring(), resulting in a substantial performance penalty compared to the underlying POSIX substring() function. The simplest fix for this would be to change the strictness marking of similar_escape(), but if we do that we risk breaking existing views that depend on that function. Hence, leave similar_escape() as-is as a compatibility function, and instead invent a new function similar_to_escape() that comes in two strict variants. There are a couple of other behaviors in this area that are also not per spec, but they are documented and seem generally at least as sane as the spec's definition, so leave them alone. But improve the documentation to describe them fully. Patch by me; thanks to Álvaro Herrera and Andrew Gierth for review and discussion. Discussion: https://postgr.es/m/14047.1557708214@sss.pgh.pa.us
This commit is contained in:
@ -13073,15 +13073,15 @@ a_expr: c_expr { $$ = $1; }
|
||||
|
||||
| a_expr SIMILAR TO a_expr %prec SIMILAR
|
||||
{
|
||||
FuncCall *n = makeFuncCall(SystemFuncName("similar_escape"),
|
||||
list_make2($4, makeNullAConst(-1)),
|
||||
FuncCall *n = makeFuncCall(SystemFuncName("similar_to_escape"),
|
||||
list_make1($4),
|
||||
@2);
|
||||
$$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "~",
|
||||
$1, (Node *) n, @2);
|
||||
}
|
||||
| a_expr SIMILAR TO a_expr ESCAPE a_expr %prec SIMILAR
|
||||
{
|
||||
FuncCall *n = makeFuncCall(SystemFuncName("similar_escape"),
|
||||
FuncCall *n = makeFuncCall(SystemFuncName("similar_to_escape"),
|
||||
list_make2($4, $6),
|
||||
@2);
|
||||
$$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "~",
|
||||
@ -13089,15 +13089,15 @@ a_expr: c_expr { $$ = $1; }
|
||||
}
|
||||
| a_expr NOT_LA SIMILAR TO a_expr %prec NOT_LA
|
||||
{
|
||||
FuncCall *n = makeFuncCall(SystemFuncName("similar_escape"),
|
||||
list_make2($5, makeNullAConst(-1)),
|
||||
FuncCall *n = makeFuncCall(SystemFuncName("similar_to_escape"),
|
||||
list_make1($5),
|
||||
@2);
|
||||
$$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "!~",
|
||||
$1, (Node *) n, @2);
|
||||
}
|
||||
| a_expr NOT_LA SIMILAR TO a_expr ESCAPE a_expr %prec NOT_LA
|
||||
{
|
||||
FuncCall *n = makeFuncCall(SystemFuncName("similar_escape"),
|
||||
FuncCall *n = makeFuncCall(SystemFuncName("similar_to_escape"),
|
||||
list_make2($5, $7),
|
||||
@2);
|
||||
$$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "!~",
|
||||
@ -14323,9 +14323,9 @@ subquery_Op:
|
||||
| NOT_LA ILIKE
|
||||
{ $$ = list_make1(makeString("!~~*")); }
|
||||
/* cannot put SIMILAR TO here, because SIMILAR TO is a hack.
|
||||
* the regular expression is preprocessed by a function (similar_escape),
|
||||
* the regular expression is preprocessed by a function (similar_to_escape),
|
||||
* and the ~ operator for posix regular expressions is used.
|
||||
* x SIMILAR TO y -> x ~ similar_escape(y)
|
||||
* x SIMILAR TO y -> x ~ similar_to_escape(y)
|
||||
* this transformation is made on the fly by the parser upwards.
|
||||
* however the SubLink structure which handles any/some/all stuff
|
||||
* is not ready for such a thing.
|
||||
|
Reference in New Issue
Block a user