summaryrefslogtreecommitdiffstats
path: root/yql/essentials/sql
diff options
context:
space:
mode:
authorvityaman <[email protected]>2025-04-09 17:57:35 +0300
committerrobot-piglet <[email protected]>2025-04-09 18:12:05 +0300
commit394fee4aa8d48e58cf82c72bcb9dda0a5dd50190 (patch)
tree48fee02cc78dd77aaf1e5e96f2c1a70bd41dfb5d /yql/essentials/sql
parent0fd1b879589ea8263582a184ccbeac61fd38b596 (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')
-rw-r--r--yql/essentials/sql/v1/complete/core/statement.h10
-rw-r--r--yql/essentials/sql/v1/complete/core/ya.make3
-rw-r--r--yql/essentials/sql/v1/complete/name/name_service.h15
-rw-r--r--yql/essentials/sql/v1/complete/name/static/frequency.cpp13
-rw-r--r--yql/essentials/sql/v1/complete/name/static/frequency.h1
-rw-r--r--yql/essentials/sql/v1/complete/name/static/frequency_ut.cpp6
-rw-r--r--yql/essentials/sql/v1/complete/name/static/json_name_set.cpp33
-rw-r--r--yql/essentials/sql/v1/complete/name/static/name_service.cpp10
-rw-r--r--yql/essentials/sql/v1/complete/name/static/name_service.h1
-rw-r--r--yql/essentials/sql/v1/complete/name/static/ranking.cpp6
-rw-r--r--yql/essentials/sql/v1/complete/name/static/ya.make1
-rw-r--r--yql/essentials/sql/v1/complete/name/ya.make4
-rw-r--r--yql/essentials/sql/v1/complete/sql_complete.cpp12
-rw-r--r--yql/essentials/sql/v1/complete/sql_complete.h1
-rw-r--r--yql/essentials/sql/v1/complete/sql_complete_ut.cpp60
-rw-r--r--yql/essentials/sql/v1/complete/syntax/local.cpp39
-rw-r--r--yql/essentials/sql/v1/complete/syntax/local.h5
-rw-r--r--yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp22
-rw-r--r--yql/essentials/sql/v1/complete/syntax/parser_call_stack.h5
-rw-r--r--yql/essentials/sql/v1/complete/ya.make1
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