diff options
author | aneporada <aneporada@ydb.tech> | 2022-12-07 12:15:08 +0300 |
---|---|---|
committer | aneporada <aneporada@ydb.tech> | 2022-12-07 12:15:08 +0300 |
commit | 62b457541e240a5ddad9a474cd0339951a166cb5 (patch) | |
tree | c7ed7ab2be3e15a27180610ac015fcdba7b7d535 | |
parent | c6801726ac1fd244024843fea3b8d4c76896090c (diff) | |
download | ydb-62b457541e240a5ddad9a474cd0339951a166cb5.tar.gz |
Emit proper error message when top level named subquery statement is found in libraries
-rw-r--r-- | ydb/library/yql/sql/v1/node.h | 1 | ||||
-rw-r--r-- | ydb/library/yql/sql/v1/select.cpp | 31 | ||||
-rw-r--r-- | ydb/library/yql/sql/v1/sql.cpp | 6 | ||||
-rw-r--r-- | ydb/library/yql/sql/v1/sql_ut.cpp | 21 |
4 files changed, 58 insertions, 1 deletions
diff --git a/ydb/library/yql/sql/v1/node.h b/ydb/library/yql/sql/v1/node.h index f2c60b8dcf..538202854f 100644 --- a/ydb/library/yql/sql/v1/node.h +++ b/ydb/library/yql/sql/v1/node.h @@ -1307,6 +1307,7 @@ namespace NSQLTranslationV1 { // Implemented in select.cpp TNodePtr BuildSubquery(TSourcePtr source, const TString& alias, bool inSubquery, int ensureTupleSize, TScopedStatePtr scoped); TNodePtr BuildSubqueryRef(TNodePtr subquery, const TString& alias, int tupleIndex = -1); + TNodePtr BuildInvalidSubqueryRef(TPosition subqueryPos); TNodePtr BuildSourceNode(TPosition pos, TSourcePtr source, bool checkExist = false); TSourcePtr BuildMuxSource(TPosition pos, TVector<TSourcePtr>&& sources); TSourcePtr BuildFakeSource(TPosition pos, bool missingFrom = false, bool inSubquery = false); diff --git a/ydb/library/yql/sql/v1/select.cpp b/ydb/library/yql/sql/v1/select.cpp index a7d2d0a8c4..c3fa583668 100644 --- a/ydb/library/yql/sql/v1/select.cpp +++ b/ydb/library/yql/sql/v1/select.cpp @@ -650,6 +650,37 @@ TNodePtr BuildSubqueryRef(TNodePtr subquery, const TString& alias, int tupleInde return new TSubqueryRefNode(std::move(subquery), alias, tupleIndex); } +class TInvalidSubqueryRefNode: public ISource { +public: + TInvalidSubqueryRefNode(TPosition pos) + : ISource(pos) + , Pos(pos) + { + } + + bool DoInit(TContext& ctx, ISource* src) override { + Y_UNUSED(src); + ctx.Error(Pos) << "Named subquery can not be used as a top level statement in libraries"; + return false; + } + + TNodePtr Build(TContext& ctx) override { + Y_UNUSED(ctx); + return {}; + } + + TPtr DoClone() const final { + return new TInvalidSubqueryRefNode(Pos); + } + +protected: + const TPosition Pos; +}; + +TNodePtr BuildInvalidSubqueryRef(TPosition subqueryPos) { + return new TInvalidSubqueryRefNode(subqueryPos); +} + class TTableSource: public IRealSource { public: TTableSource(TPosition pos, const TTableRef& table, const TString& label) diff --git a/ydb/library/yql/sql/v1/sql.cpp b/ydb/library/yql/sql/v1/sql.cpp index b3bd162c18..475ccc5d18 100644 --- a/ydb/library/yql/sql/v1/sql.cpp +++ b/ydb/library/yql/sql/v1/sql.cpp @@ -8634,7 +8634,11 @@ bool TSqlQuery::Statement(TVector<TNodePtr>& blocks, const TRule_sql_stmt_core& } TVector<TNodePtr> nodes; auto subquery = nodeExpr->GetSource(); - if (subquery) { + if (subquery && Mode == NSQLTranslation::ESqlMode::LIBRARY && Ctx.ScopeLevel == 0) { + for (size_t i = 0; i < names.size(); ++i) { + nodes.push_back(BuildInvalidSubqueryRef(subquery->GetPos())); + } + } else if (subquery) { const auto alias = Ctx.MakeName("subquerynode"); const auto ref = Ctx.MakeName("subquery"); blocks.push_back(BuildSubquery(subquery, alias, diff --git a/ydb/library/yql/sql/v1/sql_ut.cpp b/ydb/library/yql/sql/v1/sql_ut.cpp index 9fe02d1f2a..6e993d79a4 100644 --- a/ydb/library/yql/sql/v1/sql_ut.cpp +++ b/ydb/library/yql/sql/v1/sql_ut.cpp @@ -3551,6 +3551,27 @@ select FormatType($f()); "<main>:1:42: Error: Source does not allow column references\n" "<main>:1:71: Error: Column reference 'subkey'\n"); } + + Y_UNIT_TEST(ErrorInLibraryWithTopLevelNamedSubquery) { + TString withUnusedSubq = "$unused = select max(key) from plato.Input;\n" + "\n" + "define subquery $foo() as\n" + " $count = select count(*) from plato.Input;\n" + " select * from plato.Input limit $count / 2;\n" + "end define;\n" + "export $foo;\n"; + UNIT_ASSERT(SqlToYqlWithMode(withUnusedSubq, NSQLTranslation::ESqlMode::LIBRARY).IsOk()); + + TString withTopLevelSubq = "$count = select count(*) from plato.Input;\n" + "\n" + "define subquery $foo() as\n" + " select * from plato.Input limit $count / 2;\n" + "end define;\n" + "export $foo;\n"; + auto res = SqlToYqlWithMode(withTopLevelSubq, NSQLTranslation::ESqlMode::LIBRARY); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:17: Error: Named subquery can not be used as a top level statement in libraries\n"); + } } void CheckUnused(const TString& req, const TString& symbol, unsigned row, unsigned col) { |