Skip to content

Commit d715fff

Browse files
jepett0zinal
authored andcommitted
24-3: Enable subqueries inside views (ydb-platform#10517) (ydb-platform#10632)
1 parent fc2baf5 commit d715fff

File tree

6 files changed

+119
-21
lines changed

6 files changed

+119
-21
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: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,18 @@ void CompareResults(const TDataQueryResult& first, const TDataQueryResult& secon
120120
}
121121
}
122122

123-
void InitializeTablesAndSecondaryViews(TSession& session) {
123+
void CompareResults(const TDataQueryResult& first, const TDataQueryResult& second) {
124+
CompareResults(first.GetResultSets(), second.GetResultSets());
125+
}
126+
127+
void CompareResults(const NQuery::TExecuteQueryResult& first, const NQuery::TExecuteQueryResult& second) {
128+
CompareResults(first.GetResultSets(), second.GetResultSets());
129+
}
130+
131+
void InitializeTablesAndSecondaryViews(NQuery::TSession& session) {
124132
const auto inputFolder = ArcadiaFromCurrentLocation(__SOURCE_FILE__, "input");
125-
ExecuteDataDefinitionQuery(session, ReadWholeFile(inputFolder + "/create_tables_and_secondary_views.sql"));
126-
ExecuteDataModificationQuery(session, ReadWholeFile(inputFolder + "/fill_tables.sql"));
133+
ExecuteQuery(session, ReadWholeFile(inputFolder + "/create_tables_and_secondary_views.sql"));
134+
ExecuteQuery(session, ReadWholeFile(inputFolder + "/fill_tables.sql"));
127135
}
128136

129137
}
@@ -439,7 +447,7 @@ Y_UNIT_TEST_SUITE(TSelectFromViewTest) {
439447
Y_UNIT_TEST(ReadTestCasesFromFiles) {
440448
TKikimrRunner kikimr;
441449
EnableViewsFeatureFlag(kikimr);
442-
auto session = kikimr.GetTableClient().CreateSession().GetValueSync().GetSession();
450+
auto session = kikimr.GetQueryClient().GetSession().ExtractValueSync().GetSession();
443451

444452
InitializeTablesAndSecondaryViews(session);
445453
EnableLogging();
@@ -450,13 +458,13 @@ Y_UNIT_TEST_SUITE(TSelectFromViewTest) {
450458
TString testcase;
451459
while (testcase = testcases.Next()) {
452460
const auto pathPrefix = TStringBuilder() << testcasesFolder << '/' << testcase << '/';
453-
ExecuteDataDefinitionQuery(session, ReadWholeFile(pathPrefix + "create_view.sql"));
461+
ExecuteQuery(session, ReadWholeFile(pathPrefix + "create_view.sql"));
454462

455-
const auto etalonResults = ExecuteDataModificationQuery(session, ReadWholeFile(pathPrefix + "etalon_query.sql"));
456-
const auto selectFromViewResults = ExecuteDataModificationQuery(session, ReadWholeFile(pathPrefix + "select_from_view.sql"));
463+
const auto etalonResults = ExecuteQuery(session, ReadWholeFile(pathPrefix + "etalon_query.sql"));
464+
const auto selectFromViewResults = ExecuteQuery(session, ReadWholeFile(pathPrefix + "select_from_view.sql"));
457465
CompareResults(etalonResults, selectFromViewResults);
458466

459-
ExecuteDataDefinitionQuery(session, ReadWholeFile(pathPrefix + "drop_view.sql"));
467+
ExecuteQuery(session, ReadWholeFile(pathPrefix + "drop_view.sql"));
460468
}
461469
}
462470

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

Lines changed: 78 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,31 +53,67 @@ TString CollectTokens(const TRule_select_stmt& selectStatement) {
5353
return tokenCollector.Tokens;
5454
}
5555

56-
NSQLTranslation::TTranslationSettings CreateViewTranslationSettings(const NSQLTranslation::TTranslationSettings& base) {
57-
NSQLTranslation::TTranslationSettings settings;
56+
bool RecreateContext(
57+
TContext& ctx, const NSQLTranslation::TTranslationSettings& settings, const TString& recreationQuery
58+
) {
59+
if (!recreationQuery) {
60+
return true;
61+
}
62+
const TString queryName = "context recreation query";
63+
64+
const auto* ast = NSQLTranslationV1::SqlAST(
65+
recreationQuery, queryName, ctx.Issues,
66+
settings.MaxErrors, settings.AnsiLexer, settings.Arena
67+
);
68+
if (!ast) {
69+
return false;
70+
}
5871

59-
settings.ClusterMapping = base.ClusterMapping;
60-
settings.Mode = NSQLTranslation::ESqlMode::LIMITED_VIEW;
72+
TSqlQuery queryTranslator(ctx, ctx.Settings.Mode, true);
73+
auto node = queryTranslator.Build(static_cast<const TSQLv1ParserAST&>(*ast));
6174

62-
return settings;
75+
return node && node->Init(ctx, nullptr) && node->Translate(ctx);
6376
}
6477

65-
TNodePtr BuildViewSelect(const TRule_select_stmt& query, TContext& ctx) {
66-
const auto viewTranslationSettings = CreateViewTranslationSettings(ctx.Settings);
67-
TContext viewParsingContext(viewTranslationSettings, {}, ctx.Issues);
68-
TSqlSelect select(viewParsingContext, viewTranslationSettings.Mode);
69-
TPosition pos;
70-
auto source = select.Build(query, pos);
78+
TNodePtr BuildViewSelect(
79+
const TRule_select_stmt& selectStatement,
80+
TContext& parentContext,
81+
const TString& contextRecreationQuery
82+
) {
83+
TIssues issues;
84+
TContext context(parentContext.Settings, {}, issues);
85+
if (!RecreateContext(context, context.Settings, contextRecreationQuery)) {
86+
parentContext.Issues.AddIssues(issues);
87+
return nullptr;
88+
}
89+
issues.Clear();
90+
91+
// Holds (among other things) subquery references.
92+
// These references need to be passed to the parent context
93+
// to be able to compile view queries with subqueries.
94+
context.PushCurrentBlocks(&parentContext.GetCurrentBlocks());
95+
96+
context.Settings.Mode = NSQLTranslation::ESqlMode::LIMITED_VIEW;
97+
98+
TSqlSelect selectTranslator(context, context.Settings.Mode);
99+
TPosition pos = parentContext.Pos();
100+
auto source = selectTranslator.Build(selectStatement, pos);
71101
if (!source) {
102+
parentContext.Issues.AddIssues(issues);
72103
return nullptr;
73104
}
74-
return BuildSelectResult(
105+
auto node = BuildSelectResult(
75106
pos,
76107
std::move(source),
77108
false,
78109
false,
79-
viewParsingContext.Scoped
110+
context.Scoped
80111
);
112+
if (!node) {
113+
parentContext.Issues.AddIssues(issues);
114+
return nullptr;
115+
}
116+
return node;
81117
}
82118

83119
}
@@ -4568,6 +4604,7 @@ bool TSqlTranslation::ValidateExternalTable(const TCreateTableParameters& params
45684604
return true;
45694605
}
45704606

4607+
<<<<<<< HEAD
45714608
bool TSqlTranslation::ParseViewOptions(std::map<TString, TDeferredAtom>& features,
45724609
const TRule_with_table_settings& options) {
45734610
const auto& firstEntry = options.GetRule_table_settings_entry3();
@@ -4600,6 +4637,34 @@ bool TSqlTranslation::ParseViewQuery(std::map<TString, TDeferredAtom>& features,
46004637
features["query_text"] = {Ctx.Pos(), queryText};
46014638

46024639
const auto viewSelect = BuildViewSelect(query, Ctx);
4640+
=======
4641+
bool TSqlTranslation::ParseViewQuery(
4642+
std::map<TString, TDeferredAtom>& features,
4643+
const TRule_select_stmt& query
4644+
) {
4645+
TString queryText = CollectTokens(query);
4646+
TString contextRecreationQuery;
4647+
{
4648+
const auto& service = Ctx.Scoped->CurrService;
4649+
const auto& cluster = Ctx.Scoped->CurrCluster;
4650+
const auto effectivePathPrefix = Ctx.GetPrefixPath(service, cluster);
4651+
4652+
// TO DO: capture all runtime pragmas in a similar fashion.
4653+
if (effectivePathPrefix != Ctx.Settings.PathPrefix) {
4654+
contextRecreationQuery = TStringBuilder() << "PRAGMA TablePathPrefix = \"" << effectivePathPrefix << "\";\n";
4655+
}
4656+
4657+
// TO DO: capture other compilation-affecting statements except USE.
4658+
if (cluster.GetLiteral() && *cluster.GetLiteral() != Ctx.Settings.DefaultCluster) {
4659+
contextRecreationQuery = TStringBuilder() << "USE " << *cluster.GetLiteral() << ";\n";
4660+
}
4661+
}
4662+
features["query_text"] = { Ctx.Pos(), contextRecreationQuery + queryText };
4663+
4664+
// AST is needed for ready-made validation of CREATE VIEW statement.
4665+
// Query is stored as plain text, not AST.
4666+
const auto viewSelect = BuildViewSelect(query, Ctx, contextRecreationQuery);
4667+
>>>>>>> 98132426f0 (24-3: Enable subqueries inside views (#10517) (#10632))
46034668
if (!viewSelect) {
46044669
return false;
46054670
}

0 commit comments

Comments
 (0)