diff options
author | deminds <[email protected]> | 2025-03-11 13:59:51 +0300 |
---|---|---|
committer | deminds <[email protected]> | 2025-03-11 14:18:49 +0300 |
commit | a524c2bc110ac3ca4cf6547f1f5e41ce28391ebb (patch) | |
tree | 5c0b46c6037608f97182f4a27de4a92f3173e93a /yql/essentials/sql/v1/sql_translation.cpp | |
parent | 611f4466195f72f44d869385122cad3cfc89a183 (diff) |
view: use parent context for query AST building
Issues:
* <HIDDEN_URL>
* <https://github.com/ydb-platform/ydb/issues/14709>
Previously it was impossible to create a simple view like the following:
```sql
CREATE VIEW demo_view WITH (security_invoker = TRUE) AS
SELECT
"bbb" LIKE Unwrap("aaa")
```
The problem was caused by the fact that a separate parsing context was used to build a view select AST for later validation. The list of UDFs is global for the whole parsing process to optimize the calculations. This global list was lost in the separate context and the view validation failed in such cases.
We fix the issue by using the same context for the view query validation in which the `CREATE VIEW` statement is executed. Moreover, we have started capturing all the statements in the view query text that can affect the compilation (see the `NeedUseForAllStatements` function).
commit_hash:f84d54ff1688fb43af7170a4db35f6729f2c4f10
Diffstat (limited to 'yql/essentials/sql/v1/sql_translation.cpp')
-rw-r--r-- | yql/essentials/sql/v1/sql_translation.cpp | 109 |
1 files changed, 40 insertions, 69 deletions
diff --git a/yql/essentials/sql/v1/sql_translation.cpp b/yql/essentials/sql/v1/sql_translation.cpp index 138d4dbae55..df9f48f262a 100644 --- a/yql/essentials/sql/v1/sql_translation.cpp +++ b/yql/essentials/sql/v1/sql_translation.cpp @@ -19,6 +19,8 @@ namespace { using namespace NSQLTranslationV1; +using NSQLTranslation::ESqlMode; + template <typename Callback> void VisitAllFields(const NProtoBuf::Message& msg, Callback& callback) { const auto* descr = msg.GetDescriptor(); @@ -54,68 +56,49 @@ TString CollectTokens(const TRule_select_stmt& selectStatement) { return tokenCollector.Tokens; } -bool RecreateContext( - TContext& ctx, const NSQLTranslation::TTranslationSettings& settings, const TString& recreationQuery -) { - if (!recreationQuery) { - return true; - } - const TString queryName = "context recreation query"; - - const auto* ast = NSQLTranslationV1::SqlAST( - ctx.Parsers, - recreationQuery, queryName, ctx.Issues, - settings.MaxErrors, settings.AnsiLexer, settings.Antlr4Parser, settings.Arena - ); - if (!ast) { +bool BuildContextRecreationQuery(TContext& context, TStringBuilder& query) { + TVector<TString> statements; + if (!SplitQueryToStatements(context.Lexers, context.Parsers, context.Query, statements, context.Issues, context.Settings)) { return false; } - TSqlQuery queryTranslator(ctx, ctx.Settings.Mode, true); - auto node = queryTranslator.Build(static_cast<const TSQLv1ParserAST&>(*ast)); - - return node && node->Init(ctx, nullptr) && node->Translate(ctx); + for (size_t id : context.ForAllStatementsParts) { + query << statements[id] << '\n'; + } + return true; } -TNodePtr BuildViewSelect( - const TRule_select_stmt& selectStatement, - TContext& parentContext, - const TString& contextRecreationQuery -) { - TIssues issues; - TContext context(parentContext.Lexers, parentContext.Parsers, parentContext.Settings, {}, issues, parentContext.Query); - if (!RecreateContext(context, context.Settings, contextRecreationQuery)) { - parentContext.Issues.AddIssues(issues); - return nullptr; - } - issues.Clear(); +// ensures that the parsing mode is restored to the original value +class TModeGuard { + ESqlMode& Mode; + ESqlMode OriginalMode; - // Holds (among other things) subquery references. - // These references need to be passed to the parent context - // to be able to compile view queries with subqueries. - context.PushCurrentBlocks(&parentContext.GetCurrentBlocks()); +public: + TModeGuard(ESqlMode& mode, ESqlMode newMode) + : Mode(mode) + , OriginalMode(std::exchange(mode, newMode)) + {} - context.Settings.Mode = NSQLTranslation::ESqlMode::LIMITED_VIEW; + ~TModeGuard() { + Mode = OriginalMode; + } +}; +TNodePtr BuildViewSelect(const TRule_select_stmt& selectStatement, TContext& context) { + TModeGuard guard(context.Settings.Mode, ESqlMode::LIMITED_VIEW); TSqlSelect selectTranslator(context, context.Settings.Mode); - TPosition pos = parentContext.Pos(); - auto source = selectTranslator.Build(selectStatement, pos); + auto position = context.Pos(); + auto source = selectTranslator.Build(selectStatement, position); if (!source) { - parentContext.Issues.AddIssues(issues); return nullptr; } - auto node = BuildSelectResult( - pos, - std::move(source), - false, - false, + return BuildSelectResult( + position, + source, + false, /* write result */ + false, /* in subquery */ context.Scoped ); - if (!node) { - parentContext.Issues.AddIssues(issues); - return nullptr; - } - return node; } } @@ -5129,32 +5112,20 @@ bool TSqlTranslation::ParseViewQuery( std::map<TString, TDeferredAtom>& features, const TRule_select_stmt& query ) { - TString queryText = CollectTokens(query); - TString contextRecreationQuery; - { - const auto& service = Ctx.Scoped->CurrService; - const auto& cluster = Ctx.Scoped->CurrCluster; - const auto effectivePathPrefix = Ctx.GetPrefixPath(service, cluster); - - // TO DO: capture all runtime pragmas in a similar fashion. - if (effectivePathPrefix != Ctx.Settings.PathPrefix) { - contextRecreationQuery = TStringBuilder() << "PRAGMA TablePathPrefix = \"" << effectivePathPrefix << "\";\n"; - } - - // TO DO: capture other compilation-affecting statements except USE. - if (cluster.GetLiteral() && *cluster.GetLiteral() != Ctx.Settings.DefaultCluster) { - contextRecreationQuery = TStringBuilder() << "USE " << *cluster.GetLiteral() << ";\n"; - } + TStringBuilder queryText; + if (!BuildContextRecreationQuery(Ctx, queryText)) { + return false; } - features["query_text"] = { Ctx.Pos(), contextRecreationQuery + queryText }; + queryText << CollectTokens(query); + features["query_text"] = { Ctx.Pos(), queryText }; - // AST is needed for ready-made validation of CREATE VIEW statement. - // Query is stored as plain text, not AST. - const auto viewSelect = BuildViewSelect(query, Ctx, contextRecreationQuery); + // The AST is needed solely for the validation of the CREATE VIEW statement. + // The final storage format for the query is a plain text, not an AST. + const auto viewSelect = BuildViewSelect(query, Ctx); if (!viewSelect) { return false; } - features["query_ast"] = {viewSelect, Ctx}; + features["query_ast"] = { viewSelect, Ctx }; return true; } |