summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvvvv <[email protected]>2023-06-14 19:59:08 +0300
committervvvv <[email protected]>2023-06-14 19:59:08 +0300
commit1f28f637f5097f6ee7835de829bf4a6947849d00 (patch)
treecaed48a9b853f0087feaafda299ed42ad3ecc563
parent3f3f15f2e06a1f183d72c229cacf1d0f8949aa57 (diff)
Optimizers for PgLike to avoid Re2 if possible
-rw-r--r--ydb/library/yql/core/common_opt/yql_co_pgselect.cpp53
1 files changed, 53 insertions, 0 deletions
diff --git a/ydb/library/yql/core/common_opt/yql_co_pgselect.cpp b/ydb/library/yql/core/common_opt/yql_co_pgselect.cpp
index 7b6dbd9dfaf..7b12850f891 100644
--- a/ydb/library/yql/core/common_opt/yql_co_pgselect.cpp
+++ b/ydb/library/yql/core/common_opt/yql_co_pgselect.cpp
@@ -3240,6 +3240,59 @@ TExprNode::TPtr ExpandPgSelectSublink(const TExprNode::TPtr& node, TExprContext&
TExprNode::TPtr ExpandPgLike(const TExprNode::TPtr& node, TExprContext& ctx, TOptimizeContext& optCtx) {
Y_UNUSED(optCtx);
const bool insensitive = node->IsCallable("PgILike");
+ if (!insensitive) {
+ auto pattern = node->Child(1);
+ if (pattern->IsCallable("PgConst") &&
+ pattern->Tail().IsCallable("PgType") &&
+ pattern->Tail().Head().Content() == "text") {
+ auto str = pattern->Head().Content();
+ auto hasUnderscore = AnyOf(str, [](char c) { return c == '_'; });
+ size_t countOfPercents = 0;
+ ForEach(str.begin(), str.end(), [&](char c) { countOfPercents += (c == '%');});
+ if (!hasUnderscore && countOfPercents == 0) {
+ return ctx.Builder(node->Pos())
+ .Callable("PgOp")
+ .Atom(0, "=")
+ .Add(1, node->ChildPtr(0))
+ .Add(2, pattern)
+ .Seal()
+ .Build();
+ }
+
+ TStringBuf op;
+ TStringBuf arg;
+ if (!hasUnderscore && countOfPercents == 1 && str.StartsWith('%')) {
+ op = "EndsWith";
+ arg = str.SubString(1, str.Size() - 1);
+ }
+
+ if (!hasUnderscore && countOfPercents == 1 && str.EndsWith('%')) {
+ op = "StartsWith";
+ arg = str.SubString(0, str.Size() - 1);
+ }
+
+ if (!hasUnderscore && countOfPercents == 2 && str.StartsWith('%') && str.EndsWith('%')) {
+ op = "StringContains";
+ arg = str.SubString(1, str.Size() - 2);
+ }
+
+ if (!op.empty()) {
+ return ctx.Builder(node->Pos())
+ .Callable("ToPg")
+ .Callable(0, op)
+ .Callable(0, "FromPg")
+ .Add(0, node->ChildPtr(0))
+ .Seal()
+ .Callable(1, "String")
+ .Atom(0, arg)
+ .Seal()
+ .Seal()
+ .Seal()
+ .Build();
+ }
+ }
+ }
+
auto matcher = ctx.Builder(node->Pos())
.Callable("Udf")
.Atom(0, "Re2.Match")