Skip to content

Commit ae913bc

Browse files
vityamanrobot-piglet
authored andcommitted
YQL-19747: Recover from unclosed ID_QUOTED
The simplest solution actually is an SQL injection. --- - Related to `YQL-19747` - Related to #9056 - Related to #18146 - Related to vityaman#46 --- Pull Request resolved: ytsaurus/ytsaurus#1283 commit_hash:7043e7cdd1e0d378926783d31cf5f8e055393aaa
1 parent 16630d4 commit ae913bc

File tree

5 files changed

+47
-7
lines changed

5 files changed

+47
-7
lines changed

yql/essentials/sql/v1/complete/core/input.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ namespace NSQLComplete {
99
size_t CursorPosition = Text.length();
1010
};
1111

12+
struct TMaterializedInput {
13+
TString Text;
14+
size_t CursorPosition = Text.length();
15+
};
16+
1217
TCompletionInput SharpedInput(TString& text Y_LIFETIME_BOUND);
1318

1419
} // namespace NSQLComplete

yql/essentials/sql/v1/complete/sql_complete_ut.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,12 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) {
508508
UNIT_ASSERT_VALUES_EQUAL(actual.CompletedToken.Content, "pr");
509509
}
510510
{
511-
TVector<TCandidate> expected = {};
511+
TVector<TCandidate> expected = {
512+
{FolderName, ".sys/"},
513+
{FolderName, "local/"},
514+
{FolderName, "prod/"},
515+
{FolderName, "test/"},
516+
};
512517
UNIT_ASSERT_VALUES_EQUAL(Complete(engine, "SELECT * FROM `#"), expected);
513518
}
514519
{
@@ -564,6 +569,26 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) {
564569
}
565570
}
566571

572+
Y_UNIT_TEST(SelectFromUnclosedIdQuoted) {
573+
auto engine = MakeSqlCompletionEngineUT();
574+
{
575+
TVector<TCandidate> expected = {
576+
{FolderName, ".sys/"},
577+
{FolderName, "local/"},
578+
{FolderName, "prod/"},
579+
{FolderName, "test/"},
580+
};
581+
UNIT_ASSERT_VALUES_EQUAL(Complete(engine, "SELECT * FROM `#"), expected);
582+
}
583+
{
584+
TVector<TCandidate> expected = {
585+
{TableName, "meta"},
586+
{FolderName, "service/"},
587+
};
588+
UNIT_ASSERT_VALUES_EQUAL(Complete(engine, "SELECT * FROM `test/"), expected);
589+
}
590+
}
591+
567592
Y_UNIT_TEST(SelectFromCluster) {
568593
auto engine = MakeSqlCompletionEngineUT();
569594
{

yql/essentials/sql/v1/complete/syntax/cursor_token_context.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,13 @@ namespace NSQLComplete {
112112

113113
bool GetStatement(
114114
ILexer::TPtr& lexer,
115-
TCompletionInput input,
115+
const TMaterializedInput& input,
116116
TCompletionInput& output,
117117
size_t& output_position) {
118118
TVector<TString> statements;
119119
NYql::TIssues issues;
120120
if (!NSQLTranslationV1::SplitQueryToStatements(
121-
TString(input.Text) + ";", lexer,
121+
input.Text, lexer,
122122
statements, issues, /* file = */ "",
123123
/* areBlankSkipped = */ false)) {
124124
return false;
@@ -129,15 +129,16 @@ namespace NSQLComplete {
129129
for (const auto& statement : statements) {
130130
if (input.CursorPosition < cursor + statement.size()) {
131131
output = {
132-
.Text = input.Text.SubStr(cursor, statement.size()),
132+
.Text = TStringBuf(input.Text).SubStr(cursor, statement.size()),
133133
.CursorPosition = input.CursorPosition - cursor,
134134
};
135135
return true;
136136
}
137137
cursor += statement.size();
138138
}
139139

140-
output = input;
140+
output.Text = TStringBuf(input.Text);
141+
output.CursorPosition = input.CursorPosition;
141142
return true;
142143
}
143144

yql/essentials/sql/v1/complete/syntax/cursor_token_context.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ namespace NSQLComplete {
3838

3939
bool GetStatement(
4040
ILexer::TPtr& lexer,
41-
TCompletionInput input,
41+
const TMaterializedInput& input,
4242
TCompletionInput& output,
4343
size_t& output_position);
4444

yql/essentials/sql/v1/complete/syntax/local.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,18 @@ namespace NSQLComplete {
5757
}
5858

5959
TLocalSyntaxContext Analyze(TCompletionInput input) override {
60+
TMaterializedInput materialized = {
61+
.Text = TString(input.Text),
62+
.CursorPosition = input.CursorPosition,
63+
};
64+
65+
// - ";" is for a correct stetement split
66+
// - "-- `" is for a ilformed ID_QUOTED recovery
67+
materialized.Text += "; -- `";
68+
6069
TCompletionInput statement;
6170
size_t statement_position;
62-
if (!GetStatement(Lexer_, input, statement, statement_position)) {
71+
if (!GetStatement(Lexer_, materialized, statement, statement_position)) {
6372
return {};
6473
}
6574

0 commit comments

Comments
 (0)