Skip to content

Commit 56b80f8

Browse files
authored
Enable subqueries inside views (#10517)
1 parent 5011c62 commit 56b80f8

File tree

6 files changed

+71
-27
lines changed

6 files changed

+71
-27
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CREATE VIEW in_subquery WITH (security_invoker = TRUE) AS
2+
SELECT
3+
*
4+
FROM series
5+
WHERE series_id IN (
6+
SELECT
7+
series_id
8+
FROM series
9+
);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DROP VIEW in_subquery;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
SELECT
2+
*
3+
FROM (
4+
SELECT
5+
*
6+
FROM series
7+
WHERE series_id IN (
8+
SELECT
9+
series_id
10+
FROM series
11+
)
12+
);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SELECT
2+
*
3+
FROM in_subquery;

ydb/core/kqp/ut/view/view_ut.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,10 @@ void CompareResults(const NQuery::TExecuteQueryResult& first, const NQuery::TExe
139139
CompareResults(first.GetResultSets(), second.GetResultSets());
140140
}
141141

142-
void InitializeTablesAndSecondaryViews(TSession& session) {
142+
void InitializeTablesAndSecondaryViews(NQuery::TSession& session) {
143143
const auto inputFolder = ArcadiaFromCurrentLocation(__SOURCE_FILE__, "input");
144-
ExecuteDataDefinitionQuery(session, ReadWholeFile(inputFolder + "/create_tables_and_secondary_views.sql"));
145-
ExecuteDataModificationQuery(session, ReadWholeFile(inputFolder + "/fill_tables.sql"));
144+
ExecuteQuery(session, ReadWholeFile(inputFolder + "/create_tables_and_secondary_views.sql"));
145+
ExecuteQuery(session, ReadWholeFile(inputFolder + "/fill_tables.sql"));
146146
}
147147

148148
}
@@ -582,7 +582,7 @@ Y_UNIT_TEST_SUITE(TSelectFromViewTest) {
582582
Y_UNIT_TEST(ReadTestCasesFromFiles) {
583583
TKikimrRunner kikimr;
584584
EnableViewsFeatureFlag(kikimr);
585-
auto session = kikimr.GetTableClient().CreateSession().GetValueSync().GetSession();
585+
auto session = kikimr.GetQueryClient().GetSession().ExtractValueSync().GetSession();
586586

587587
InitializeTablesAndSecondaryViews(session);
588588
EnableLogging();
@@ -593,13 +593,13 @@ Y_UNIT_TEST_SUITE(TSelectFromViewTest) {
593593
TString testcase;
594594
while (testcase = testcases.Next()) {
595595
const auto pathPrefix = TStringBuilder() << testcasesFolder << '/' << testcase << '/';
596-
ExecuteDataDefinitionQuery(session, ReadWholeFile(pathPrefix + "create_view.sql"));
596+
ExecuteQuery(session, ReadWholeFile(pathPrefix + "create_view.sql"));
597597

598-
const auto etalonResults = ExecuteDataModificationQuery(session, ReadWholeFile(pathPrefix + "etalon_query.sql"));
599-
const auto selectFromViewResults = ExecuteDataModificationQuery(session, ReadWholeFile(pathPrefix + "select_from_view.sql"));
598+
const auto etalonResults = ExecuteQuery(session, ReadWholeFile(pathPrefix + "etalon_query.sql"));
599+
const auto selectFromViewResults = ExecuteQuery(session, ReadWholeFile(pathPrefix + "select_from_view.sql"));
600600
CompareResults(etalonResults, selectFromViewResults);
601601

602-
ExecuteDataDefinitionQuery(session, ReadWholeFile(pathPrefix + "drop_view.sql"));
602+
ExecuteQuery(session, ReadWholeFile(pathPrefix + "drop_view.sql"));
603603
}
604604
}
605605

ydb/library/yql/sql/v1/sql_translation.cpp

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -55,48 +55,67 @@ TString CollectTokens(const TRule_select_stmt& selectStatement) {
5555
return tokenCollector.Tokens;
5656
}
5757

58-
bool RestoreContext(
59-
TContext& ctx, const NSQLTranslation::TTranslationSettings& settings, const TString& contextRestorationQuery
58+
bool RecreateContext(
59+
TContext& ctx, const NSQLTranslation::TTranslationSettings& settings, const TString& recreationQuery
6060
) {
61-
const TString queryName = "context restoration query";
61+
if (!recreationQuery) {
62+
return true;
63+
}
64+
const TString queryName = "context recreation query";
6265

6366
const auto* ast = NSQLTranslationV1::SqlAST(
64-
contextRestorationQuery, queryName, ctx.Issues,
67+
recreationQuery, queryName, ctx.Issues,
6568
settings.MaxErrors, settings.AnsiLexer, settings.Antlr4Parser, settings.TestAntlr4, settings.Arena
6669
);
6770
if (!ast) {
6871
return false;
6972
}
7073

71-
TSqlQuery query(ctx, ctx.Settings.Mode, true);
72-
auto node = query.Build(static_cast<const TSQLv1ParserAST&>(*ast));
74+
TSqlQuery queryTranslator(ctx, ctx.Settings.Mode, true);
75+
auto node = queryTranslator.Build(static_cast<const TSQLv1ParserAST&>(*ast));
7376

7477
return node && node->Init(ctx, nullptr) && node->Translate(ctx);
7578
}
7679

7780
TNodePtr BuildViewSelect(
78-
const TRule_select_stmt& selectQuery,
81+
const TRule_select_stmt& selectStatement,
7982
TContext& parentContext,
80-
const TString& contextRestorationQuery
83+
const TString& contextRecreationQuery
8184
) {
82-
TContext context(parentContext.Settings, {}, parentContext.Issues);
83-
RestoreContext(context, context.Settings, contextRestorationQuery);
85+
TIssues issues;
86+
TContext context(parentContext.Settings, {}, issues);
87+
if (!RecreateContext(context, context.Settings, contextRecreationQuery)) {
88+
parentContext.Issues.AddIssues(issues);
89+
return nullptr;
90+
}
91+
issues.Clear();
92+
93+
// Holds (among other things) subquery references.
94+
// These references need to be passed to the parent context
95+
// to be able to compile view queries with subqueries.
96+
context.PushCurrentBlocks(&parentContext.GetCurrentBlocks());
8497

8598
context.Settings.Mode = NSQLTranslation::ESqlMode::LIMITED_VIEW;
8699

87-
TSqlSelect select(context, context.Settings.Mode);
88-
TPosition pos;
89-
auto source = select.Build(selectQuery, pos);
100+
TSqlSelect selectTranslator(context, context.Settings.Mode);
101+
TPosition pos = parentContext.Pos();
102+
auto source = selectTranslator.Build(selectStatement, pos);
90103
if (!source) {
104+
parentContext.Issues.AddIssues(issues);
91105
return nullptr;
92106
}
93-
return BuildSelectResult(
107+
auto node = BuildSelectResult(
94108
pos,
95109
std::move(source),
96110
false,
97111
false,
98112
context.Scoped
99113
);
114+
if (!node) {
115+
parentContext.Issues.AddIssues(issues);
116+
return nullptr;
117+
}
118+
return node;
100119
}
101120

102121
}
@@ -4896,27 +4915,27 @@ bool TSqlTranslation::ParseViewQuery(
48964915
const TRule_select_stmt& query
48974916
) {
48984917
TString queryText = CollectTokens(query);
4899-
TString contextRestorationQuery;
4918+
TString contextRecreationQuery;
49004919
{
49014920
const auto& service = Ctx.Scoped->CurrService;
49024921
const auto& cluster = Ctx.Scoped->CurrCluster;
49034922
const auto effectivePathPrefix = Ctx.GetPrefixPath(service, cluster);
49044923

49054924
// TO DO: capture all runtime pragmas in a similar fashion.
49064925
if (effectivePathPrefix != Ctx.Settings.PathPrefix) {
4907-
contextRestorationQuery = TStringBuilder() << "PRAGMA TablePathPrefix = \"" << effectivePathPrefix << "\";\n";
4926+
contextRecreationQuery = TStringBuilder() << "PRAGMA TablePathPrefix = \"" << effectivePathPrefix << "\";\n";
49084927
}
49094928

49104929
// TO DO: capture other compilation-affecting statements except USE.
49114930
if (cluster.GetLiteral() && *cluster.GetLiteral() != Ctx.Settings.DefaultCluster) {
4912-
contextRestorationQuery = TStringBuilder() << "USE " << *cluster.GetLiteral() << ";\n";
4931+
contextRecreationQuery = TStringBuilder() << "USE " << *cluster.GetLiteral() << ";\n";
49134932
}
49144933
}
4915-
features["query_text"] = { Ctx.Pos(), contextRestorationQuery + queryText };
4934+
features["query_text"] = { Ctx.Pos(), contextRecreationQuery + queryText };
49164935

49174936
// AST is needed for ready-made validation of CREATE VIEW statement.
49184937
// Query is stored as plain text, not AST.
4919-
const auto viewSelect = BuildViewSelect(query, Ctx, contextRestorationQuery);
4938+
const auto viewSelect = BuildViewSelect(query, Ctx, contextRecreationQuery);
49204939
if (!viewSelect) {
49214940
return false;
49224941
}

0 commit comments

Comments
 (0)