From 988bf3a34e21891a888cf3e2d37429ced580ce4d Mon Sep 17 00:00:00 2001 From: Daniil Demin Date: Fri, 9 Feb 2024 15:24:40 +0000 Subject: [PATCH] Use the same empty parsing context for early validation of view queries in CREATE VIEW statement and for selecting from the views Preliminary validation is done by adding "query_ast" node to the builded AST of the CREATE VIEW statement. It does not surve any real purpose (it is not persisted in the scheme) as of now except early validation of view queries. --- ydb/core/kqp/ut/view/view_ut.cpp | 18 +++++++++ ydb/library/yql/sql/v1/sql_translation.cpp | 43 ++++++++++++++++------ 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/ydb/core/kqp/ut/view/view_ut.cpp b/ydb/core/kqp/ut/view/view_ut.cpp index c3eb3bd492dc..381dea85c6d9 100644 --- a/ydb/core/kqp/ut/view/view_ut.cpp +++ b/ydb/core/kqp/ut/view/view_ut.cpp @@ -324,6 +324,24 @@ Y_UNIT_TEST_SUITE(TCreateAndDropViewTest) { UNIT_ASSERT(dropResult.GetIssues().ToString().Contains("Error: Path does not exist")); } } + + Y_UNIT_TEST(ContextPollution) { + TKikimrRunner kikimr(TKikimrSettings().SetWithSampleTables(false)); + EnableViewsFeatureFlag(kikimr); + auto session = kikimr.GetTableClient().CreateSession().GetValueSync().GetSession(); + + ExecuteDataDefinitionQuery(session, R"( + CREATE VIEW InnerView WITH (security_invoker = TRUE) AS SELECT 1; + )"); + ExecuteDataDefinitionQuery(session, R"( + CREATE VIEW OuterView WITH (security_invoker = TRUE) AS SELECT * FROM InnerView; + )"); + + ExecuteDataDefinitionQuery(session, R"( + DROP VIEW OuterView; + CREATE VIEW OuterView WITH (security_invoker = TRUE) AS SELECT * FROM InnerView; + )"); + } } Y_UNIT_TEST_SUITE(TSelectFromViewTest) { diff --git a/ydb/library/yql/sql/v1/sql_translation.cpp b/ydb/library/yql/sql/v1/sql_translation.cpp index 5b8a71852540..55375971f156 100644 --- a/ydb/library/yql/sql/v1/sql_translation.cpp +++ b/ydb/library/yql/sql/v1/sql_translation.cpp @@ -53,6 +53,33 @@ TString CollectTokens(const TRule_select_stmt& selectStatement) { return tokenCollector.Tokens; } +NSQLTranslation::TTranslationSettings CreateViewTranslationSettings(const NSQLTranslation::TTranslationSettings& base) { + NSQLTranslation::TTranslationSettings settings; + + settings.ClusterMapping = base.ClusterMapping; + settings.Mode = NSQLTranslation::ESqlMode::LIMITED_VIEW; + + return settings; +} + +TNodePtr BuildViewSelect(const TRule_select_stmt& query, TContext& ctx) { + const auto viewTranslationSettings = CreateViewTranslationSettings(ctx.Settings); + TContext viewParsingContext(viewTranslationSettings, {}, ctx.Issues); + TSqlSelect select(viewParsingContext, viewTranslationSettings.Mode); + TPosition pos; + auto source = select.Build(query, pos); + if (!source) { + return nullptr; + } + return BuildSelectResult( + pos, + std::move(source), + false, + false, + viewParsingContext.Scoped + ); +} + } namespace NSQLTranslationV1 { @@ -4493,19 +4520,11 @@ bool TSqlTranslation::ParseViewQuery(std::map& features, const TString queryText = CollectTokens(query); features["query_text"] = {Ctx.Pos(), queryText}; - { - TSqlSelect select(Ctx, Mode); - TPosition pos; - auto source = select.Build(query, pos); - if (!source) { - return false; - } - features["query_ast"] = {BuildSelectResult(pos, - std::move(source), - false, - false, - Ctx.Scoped), Ctx}; + const auto viewSelect = BuildViewSelect(query, Ctx); + if (!viewSelect) { + return false; } + features["query_ast"] = {viewSelect, Ctx}; return true; }