diff options
author | vityaman <[email protected]> | 2025-04-09 17:57:35 +0300 |
---|---|---|
committer | robot-piglet <[email protected]> | 2025-04-09 18:12:05 +0300 |
commit | 394fee4aa8d48e58cf82c72bcb9dda0a5dd50190 (patch) | |
tree | 48fee02cc78dd77aaf1e5e96f2c1a70bd41dfb5d /yql/essentials/sql | |
parent | 0fd1b879589ea8263582a184ccbeac61fd38b596 (diff) |
YQL-19747 Complete select and insert hints
- Related to https://github.com/ydb-platform/ydb/issues/9056
- Related to https://github.com/vityaman/ydb/issues/19
---
Pull Request resolved: https://github.com/ytsaurus/ytsaurus/pull/1189
commit_hash:7f1cb1dcf0617aa2c94c3f2188fc9bd481380252
Diffstat (limited to 'yql/essentials/sql')
20 files changed, 220 insertions, 28 deletions
diff --git a/yql/essentials/sql/v1/complete/core/statement.h b/yql/essentials/sql/v1/complete/core/statement.h new file mode 100644 index 00000000000..d4c095a0e1f --- /dev/null +++ b/yql/essentials/sql/v1/complete/core/statement.h @@ -0,0 +1,10 @@ +#pragma once + +namespace NSQLComplete { + + enum class EStatementKind { + Select, + Insert, + }; + +} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/core/ya.make b/yql/essentials/sql/v1/complete/core/ya.make new file mode 100644 index 00000000000..9865d255c8f --- /dev/null +++ b/yql/essentials/sql/v1/complete/core/ya.make @@ -0,0 +1,3 @@ +LIBRARY() + +END() diff --git a/yql/essentials/sql/v1/complete/name/name_service.h b/yql/essentials/sql/v1/complete/name/name_service.h index 6a7e38dfc20..34a109d0013 100644 --- a/yql/essentials/sql/v1/complete/name/name_service.h +++ b/yql/essentials/sql/v1/complete/name/name_service.h @@ -1,5 +1,7 @@ #pragma once +#include <yql/essentials/sql/v1/complete/core/statement.h> + #include <library/cpp/threading/future/core/future.h> #include <util/generic/vector.h> @@ -29,16 +31,24 @@ namespace NSQLComplete { struct TConstraints: TNamespaced {}; }; + struct THintName: TIndentifier { + struct TConstraints { + EStatementKind Statement; + }; + }; + using TGenericName = std::variant< TPragmaName, TTypeName, - TFunctionName>; + TFunctionName, + THintName>; struct TNameRequest { struct { std::optional<TPragmaName::TConstraints> Pragma; std::optional<TTypeName::TConstraints> Type; std::optional<TFunctionName::TConstraints> Function; + std::optional<THintName::TConstraints> Hint; } Constraints; TString Prefix = ""; size_t Limit = 128; @@ -46,7 +56,8 @@ namespace NSQLComplete { bool IsEmpty() const { return !Constraints.Pragma && !Constraints.Type && - !Constraints.Function; + !Constraints.Function && + !Constraints.Hint; } }; diff --git a/yql/essentials/sql/v1/complete/name/static/frequency.cpp b/yql/essentials/sql/v1/complete/name/static/frequency.cpp index 2de082e287e..b3707533e69 100644 --- a/yql/essentials/sql/v1/complete/name/static/frequency.cpp +++ b/yql/essentials/sql/v1/complete/name/static/frequency.cpp @@ -19,6 +19,8 @@ namespace NSQLComplete { const char* Func = "FUNC"; const char* Module = "MODULE"; const char* ModuleFunc = "MODULE_FUNC"; + const char* ReadHint = "READ_HINT"; + const char* InsertHint = "INSERT_HINT"; } Parent; } Json; @@ -58,7 +60,9 @@ namespace NSQLComplete { item.Parent == Json.Parent.Type || item.Parent == Json.Parent.Func || item.Parent == Json.Parent.ModuleFunc || - item.Parent == Json.Parent.Module) { + item.Parent == Json.Parent.Module || + item.Parent == Json.Parent.ReadHint || + item.Parent == Json.Parent.InsertHint) { item.Rule = ToLowerUTF8(item.Rule); } @@ -66,11 +70,14 @@ namespace NSQLComplete { data.Pragmas[item.Rule] += item.Sum; } else if (item.Parent == Json.Parent.Type) { data.Types[item.Rule] += item.Sum; + } else if (item.Parent == Json.Parent.Module) { + // Ignore, unsupported: Modules } else if (item.Parent == Json.Parent.Func || item.Parent == Json.Parent.ModuleFunc) { data.Functions[item.Rule] += item.Sum; - } else if (item.Parent == Json.Parent.Module) { - // Ignore, unsupported: Modules + } else if (item.Parent == Json.Parent.ReadHint || + item.Parent == Json.Parent.InsertHint) { + data.Hints[item.Rule] += item.Sum; } else { // Ignore, unsupported: Parser Call Stacks } diff --git a/yql/essentials/sql/v1/complete/name/static/frequency.h b/yql/essentials/sql/v1/complete/name/static/frequency.h index 067453bc404..024d93cefcb 100644 --- a/yql/essentials/sql/v1/complete/name/static/frequency.h +++ b/yql/essentials/sql/v1/complete/name/static/frequency.h @@ -9,6 +9,7 @@ namespace NSQLComplete { THashMap<TString, size_t> Pragmas; THashMap<TString, size_t> Types; THashMap<TString, size_t> Functions; + THashMap<TString, size_t> Hints; }; TFrequencyData ParseJsonFrequencyData(const TStringBuf text); diff --git a/yql/essentials/sql/v1/complete/name/static/frequency_ut.cpp b/yql/essentials/sql/v1/complete/name/static/frequency_ut.cpp index dd6ee2cfbb2..a5fd8fad00a 100644 --- a/yql/essentials/sql/v1/complete/name/static/frequency_ut.cpp +++ b/yql/essentials/sql/v1/complete/name/static/frequency_ut.cpp @@ -12,6 +12,8 @@ Y_UNIT_TEST_SUITE(FrequencyTests) { {"parent":"TYPE","rule":"BIGINT","sum":7101}, {"parent":"MODULE_FUNC","rule":"Compress::BZip2","sum":2}, {"parent":"MODULE","rule":"re2","sum":3094}, + {"parent":"READ_HINT","rule":"COLUMNS","sum":826110}, + {"parent":"INSERT_HINT","rule":"COLUMN_GROUPS","sum":225}, {"parent":"TRule_action_or_subquery_args","rule":"TRule_action_or_subquery_args.Block2","sum":4874480} ])"); @@ -23,6 +25,10 @@ Y_UNIT_TEST_SUITE(FrequencyTests) { {"abc", 1}, {"compress::bzip2", 2}, }, + .Hints = { + {"columns", 826110}, + {"column_groups", 225}, + }, }; UNIT_ASSERT_VALUES_EQUAL(actual.Types, expected.Types); diff --git a/yql/essentials/sql/v1/complete/name/static/json_name_set.cpp b/yql/essentials/sql/v1/complete/name/static/json_name_set.cpp index 9fdf314fee6..bc522fd674c 100644 --- a/yql/essentials/sql/v1/complete/name/static/json_name_set.cpp +++ b/yql/essentials/sql/v1/complete/name/static/json_name_set.cpp @@ -3,6 +3,8 @@ #include <library/cpp/json/json_reader.h> #include <library/cpp/resource/resource.h> +#include <util/charset/utf8.h> + namespace NSQLComplete { NJson::TJsonValue LoadJsonResource(const TStringBuf filename) { @@ -38,7 +40,7 @@ namespace NSQLComplete { return ParseNames(json.GetArraySafe()); } - TVector<TString> ParseUfs(NJson::TJsonValue json) { + TVector<TString> ParseUdfs(NJson::TJsonValue json) { TVector<TString> names; for (auto& [module, v] : json.GetMapSafe()) { auto functions = ParseNames(v.GetArraySafe()); @@ -50,13 +52,40 @@ namespace NSQLComplete { return names; } + // TODO(YQL-19747): support multiple systems, name service/set hierarchy - common & special + THashMap<EStatementKind, TVector<TString>> ParseHints(NJson::TJsonValue json) { + THashMap<EStatementKind, TVector<TString>> hints; + + THashMap<EStatementKind, TString> StatementNames = { + {EStatementKind::Select, "read"}, + {EStatementKind::Insert, "insert"}, + }; + + for (const auto& [k, kname] : StatementNames) { + for (auto& [_, values] : json.GetMapSafe().at(kname).GetMapSafe()) { + for (auto& name : ParseNames(values.GetMapSafe().at("hints").GetArraySafe())) { + hints[k].emplace_back(std::move(name)); + } + } + } + + for (auto& [_, hints] : hints) { + for (auto& hint : hints) { + hint = ToUpperUTF8(hint); + } + } + + return hints; + } + NameSet MakeDefaultNameSet() { return { .Pragmas = ParsePragmas(LoadJsonResource("pragmas_opensource.json")), .Types = ParseTypes(LoadJsonResource("types.json")), .Functions = Merge( ParseFunctions(LoadJsonResource("sql_functions.json")), - ParseUfs(LoadJsonResource("udfs_basic.json"))), + ParseUdfs(LoadJsonResource("udfs_basic.json"))), + .Hints = ParseHints(LoadJsonResource("statements_opensource.json")), }; } diff --git a/yql/essentials/sql/v1/complete/name/static/name_service.cpp b/yql/essentials/sql/v1/complete/name/static/name_service.cpp index 42769198579..37f5a06785b 100644 --- a/yql/essentials/sql/v1/complete/name/static/name_service.cpp +++ b/yql/essentials/sql/v1/complete/name/static/name_service.cpp @@ -74,6 +74,9 @@ namespace NSQLComplete { Sort(NameSet_.Pragmas, NoCaseCompare); Sort(NameSet_.Types, NoCaseCompare); Sort(NameSet_.Functions, NoCaseCompare); + for (auto& [_, hints] : NameSet_.Hints) { + Sort(hints, NoCaseCompare); + } } TFuture<TNameResponse> Lookup(TNameRequest request) override { @@ -97,6 +100,13 @@ namespace NSQLComplete { AppendAs<TFunctionName>(response.RankedNames, names); } + if (request.Constraints.Hint) { + const auto stmt = request.Constraints.Hint->Statement; + AppendAs<THintName>( + response.RankedNames, + FilteredByPrefix(request.Prefix, NameSet_.Hints[stmt])); + } + Ranking_->CropToSortedPrefix(response.RankedNames, request.Limit); for (auto& name : response.RankedNames) { diff --git a/yql/essentials/sql/v1/complete/name/static/name_service.h b/yql/essentials/sql/v1/complete/name/static/name_service.h index 348d6ece454..d5459faa1d7 100644 --- a/yql/essentials/sql/v1/complete/name/static/name_service.h +++ b/yql/essentials/sql/v1/complete/name/static/name_service.h @@ -10,6 +10,7 @@ namespace NSQLComplete { TVector<TString> Pragmas; TVector<TString> Types; TVector<TString> Functions; + THashMap<EStatementKind, TVector<TString>> Hints; }; NameSet MakeDefaultNameSet(); diff --git a/yql/essentials/sql/v1/complete/name/static/ranking.cpp b/yql/essentials/sql/v1/complete/name/static/ranking.cpp index b3d5c3c8c31..79ebbc98003 100644 --- a/yql/essentials/sql/v1/complete/name/static/ranking.cpp +++ b/yql/essentials/sql/v1/complete/name/static/ranking.cpp @@ -77,6 +77,12 @@ namespace NSQLComplete { } } + if constexpr (std::is_same_v<T, THintName>) { + if (auto weight = Frequency_.Hints.FindPtr(identifier)) { + return *weight; + } + } + return 0; }, name); } diff --git a/yql/essentials/sql/v1/complete/name/static/ya.make b/yql/essentials/sql/v1/complete/name/static/ya.make index 3c6547f3b52..155c0926399 100644 --- a/yql/essentials/sql/v1/complete/name/static/ya.make +++ b/yql/essentials/sql/v1/complete/name/static/ya.make @@ -17,6 +17,7 @@ RESOURCE( yql/essentials/data/language/types.json types.json yql/essentials/data/language/sql_functions.json sql_functions.json yql/essentials/data/language/udfs_basic.json udfs_basic.json + yql/essentials/data/language/statements_opensource.json statements_opensource.json yql/essentials/data/language/rules_corr_basic.json rules_corr_basic.json ) diff --git a/yql/essentials/sql/v1/complete/name/ya.make b/yql/essentials/sql/v1/complete/name/ya.make index c8af42acfb0..43f7dc2c1b3 100644 --- a/yql/essentials/sql/v1/complete/name/ya.make +++ b/yql/essentials/sql/v1/complete/name/ya.make @@ -1,5 +1,9 @@ LIBRARY() +PEERDIR( + yql/essentials/sql/v1/complete/core +) + END() RECURSE( diff --git a/yql/essentials/sql/v1/complete/sql_complete.cpp b/yql/essentials/sql/v1/complete/sql_complete.cpp index 85fcf87afd1..c3581bfc9ea 100644 --- a/yql/essentials/sql/v1/complete/sql_complete.cpp +++ b/yql/essentials/sql/v1/complete/sql_complete.cpp @@ -101,6 +101,12 @@ namespace NSQLComplete { request.Constraints.Function = std::move(constraints); } + if (context.Hint) { + THintName::TConstraints constraints; + constraints.Statement = context.Hint->StatementKind; + request.Constraints.Hint = std::move(constraints); + } + if (request.IsEmpty()) { return; } @@ -125,6 +131,9 @@ namespace NSQLComplete { name.Indentifier += "("; return {ECandidateKind::FunctionName, std::move(name.Indentifier)}; } + if constexpr (std::is_base_of_v<THintName, T>) { + return {ECandidateKind::HintName, std::move(name.Indentifier)}; + } }, std::move(name))); } } @@ -182,6 +191,9 @@ void Out<NSQLComplete::ECandidateKind>(IOutputStream& out, NSQLComplete::ECandid case NSQLComplete::ECandidateKind::FunctionName: out << "FunctionName"; break; + case NSQLComplete::ECandidateKind::HintName: + out << "HintName"; + break; } } diff --git a/yql/essentials/sql/v1/complete/sql_complete.h b/yql/essentials/sql/v1/complete/sql_complete.h index 5d0271b4dca..de7a597d517 100644 --- a/yql/essentials/sql/v1/complete/sql_complete.h +++ b/yql/essentials/sql/v1/complete/sql_complete.h @@ -23,6 +23,7 @@ namespace NSQLComplete { PragmaName, TypeName, FunctionName, + HintName, }; struct TCandidate { diff --git a/yql/essentials/sql/v1/complete/sql_complete_ut.cpp b/yql/essentials/sql/v1/complete/sql_complete_ut.cpp index 7d595842afb..4e3b84be617 100644 --- a/yql/essentials/sql/v1/complete/sql_complete_ut.cpp +++ b/yql/essentials/sql/v1/complete/sql_complete_ut.cpp @@ -38,6 +38,7 @@ public: Y_UNIT_TEST_SUITE(SqlCompleteTests) { using ECandidateKind::FunctionName; + using ECandidateKind::HintName; using ECandidateKind::Keyword; using ECandidateKind::PragmaName; using ECandidateKind::TypeName; @@ -59,6 +60,10 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { .Pragmas = {"yson.CastToString"}, .Types = {"Uint64"}, .Functions = {"StartsWith", "DateTime::Split"}, + .Hints = { + {EStatementKind::Select, {"XLOCK"}}, + {EStatementKind::Insert, {"EXPIRATION"}}, + }, }; auto ranking = MakeDefaultRanking({}); INameService::TPtr service = MakeStaticNameService(std::move(names), std::move(ranking)); @@ -69,6 +74,12 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { return engine->Complete(input).Candidates; } + TVector<TCandidate> CompleteTop(size_t limit, ISqlCompletionEngine::TPtr& engine, TCompletionInput input) { + auto candidates = Complete(engine, input); + candidates.crop(limit); + return candidates; + } + Y_UNIT_TEST(Beginning) { TVector<TCandidate> expected = { {Keyword, "ALTER"}, @@ -465,6 +476,28 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { } } + Y_UNIT_TEST(SelectTableHintName) { + TVector<TCandidate> expected = { + {Keyword, "COLUMNS"}, + {Keyword, "SCHEMA"}, + {HintName, "XLOCK"}, + }; + + auto engine = MakeSqlCompletionEngineUT(); + UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT key FROM my_table WITH "}), expected); + } + + Y_UNIT_TEST(InsertTableHintName) { + TVector<TCandidate> expected = { + {Keyword, "COLUMNS"}, + {Keyword, "SCHEMA"}, + {HintName, "EXPIRATION"}, + }; + + auto engine = MakeSqlCompletionEngineUT(); + UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"INSERT INTO my_table WITH "}), expected); + } + Y_UNIT_TEST(UTF8Wide) { auto engine = MakeSqlCompletionEngineUT(); UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"\xF0\x9F\x98\x8A"}).size(), 0); @@ -606,17 +639,19 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { {"minby", 32}, {"maxby", 32}, }, + .Hints = { + {"xlock", 4}, + {"unordered", 2}, + }, }; auto service = MakeStaticNameService(MakeDefaultNameSet(), MakeDefaultRanking(frequency)); auto engine = MakeSqlCompletionEngine(MakePureLexerSupplier(), std::move(service)); { - TVector<TCandidate> expectedPrefix = { + TVector<TCandidate> expected = { {PragmaName, "DefaultMemoryLimit"}, {PragmaName, "Annotations"}, }; - auto actualPrefix = Complete(engine, {"PRAGMA yt."}); - actualPrefix.crop(expectedPrefix.size()); - UNIT_ASSERT_VALUES_EQUAL(actualPrefix, expectedPrefix); + UNIT_ASSERT_VALUES_EQUAL(CompleteTop(expected.size(), engine, {"PRAGMA yt."}), expected); } { TVector<TCandidate> expected = { @@ -630,7 +665,7 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT OPTIONAL<I"}), expected); } { - TVector<TCandidate> expectedPrefix = { + TVector<TCandidate> expected = { {FunctionName, "Min("}, {FunctionName, "Max("}, {FunctionName, "MaxOf("}, @@ -640,11 +675,16 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { {FunctionName, "Math::Acos("}, {FunctionName, "Math::Asin("}, }; - - auto actualPrefix = Complete(engine, {"SELECT m"}); - actualPrefix.crop(expectedPrefix.size()); - - UNIT_ASSERT_VALUES_EQUAL(actualPrefix, expectedPrefix); + UNIT_ASSERT_VALUES_EQUAL(CompleteTop(expected.size(), engine, {"SELECT m"}), expected); + } + { + TVector<TCandidate> expected = { + {Keyword, "COLUMNS"}, + {Keyword, "SCHEMA"}, + {HintName, "XLOCK"}, + {HintName, "UNORDERED"}, + }; + UNIT_ASSERT_VALUES_EQUAL(CompleteTop(expected.size(), engine, {"SELECT * FROM a WITH "}), expected); } } diff --git a/yql/essentials/sql/v1/complete/syntax/local.cpp b/yql/essentials/sql/v1/complete/syntax/local.cpp index 28ace474f8e..e6a7430ca27 100644 --- a/yql/essentials/sql/v1/complete/syntax/local.cpp +++ b/yql/essentials/sql/v1/complete/syntax/local.cpp @@ -22,6 +22,13 @@ namespace NSQLComplete { + template <std::regular_invocable<TParserCallStack> StackPredicate> + std::regular_invocable<TMatchedRule> auto RuleAdapted(StackPredicate predicate) { + return [=](const TMatchedRule& rule) { + return predicate(rule.ParserCallStack); + }; + } + template <bool IsAnsiLexer> class TSpecializedLocalSyntaxAnalysis: public ILocalSyntaxAnalysis { private: @@ -61,6 +68,7 @@ namespace NSQLComplete { .Pragma = PragmaMatch(tokens, candidates), .IsTypeName = IsTypeNameMatched(candidates), .Function = FunctionMatch(tokens, candidates), + .Hint = HintMatch(candidates), }; } @@ -137,10 +145,7 @@ namespace NSQLComplete { std::optional<TLocalSyntaxContext::TPragma> PragmaMatch( const NSQLTranslation::TParsedTokenList& tokens, const TC3Candidates& candidates) { - bool isMatched = AnyOf(candidates.Rules, [&](const TMatchedRule& rule) { - return IsLikelyPragmaStack(rule.ParserCallStack); - }); - if (!isMatched) { + if (!AnyOf(candidates.Rules, RuleAdapted(IsLikelyPragmaStack))) { return std::nullopt; } @@ -154,17 +159,12 @@ namespace NSQLComplete { } bool IsTypeNameMatched(const TC3Candidates& candidates) { - return AnyOf(candidates.Rules, [&](const TMatchedRule& rule) { - return IsLikelyTypeStack(rule.ParserCallStack); - }); + return AnyOf(candidates.Rules, RuleAdapted(IsLikelyTypeStack)); } std::optional<TLocalSyntaxContext::TFunction> FunctionMatch( const NSQLTranslation::TParsedTokenList& tokens, const TC3Candidates& candidates) { - bool isMatched = AnyOf(candidates.Rules, [&](const TMatchedRule& rule) { - return IsLikelyFunctionStack(rule.ParserCallStack); - }); - if (!isMatched) { + if (!AnyOf(candidates.Rules, RuleAdapted(IsLikelyFunctionStack))) { return std::nullopt; } @@ -177,6 +177,23 @@ namespace NSQLComplete { return function; } + std::optional<TLocalSyntaxContext::THint> HintMatch(const TC3Candidates& candidates) { + // TODO(YQL-19747): detect local contexts with a single iteration through the candidates.Rules + auto rule = FindIf(candidates.Rules, RuleAdapted(IsLikelyHintStack)); + if (rule == std::end(candidates.Rules)) { + return std::nullopt; + } + + auto stmt = StatementKindOf(rule->ParserCallStack); + if (stmt == std::nullopt) { + return std::nullopt; + } + + return TLocalSyntaxContext::THint{ + .StatementKind = *stmt, + }; + } + NSQLTranslation::TParsedTokenList Tokenized(const TStringBuf text) { NSQLTranslation::TParsedTokenList tokens; NYql::TIssues issues; diff --git a/yql/essentials/sql/v1/complete/syntax/local.h b/yql/essentials/sql/v1/complete/syntax/local.h index 24e78108e10..8d51c54df57 100644 --- a/yql/essentials/sql/v1/complete/syntax/local.h +++ b/yql/essentials/sql/v1/complete/syntax/local.h @@ -18,10 +18,15 @@ namespace NSQLComplete { TString Namespace; }; + struct THint { + EStatementKind StatementKind; + }; + TVector<TString> Keywords; std::optional<TPragma> Pragma; bool IsTypeName; std::optional<TFunction> Function; + std::optional<THint> Hint; }; class ILocalSyntaxAnalysis { diff --git a/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp index 1bfcac47266..bbe0b3d371c 100644 --- a/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp +++ b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp @@ -6,6 +6,8 @@ #include <util/generic/algorithm.h> #include <util/generic/yexception.h> +#include <ranges> + #define DEBUG_SYMBOLIZE_STACK(stack) \ auto debug_symbolized_##stack = Symbolized(stack) @@ -40,6 +42,10 @@ namespace NSQLComplete { RULE(Id_or_type), }; + const TVector<TRuleId> HintNameRules = { + RULE(Id_hint), + }; + TVector<std::string> Symbolized(const TParserCallStack& stack) { const ISqlGrammar& grammar = GetSqlGrammar(); @@ -89,6 +95,22 @@ namespace NSQLComplete { EndsWith({RULE(Atom_expr), RULE(Id_or_type)}, stack); } + bool IsLikelyHintStack(const TParserCallStack& stack) { + return ContainsRule(RULE(Id_hint), stack); + } + + std::optional<EStatementKind> StatementKindOf(const TParserCallStack& stack) { + for (TRuleId rule : std::ranges::views::reverse(stack)) { + if (rule == RULE(Select_core)) { + return EStatementKind::Select; + } + if (rule == RULE(Into_table_stmt)) { + return EStatementKind::Insert; + } + } + return std::nullopt; + } + std::unordered_set<TRuleId> GetC3PreferredRules() { std::unordered_set<TRuleId> preferredRules; preferredRules.insert(std::begin(KeywordRules), std::end(KeywordRules)); diff --git a/yql/essentials/sql/v1/complete/syntax/parser_call_stack.h b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.h index 94533bddaae..98738728231 100644 --- a/yql/essentials/sql/v1/complete/syntax/parser_call_stack.h +++ b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.h @@ -1,6 +1,7 @@ #pragma once #include <yql/essentials/sql/v1/complete/antlr4/defs.h> +#include <yql/essentials/sql/v1/complete/core/statement.h> namespace NSQLComplete { @@ -10,6 +11,10 @@ namespace NSQLComplete { bool IsLikelyFunctionStack(const TParserCallStack& stack); + bool IsLikelyHintStack(const TParserCallStack& stack); + + std::optional<EStatementKind> StatementKindOf(const TParserCallStack& stack); + std::unordered_set<TRuleId> GetC3PreferredRules(); } // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/ya.make b/yql/essentials/sql/v1/complete/ya.make index 4db8f92d5aa..57e3ba3bf63 100644 --- a/yql/essentials/sql/v1/complete/ya.make +++ b/yql/essentials/sql/v1/complete/ya.make @@ -22,6 +22,7 @@ END() RECURSE( antlr4 + core name syntax text |