diff options
author | vitya-smirnov <[email protected]> | 2025-06-25 15:43:36 +0300 |
---|---|---|
committer | vitya-smirnov <[email protected]> | 2025-06-25 16:01:44 +0300 |
commit | 59fa891737bd017e3c73b3ee4320333d8f57611c (patch) | |
tree | 8c3e49287f11947bdd7d855996823e07af317332 /yql/essentials/sql | |
parent | de5ef0597b0c69b0226eece538677890aec07b16 (diff) |
YQL-19747: Hack parsing when at an empty id
There was a problem with parsing a query like
`SELECT # FROM t`, as it parsed `FROM` as if it
is an expeceted column name, so we failed to parse
a table name after `FROM` and therefore can not
complete column names, while the are so useful at
this position. Also this hack improved parsing
other queries, according to changed tests.
commit_hash:f5a657022a164d1d4bbf906db4bd2ad67bbcd956
Diffstat (limited to 'yql/essentials/sql')
4 files changed, 33 insertions, 3 deletions
diff --git a/yql/essentials/sql/v1/complete/analysis/global/global.cpp b/yql/essentials/sql/v1/complete/analysis/global/global.cpp index 191814a8e55..555d5283c14 100644 --- a/yql/essentials/sql/v1/complete/analysis/global/global.cpp +++ b/yql/essentials/sql/v1/complete/analysis/global/global.cpp @@ -95,6 +95,17 @@ namespace NSQLComplete { } TGlobalContext Analyze(TCompletionInput input, TEnvironment env) override { + TString recovered; + if (IsRecoverable(input)) { + recovered = TString(input.Text); + + // - "_" is to parse `SELECT x._ FROM table` + // instead of `SELECT x.FROM table` + recovered.insert(input.CursorPosition, "_"); + + input.Text = recovered; + } + SQLv1::Sql_queryContext* sqlQuery = Parse(input.Text); Y_ENSURE(sqlQuery); @@ -114,6 +125,17 @@ namespace NSQLComplete { } private: + bool IsRecoverable(TCompletionInput input) const { + static const TStringBuf prev = " "; + static const TStringBuf next = " .("; + + TStringBuf s = input.Text; + size_t i = input.CursorPosition; + + return (i < s.size() && prev.Contains(s[i]) || i == s.size()) && + (i > 0 /* */ && next.Contains(s[i - 1])); + } + SQLv1::Sql_queryContext* Parse(TStringBuf input) { Chars_.load(input.Data(), input.Size(), /* lenient = */ false); Lexer_.reset(); diff --git a/yql/essentials/sql/v1/complete/analysis/global/global_ut.cpp b/yql/essentials/sql/v1/complete/analysis/global/global_ut.cpp index 5e180fcb431..15aba3ee155 100644 --- a/yql/essentials/sql/v1/complete/analysis/global/global_ut.cpp +++ b/yql/essentials/sql/v1/complete/analysis/global/global_ut.cpp @@ -89,7 +89,7 @@ Y_UNIT_TEST_SUITE(GlobalAnalysisTests) { { TString query = "SELECT * FROM Concat(#"; TGlobalContext ctx = global->Analyze(SharpedInput(query), {}); - UNIT_ASSERT_VALUES_EQUAL(ctx.EnclosingFunction, Nothing()); + UNIT_ASSERT_VALUES_EQUAL(ctx.EnclosingFunction, "Concat"); } { TString query = "SELECT * FROM (#)"; diff --git a/yql/essentials/sql/v1/complete/analysis/global/named_node.cpp b/yql/essentials/sql/v1/complete/analysis/global/named_node.cpp index 14b928c53e5..0896b508432 100644 --- a/yql/essentials/sql/v1/complete/analysis/global/named_node.cpp +++ b/yql/essentials/sql/v1/complete/analysis/global/named_node.cpp @@ -84,6 +84,10 @@ namespace NSQLComplete { } std::any visitBind_parameter(SQLv1::Bind_parameterContext* ctx) override { + if (IsEnclosing(ctx)) { + return {}; + } + TMaybe<std::string> id = GetId(ctx); if (id.Empty() || id == "_") { return {}; diff --git a/yql/essentials/sql/v1/complete/sql_complete_ut.cpp b/yql/essentials/sql/v1/complete/sql_complete_ut.cpp index 5b99c6a3fe1..aa955bc2cc5 100644 --- a/yql/essentials/sql/v1/complete/sql_complete_ut.cpp +++ b/yql/essentials/sql/v1/complete/sql_complete_ut.cpp @@ -905,6 +905,7 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { auto engine = MakeSqlCompletionEngineUT(); { TVector<TCandidate> expected = { + {BindingName, "$udf"}, {HintName, "XLOCK"}, }; UNIT_ASSERT_VALUES_EQUAL(Complete(engine, "PROCESS my_table USING $udf(TableRows()) WITH "), expected); @@ -1105,8 +1106,11 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { }; UNIT_ASSERT_VALUES_EQUAL(CompleteTop(2, engine, "SELECT # FROM example.`/people` AS x"), expected); } - { // It is parsed into ``` SELECT x.FROM example.`/people` AS x ``` - TVector<TCandidate> expected = {}; + { + TVector<TCandidate> expected = { + {ColumnName, "Age"}, + {ColumnName, "Name"}, + }; UNIT_ASSERT_VALUES_EQUAL(CompleteTop(2, engine, "SELECT x.# FROM example.`/people` AS x"), expected); } { |