Skip to content

Commit d14f770

Browse files
authored
25-1, VIEW: use parent context for query AST building (#15568)
1 parent 94b1ae8 commit d14f770

File tree

9 files changed

+95
-69
lines changed

9 files changed

+95
-69
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
CREATE VIEW `view_with_udf` WITH (security_invoker = TRUE) AS
2+
SELECT
3+
"bbb" LIKE Unwrap("aaa")
4+
;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DROP VIEW `view_with_udf`;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
SELECT
2+
*
3+
FROM (
4+
SELECT
5+
"bbb" LIKE Unwrap("aaa")
6+
);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
SELECT
2+
*
3+
FROM
4+
`view_with_udf`
5+
;

yql/essentials/sql/v1/object_processing.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,26 @@ INode::TPtr TCreateObject::FillFeatures(INode::TPtr options) const {
5757
return options;
5858
}
5959

60+
namespace {
61+
62+
bool InitFeatures(TContext& ctx, ISource* src, std::map<TString, TDeferredAtom>& features) {
63+
for (auto& [key, value] : features) {
64+
if (value.HasNode() && !value.Build()->Init(ctx, src)) {
65+
return false;
66+
}
67+
}
68+
return true;
69+
}
70+
71+
}
72+
73+
bool TCreateObject::DoInit(TContext& ctx, ISource* src) {
74+
if (!InitFeatures(ctx, src, Features)) {
75+
return false;
76+
}
77+
return TObjectProcessorImpl::DoInit(ctx, src);
78+
}
79+
6080
TObjectOperatorContext::TObjectOperatorContext(TScopedStatePtr scoped)
6181
: Scoped(scoped)
6282
, ServiceId(Scoped->CurrService)

yql/essentials/sql/v1/object_processing.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class TCreateObject: public TObjectProcessorImpl {
5555
return Y(Q(Y(Q("mode"), Q(mode))));
5656
}
5757
virtual INode::TPtr FillFeatures(INode::TPtr options) const override;
58+
bool DoInit(TContext& ctx, ISource* src) override;
5859
public:
5960
TCreateObject(TPosition pos, const TString& objectId,
6061
const TString& typeId, bool existingOk, bool replaceIfExists, std::map<TString, TDeferredAtom>&& features, std::set<TString>&& featuresToReset, const TObjectOperatorContext& context)

yql/essentials/sql/v1/sql_translation.cpp

Lines changed: 40 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ namespace {
2020

2121
using namespace NSQLTranslationV1;
2222

23+
using NSQLTranslation::ESqlMode;
24+
2325
template <typename Callback>
2426
void VisitAllFields(const NProtoBuf::Message& msg, Callback& callback) {
2527
const auto* descr = msg.GetDescriptor();
@@ -55,68 +57,49 @@ TString CollectTokens(const TRule_select_stmt& selectStatement) {
5557
return tokenCollector.Tokens;
5658
}
5759

58-
bool RecreateContext(
59-
TContext& ctx, const NSQLTranslation::TTranslationSettings& settings, const TString& recreationQuery
60-
) {
61-
if (!recreationQuery) {
62-
return true;
63-
}
64-
const TString queryName = "context recreation query";
65-
66-
const auto* ast = NSQLTranslationV1::SqlAST(
67-
ctx.Parsers,
68-
recreationQuery, queryName, ctx.Issues,
69-
settings.MaxErrors, settings.AnsiLexer, settings.Antlr4Parser, settings.Arena
70-
);
71-
if (!ast) {
60+
bool BuildContextRecreationQuery(TContext& context, TStringBuilder& query) {
61+
TVector<TString> statements;
62+
if (!SplitQueryToStatements(context.Lexers, context.Parsers, context.Query, statements, context.Issues, context.Settings)) {
7263
return false;
7364
}
7465

75-
TSqlQuery queryTranslator(ctx, ctx.Settings.Mode, true);
76-
auto node = queryTranslator.Build(static_cast<const TSQLv1ParserAST&>(*ast));
77-
78-
return node && node->Init(ctx, nullptr) && node->Translate(ctx);
66+
for (size_t id : context.ForAllStatementsParts) {
67+
query << statements[id] << '\n';
68+
}
69+
return true;
7970
}
8071

81-
TNodePtr BuildViewSelect(
82-
const TRule_select_stmt& selectStatement,
83-
TContext& parentContext,
84-
const TString& contextRecreationQuery
85-
) {
86-
TIssues issues;
87-
TContext context(parentContext.Lexers, parentContext.Parsers, parentContext.Settings, {}, issues, parentContext.Query);
88-
if (!RecreateContext(context, context.Settings, contextRecreationQuery)) {
89-
parentContext.Issues.AddIssues(issues);
90-
return nullptr;
91-
}
92-
issues.Clear();
72+
// ensures that the parsing mode is restored to the original value
73+
class TModeGuard {
74+
ESqlMode& Mode;
75+
ESqlMode OriginalMode;
9376

94-
// Holds (among other things) subquery references.
95-
// These references need to be passed to the parent context
96-
// to be able to compile view queries with subqueries.
97-
context.PushCurrentBlocks(&parentContext.GetCurrentBlocks());
77+
public:
78+
TModeGuard(ESqlMode& mode, ESqlMode newMode)
79+
: Mode(mode)
80+
, OriginalMode(std::exchange(mode, newMode))
81+
{}
9882

99-
context.Settings.Mode = NSQLTranslation::ESqlMode::LIMITED_VIEW;
83+
~TModeGuard() {
84+
Mode = OriginalMode;
85+
}
86+
};
10087

88+
TNodePtr BuildViewSelect(const TRule_select_stmt& selectStatement, TContext& context) {
89+
TModeGuard guard(context.Settings.Mode, ESqlMode::LIMITED_VIEW);
10190
TSqlSelect selectTranslator(context, context.Settings.Mode);
102-
TPosition pos = parentContext.Pos();
103-
auto source = selectTranslator.Build(selectStatement, pos);
91+
auto position = context.Pos();
92+
auto source = selectTranslator.Build(selectStatement, position);
10493
if (!source) {
105-
parentContext.Issues.AddIssues(issues);
10694
return nullptr;
10795
}
108-
auto node = BuildSelectResult(
109-
pos,
110-
std::move(source),
111-
false,
112-
false,
96+
return BuildSelectResult(
97+
position,
98+
source,
99+
false, /* write result */
100+
false, /* in subquery */
113101
context.Scoped
114102
);
115-
if (!node) {
116-
parentContext.Issues.AddIssues(issues);
117-
return nullptr;
118-
}
119-
return node;
120103
}
121104

122105
}
@@ -5130,32 +5113,20 @@ bool TSqlTranslation::ParseViewQuery(
51305113
std::map<TString, TDeferredAtom>& features,
51315114
const TRule_select_stmt& query
51325115
) {
5133-
TString queryText = CollectTokens(query);
5134-
TString contextRecreationQuery;
5135-
{
5136-
const auto& service = Ctx.Scoped->CurrService;
5137-
const auto& cluster = Ctx.Scoped->CurrCluster;
5138-
const auto effectivePathPrefix = Ctx.GetPrefixPath(service, cluster);
5139-
5140-
// TO DO: capture all runtime pragmas in a similar fashion.
5141-
if (effectivePathPrefix != Ctx.Settings.PathPrefix) {
5142-
contextRecreationQuery = TStringBuilder() << "PRAGMA TablePathPrefix = \"" << effectivePathPrefix << "\";\n";
5143-
}
5144-
5145-
// TO DO: capture other compilation-affecting statements except USE.
5146-
if (cluster.GetLiteral() && *cluster.GetLiteral() != Ctx.Settings.DefaultCluster) {
5147-
contextRecreationQuery = TStringBuilder() << "USE " << *cluster.GetLiteral() << ";\n";
5148-
}
5116+
TStringBuilder queryText;
5117+
if (!BuildContextRecreationQuery(Ctx, queryText)) {
5118+
return false;
51495119
}
5150-
features["query_text"] = { Ctx.Pos(), contextRecreationQuery + queryText };
5120+
queryText << CollectTokens(query);
5121+
features["query_text"] = { Ctx.Pos(), queryText };
51515122

5152-
// AST is needed for ready-made validation of CREATE VIEW statement.
5153-
// Query is stored as plain text, not AST.
5154-
const auto viewSelect = BuildViewSelect(query, Ctx, contextRecreationQuery);
5123+
// The AST is needed solely for the validation of the CREATE VIEW statement.
5124+
// The final storage format for the query is a plain text, not an AST.
5125+
const auto viewSelect = BuildViewSelect(query, Ctx);
51555126
if (!viewSelect) {
51565127
return false;
51575128
}
5158-
features["query_ast"] = {viewSelect, Ctx};
5129+
features["query_ast"] = { viewSelect, Ctx };
51595130

51605131
return true;
51615132
}

yql/essentials/sql/v1/sql_ut.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7392,6 +7392,15 @@ Y_UNIT_TEST_SUITE(TViewSyntaxTest) {
73927392
UNIT_ASSERT_C(res.Root, res.Issues.ToString());
73937393
}
73947394

7395+
Y_UNIT_TEST(CreateViewWithUdfs) {
7396+
NYql::TAstParseResult res = SqlToYql(R"(
7397+
USE plato;
7398+
CREATE VIEW TheView WITH (security_invoker = TRUE) AS SELECT "bbb" LIKE Unwrap("aaa");
7399+
)"
7400+
);
7401+
UNIT_ASSERT_C(res.Root, res.Issues.ToString());
7402+
}
7403+
73957404
Y_UNIT_TEST(CreateViewIfNotExists) {
73967405
constexpr const char* name = "TheView";
73977406
NYql::TAstParseResult res = SqlToYql(std::format(R"(

yql/essentials/sql/v1/sql_ut_antlr4.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7389,6 +7389,15 @@ Y_UNIT_TEST_SUITE(TViewSyntaxTest) {
73897389
UNIT_ASSERT_C(res.Root, res.Issues.ToString());
73907390
}
73917391

7392+
Y_UNIT_TEST(CreateViewWithUdfs) {
7393+
NYql::TAstParseResult res = SqlToYql(R"(
7394+
USE plato;
7395+
CREATE VIEW TheView WITH (security_invoker = TRUE) AS SELECT "bbb" LIKE Unwrap("aaa");
7396+
)"
7397+
);
7398+
UNIT_ASSERT_C(res.Root, res.Issues.ToString());
7399+
}
7400+
73927401
Y_UNIT_TEST(CreateViewIfNotExists) {
73937402
constexpr const char* name = "TheView";
73947403
NYql::TAstParseResult res = SqlToYql(std::format(R"(

0 commit comments

Comments
 (0)