diff --git a/ydb/core/kqp/opt/physical/kqp_opt_phy_olap_filter.cpp b/ydb/core/kqp/opt/physical/kqp_opt_phy_olap_filter.cpp index d34bd9148916..4fcfebf991bb 100644 --- a/ydb/core/kqp/opt/physical/kqp_opt_phy_olap_filter.cpp +++ b/ydb/core/kqp/opt/physical/kqp_opt_phy_olap_filter.cpp @@ -329,6 +329,13 @@ NYql::NNodes::TCoUtf8 RemoveJsonPathUnnecessaryQuote(const NYql::NNodes::TCoUtf8 return node; } +TExprBase UnwrapOptionalTKqpOlapApplyColumnArg(const TExprBase& node) { + if (const auto& maybeColumnArg = node.Maybe()) { + return maybeColumnArg.Cast().ColumnName(); + } + return node; +} + } //namespace std::vector ConvertComparisonNode(const TExprBase& nodeIn, const TExprNode& argument, TExprContext& ctx, TPositionHandle pos, bool allowApply) @@ -351,7 +358,10 @@ std::vector ConvertComparisonNode(const TExprBase& nodeIn, const TExp } if (auto maybeMember = node.Maybe()) { - return maybeMember.Cast().Name(); + return Build(ctx, pos) + .TableRowType(ExpandType(argument.Pos(), *argument.GetTypeAnn(), ctx)) + .ColumnName(maybeMember.Cast().Name()) + .Done(); } if (auto maybeJsonValue = node.Maybe()) { @@ -397,8 +407,8 @@ std::vector ConvertComparisonNode(const TExprBase& nodeIn, const TExp if (const auto params = ExtractBinaryFunctionParameters(arithmetic, argument, ctx, pos, allowApply)) { return Build(ctx, pos) .Operator().Value(arithmetic.Ref().Content(), TNodeFlags::Default).Build() - .Left(params->first) - .Right(params->second) + .Left(UnwrapOptionalTKqpOlapApplyColumnArg(params->first)) + .Right(UnwrapOptionalTKqpOlapApplyColumnArg(params->second)) .Done(); } } @@ -410,7 +420,7 @@ std::vector ConvertComparisonNode(const TExprBase& nodeIn, const TExp YQL_ENSURE(oper.to_lower()); return Build(ctx, pos) .Operator().Value(oper, TNodeFlags::Default).Build() - .Arg(params.front()) + .Arg(UnwrapOptionalTKqpOlapApplyColumnArg(params.front())) .Done(); } } @@ -540,8 +550,8 @@ TExprBase BuildOneElementComparison(const std::pair& param return Build(ctx, pos) .Operator().Value(compareOperator, TNodeFlags::Default).Build() - .Left(parameter.first) - .Right(parameter.second) + .Left(UnwrapOptionalTKqpOlapApplyColumnArg(parameter.first)) + .Right(UnwrapOptionalTKqpOlapApplyColumnArg(parameter.second)) .Done(); } @@ -602,8 +612,8 @@ TMaybeNode ComparisonPushdown(const std::vector(ctx, pos) .Operator().Value("eq", TNodeFlags::Default).Build() - .Left(parameters[j].first) - .Right(parameters[j].second) + .Left(UnwrapOptionalTKqpOlapApplyColumnArg(parameters[j].first)) + .Right(UnwrapOptionalTKqpOlapApplyColumnArg(parameters[j].second)) .Done()); } diff --git a/ydb/core/kqp/opt/physical/predicate_collector.cpp b/ydb/core/kqp/opt/physical/predicate_collector.cpp index 01c6e6d0e0a2..6e4a2aa14e38 100644 --- a/ydb/core/kqp/opt/physical/predicate_collector.cpp +++ b/ydb/core/kqp/opt/physical/predicate_collector.cpp @@ -305,7 +305,7 @@ bool CheckComparisonParametersForPushdown(const TCoCompare& compare, const TExpr } } - if (options.PushdownSubstring) { //EnableSimpleIlikePushdown FF + if (options.PushdownSubstring) { if (IgnoreCaseSubstringMatchFunctions.contains(compare.CallableName())) { const auto& right = compare.Right().Ref(); YQL_ENSURE(right.IsCallable("String") || right.IsCallable("Utf8")); diff --git a/ydb/core/kqp/ut/olap/kqp_olap_ut.cpp b/ydb/core/kqp/ut/olap/kqp_olap_ut.cpp index bcdc56e38098..06a279d24d34 100644 --- a/ydb/core/kqp/ut/olap/kqp_olap_ut.cpp +++ b/ydb/core/kqp/ut/olap/kqp_olap_ut.cpp @@ -1458,6 +1458,107 @@ Y_UNIT_TEST_SUITE(KqpOlap) { UNIT_ASSERT_C(ast.find("KqpOlapFilter") != std::string::npos, TStringBuilder() << "Predicate wasn't pushed down. Query: " << query); } + + Y_UNIT_TEST(PredicatePushdown_SimpleAsciiILike) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnableOlapSink(true); + auto settings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetWithSampleTables(false); + TKikimrRunner kikimr(settings); + + { + auto tableClient = kikimr.GetTableClient(); + auto session = tableClient.CreateSession().GetValueSync().GetSession(); + const auto res = session.ExecuteSchemeQuery(R"( + CREATE TABLE `/Root/foo` ( + id Int64 NOT NULL, + str String, + u_str Utf8, + json JsonDocument, + PRIMARY KEY(id) + ) + WITH (STORE = COLUMN); + )").GetValueSync(); + UNIT_ASSERT(res.IsSuccess()); + } + + auto queryClient = kikimr.GetQueryClient(); + auto session = queryClient.GetSession().GetValueSync().GetSession(); + { + const auto res = session.ExecuteQuery(R"( + INSERT INTO `/Root/foo` (id, str, u_str) VALUES + (1, "hello", "hello") + )", NYdb::NQuery::TTxControl::NoTx()).GetValueSync(); + UNIT_ASSERT_C(res.IsSuccess(), res.GetIssues()); + } + + std::vector predicates = { + "str ILIKE 'hell%'", + "str ILIKE 'Hell%'", + "str ILIKE 'Hello%'", + "str ILIKE '%lo'", + "str ILIKE '%Lo'", + "str ILIKE '%Lo%'", + "str ILIKE '%eLLo%'", + "str ILIKE '%HeLLo%'", + "str ILIKE '%LLL%'", + "u_str ILIKE 'hell%'", + "u_str ILIKE 'Hell%'", + "u_str ILIKE 'Hello%'", + "u_str ILIKE '%lo'", + "u_str ILIKE '%Lo'", + "u_str ILIKE '%Lo%'", + "u_str ILIKE '%eLLo%'", + "u_str ILIKE '%HeLLo%'", + "u_str ILIKE '%LLL%'", + }; + + std::vector expectedResults = { + "[[1]]", + "[[1]]", + "[[1]]", + "[[1]]", + "[[1]]", + "[[1]]", + "[[1]]", + "[[1]]", + "[]", + "[[1]]", + "[[1]]", + "[[1]]", + "[[1]]", + "[[1]]", + "[[1]]", + "[[1]]", + "[[1]]", + "[]", + }; + + UNIT_ASSERT_EQUAL(expectedResults.size(), predicates.size()); + + for (ui32 i = 0; i < predicates.size(); ++i) { + const auto& query = TString(R"( + PRAGMA OptimizeSimpleILike; + PRAGMA AnsiLike; + SELECT id FROM `/Root/foo` WHERE + )") + predicates[i]; + Cerr + << "QUERY " << i << Endl + << query << Endl; + + const auto res = session + .ExecuteQuery(query, NYdb::NQuery::TTxControl::NoTx(), + NYdb::NQuery::TExecuteQuerySettings().StatsMode(NQuery::EStatsMode::Full)) + .ExtractValueSync(); + UNIT_ASSERT_C(res.IsSuccess(), res.GetIssues()); + + const auto ast = res.GetStats()->GetAst(); + UNIT_ASSERT_C(ast->find("KqpOlapFilter") != std::string::npos, TStringBuilder() << "ILIKE not pushed down. Query: " << query); + CompareYson(FormatResultSetYson(res.GetResultSet(0)), expectedResults[i]); + } + } + Y_UNIT_TEST(PredicatePushdown_MixStrictAndNotStrict) { auto settings = TKikimrSettings() .SetWithSampleTables(false);