diff options
author | ivanmorozov <ivanmorozov@yandex-team.com> | 2022-11-17 15:27:11 +0300 |
---|---|---|
committer | ivanmorozov <ivanmorozov@yandex-team.com> | 2022-11-17 15:27:11 +0300 |
commit | 2ea084bfc239ef31c3483557bcccd2871b59dc42 (patch) | |
tree | 81c2ff02c423159557f32a5d805583ddc6513621 | |
parent | de958bc48ec6f97a3ea97a990bfa5ddae7ada4a7 (diff) | |
download | ydb-2ea084bfc239ef31c3483557bcccd2871b59dc42.tar.gz |
object workflow in yql
-rw-r--r-- | ydb/library/yql/sql/v1/CMakeLists.txt | 1 | ||||
-rw-r--r-- | ydb/library/yql/sql/v1/SQLv1.g.in | 42 | ||||
-rw-r--r-- | ydb/library/yql/sql/v1/format/sql_format.cpp | 23 | ||||
-rw-r--r-- | ydb/library/yql/sql/v1/format/sql_format_ut.cpp | 14 | ||||
-rw-r--r-- | ydb/library/yql/sql/v1/node.h | 7 | ||||
-rw-r--r-- | ydb/library/yql/sql/v1/object_processing.cpp | 62 | ||||
-rw-r--r-- | ydb/library/yql/sql/v1/object_processing.h | 76 | ||||
-rw-r--r-- | ydb/library/yql/sql/v1/query.cpp | 16 | ||||
-rw-r--r-- | ydb/library/yql/sql/v1/sql.cpp | 213 | ||||
-rw-r--r-- | ydb/library/yql/sql/v1/sql_ut.cpp | 121 |
10 files changed, 533 insertions, 42 deletions
diff --git a/ydb/library/yql/sql/v1/CMakeLists.txt b/ydb/library/yql/sql/v1/CMakeLists.txt index 03584bb68e2..9d15e3cb086 100644 --- a/ydb/library/yql/sql/v1/CMakeLists.txt +++ b/ydb/library/yql/sql/v1/CMakeLists.txt @@ -51,6 +51,7 @@ target_sources(yql-sql-v1 PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/sql/v1/select.cpp ${CMAKE_SOURCE_DIR}/ydb/library/yql/sql/v1/sql.cpp ${CMAKE_SOURCE_DIR}/ydb/library/yql/sql/v1/query.cpp + ${CMAKE_SOURCE_DIR}/ydb/library/yql/sql/v1/object_processing.cpp ) generate_enum_serilization(yql-sql-v1 ${CMAKE_SOURCE_DIR}/ydb/library/yql/sql/v1/node.h diff --git a/ydb/library/yql/sql/v1/SQLv1.g.in b/ydb/library/yql/sql/v1/SQLv1.g.in index d89c57ce850..5a5a0272bdb 100644 --- a/ydb/library/yql/sql/v1/SQLv1.g.in +++ b/ydb/library/yql/sql/v1/SQLv1.g.in @@ -44,6 +44,9 @@ sql_stmt_core: | create_group_stmt | alter_group_stmt | drop_role_stmt + | create_object_stmt + | alter_object_stmt + | drop_object_stmt ; expr: @@ -450,6 +453,38 @@ values_source_row: LPAREN expr_list RPAREN; simple_values_source: expr_list | select_stmt; +create_object_stmt: CREATE OBJECT object_ref + LPAREN + TYPE object_type_ref + create_object_features? + RPAREN +; +create_object_features: WITH object_features; + +alter_object_stmt: ALTER OBJECT object_ref + LPAREN + TYPE object_type_ref + alter_object_features + RPAREN +; +alter_object_features: SET object_features; + +drop_object_stmt: DROP OBJECT object_ref + LPAREN + TYPE object_type_ref + drop_object_options? + RPAREN +; +drop_object_options: WITH object_features; + +object_feature_value: an_id_or_type | bind_parameter; +object_feature_kv: an_id_or_type EQUALS object_feature_value; +object_feature_flag: an_id_or_type; +object_feature: object_feature_kv | object_feature_flag; +object_features: object_feature (COMMA object_feature)*; + +object_type_ref: an_id_or_type; + create_table_stmt: CREATE (TABLE | TABLESTORE) simple_table_ref LPAREN create_table_entry (COMMA create_table_entry)* RPAREN table_inherits? table_partition_by? @@ -534,7 +569,7 @@ changefeed_setting_value: STRING_VALUE | bool_value ; -changefeed_alter_settings: +changefeed_alter_settings: DISABLE | SET LPAREN changefeed_settings RPAREN ; @@ -593,7 +628,8 @@ table_hint: | SCHEMA EQUALS? LPAREN (struct_arg_positional (COMMA struct_arg_positional)*)? COMMA? RPAREN ; -simple_table_ref_core: ((cluster_expr DOT)? id_or_at) | AT? bind_parameter; +object_ref: (cluster_expr DOT)? id_or_at; +simple_table_ref_core: object_ref | AT? bind_parameter; simple_table_ref: simple_table_ref_core table_hints?; into_simple_table_ref: simple_table_ref (ERASE BY pure_column_list)?; @@ -1002,6 +1038,7 @@ keyword_compat: ( | TEMPORARY | THEN | TIES + | TYPE | TO | TRANSACTION | TRIGGER @@ -1318,6 +1355,7 @@ TEMP: T E M P; TEMPORARY: T E M P O R A R Y; THEN: T H E N; TIES: T I E S; +TYPE: T Y P E; TO: T O; TRANSACTION: T R A N S A C T I O N; TRIGGER: T R I G G E R; diff --git a/ydb/library/yql/sql/v1/format/sql_format.cpp b/ydb/library/yql/sql/v1/format/sql_format.cpp index 53a1381dbcc..4cddca2138d 100644 --- a/ydb/library/yql/sql/v1/format/sql_format.cpp +++ b/ydb/library/yql/sql/v1/format/sql_format.cpp @@ -901,6 +901,24 @@ private: VisitAllFields(TRule_drop_role_stmt::GetDescriptor(), msg); } + void VisitCreateObject(const TRule_create_object_stmt& msg) { + PosFromToken(msg.GetToken1()); + NewLine(); + VisitAllFields(TRule_create_object_stmt::GetDescriptor(), msg); + } + + void VisitAlterObject(const TRule_alter_object_stmt& msg) { + PosFromToken(msg.GetToken1()); + NewLine(); + VisitAllFields(TRule_alter_object_stmt::GetDescriptor(), msg); + } + + void VisitDropObject(const TRule_drop_object_stmt& msg) { + PosFromToken(msg.GetToken1()); + NewLine(); + VisitAllFields(TRule_drop_object_stmt::GetDescriptor(), msg); + } + void VisitAllFields(const NProtoBuf::Descriptor* descr, const NProtoBuf::Message& msg) { for (int i = 0; i < descr->field_count(); ++i) { const NProtoBuf::FieldDescriptor* fd = descr->field(i); @@ -1762,7 +1780,10 @@ TStaticData::TStaticData() {TRule_create_group_stmt::GetDescriptor(), MakeFunctor(&TVisitor::VisitCreateGroup)}, {TRule_alter_group_stmt::GetDescriptor(), MakeFunctor(&TVisitor::VisitAlterGroup)}, {TRule_drop_role_stmt::GetDescriptor(), MakeFunctor(&TVisitor::VisitDropRole)}, - }) + {TRule_create_object_stmt::GetDescriptor(), MakeFunctor(&TVisitor::VisitCreateObject)}, + {TRule_alter_object_stmt::GetDescriptor(), MakeFunctor(&TVisitor::VisitAlterObject)}, + {TRule_drop_object_stmt::GetDescriptor(), MakeFunctor(&TVisitor::VisitDropObject)}, + }) { // ensure that all statements has a visitor auto coreDescr = TRule_sql_stmt_core::GetDescriptor(); diff --git a/ydb/library/yql/sql/v1/format/sql_format_ut.cpp b/ydb/library/yql/sql/v1/format/sql_format_ut.cpp index a27d557e3ed..779398efb89 100644 --- a/ydb/library/yql/sql/v1/format/sql_format_ut.cpp +++ b/ydb/library/yql/sql/v1/format/sql_format_ut.cpp @@ -248,6 +248,20 @@ Y_UNIT_TEST_SUITE(CheckSqlFormatter) { setup.Run(cases); } + Y_UNIT_TEST(ObjectOperations) { + TCases cases = { + {"alter oBject usEr (TYpe abcde Set a = b)", + "ALTER OBJECT usEr (TYPE abcde SET a = b);\n"}, + {"creAte oBject usEr (tYpe abcde With a = b)", + "CREATE OBJECT usEr (TYPE abcde WITH a = b);\n"}, + {"dRop oBject usEr (tYpe abcde With aeEE)", + "DROP OBJECT usEr (TYPE abcde WITH aeEE);\n"} + }; + + TSetup setup; + setup.Run(cases); + } + Y_UNIT_TEST(AlterTable) { TCases cases = { {"alter table user add user int32", diff --git a/ydb/library/yql/sql/v1/node.h b/ydb/library/yql/sql/v1/node.h index e47b8ce49ab..e5591e42b3a 100644 --- a/ydb/library/yql/sql/v1/node.h +++ b/ydb/library/yql/sql/v1/node.h @@ -82,6 +82,7 @@ namespace NSQLTranslationV1 { class ITableKeys; class ISource; class IAggregation; + class TObjectOperatorContext; typedef TIntrusivePtr<IAggregation> TAggregationPtr; struct TScopedState; @@ -1380,6 +1381,12 @@ namespace NSQLTranslationV1 { TScopedStatePtr scoped); TNodePtr BuildRenameGroup(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TDeferredAtom& newName, TScopedStatePtr scoped); TNodePtr BuildDropRoles(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TVector<TDeferredAtom>& toDrop, bool isUser, bool force, TScopedStatePtr scoped); + TNodePtr BuildCreateObjectOperation(TPosition pos, const TString& objectId, const TString& typeId, + std::map<TString, TDeferredAtom>&& features, const TObjectOperatorContext& context); + TNodePtr BuildAlterObjectOperation(TPosition pos, const TString& secretId, const TString& typeId, + std::map<TString, TDeferredAtom>&& features, const TObjectOperatorContext& context); + TNodePtr BuildDropObjectOperation(TPosition pos, const TString& secretId, const TString& typeId, + std::map<TString, TDeferredAtom>&& options, const TObjectOperatorContext& context); TNodePtr BuildWriteTable(TPosition pos, const TString& label, const TTableRef& table, EWriteColumnMode mode, TNodePtr options, TScopedStatePtr scoped); TNodePtr BuildWriteResult(TPosition pos, const TString& label, TNodePtr settings); diff --git a/ydb/library/yql/sql/v1/object_processing.cpp b/ydb/library/yql/sql/v1/object_processing.cpp new file mode 100644 index 00000000000..d59b52efd95 --- /dev/null +++ b/ydb/library/yql/sql/v1/object_processing.cpp @@ -0,0 +1,62 @@ +#include "object_processing.h" + +#include <ydb/library/yql/core/yql_callable_names.h> + +namespace NSQLTranslationV1 { +using namespace NYql; + +INode::TPtr TObjectProcessorImpl::BuildKeys() const { + auto keys = Y("Key"); + keys = L(keys, Q(Y(Q("objectId"), Y("String", BuildQuotedAtom(Pos, ObjectId))))); + keys = L(keys, Q(Y(Q("typeId"), Y("String", BuildQuotedAtom(Pos, TypeId))))); + return keys; +} + +TObjectProcessorImpl::TObjectProcessorImpl(TPosition pos, const TString& objectId, const TString& typeId, const TObjectOperatorContext& context) + : TBase(pos) + , TObjectOperatorContext(context) + , ObjectId(objectId) + , TypeId(typeId) +{ + +} + +bool TObjectProcessorImpl::DoInit(TContext& ctx, ISource* src) { + Y_UNUSED(src); + Scoped->UseCluster(ServiceId, Cluster); + auto options = FillFeatures(BuildOptions()); + auto keys = BuildKeys(); + + Add("block", Q(Y( + Y("let", "sink", Y("DataSink", BuildQuotedAtom(Pos, ServiceId), Scoped->WrapCluster(Cluster, ctx))), + Y("let", "world", Y(TString(WriteName), "world", "sink", keys, Y("Void"), Q(options))), + Y("return", ctx.PragmaAutoCommit ? Y(TString(CommitName), "world", "sink") : AstNode("world")) + ))); + return TAstListNode::DoInit(ctx, src); +} + +INode::TPtr TCreateObject::FillFeatures(INode::TPtr options) const { + if (Features.size()) { + auto features = Y(); + for (auto&& i : Features) { + if (!i.second.Empty()) { + features = L(features, Q(Y(BuildQuotedAtom(Pos, i.first), i.second.Build()))); + } else { + features = L(features, Q(Y(BuildQuotedAtom(Pos, i.first)))); + } + } + return L(options, Q(Y(Q("features"), Q(features)))); + } else { + return options; + } +} + +TObjectOperatorContext::TObjectOperatorContext(TScopedStatePtr scoped) + : Scoped(scoped) + , ServiceId(Scoped->CurrService) + , Cluster(Scoped->CurrCluster) +{ + +} + +} diff --git a/ydb/library/yql/sql/v1/object_processing.h b/ydb/library/yql/sql/v1/object_processing.h new file mode 100644 index 00000000000..a8ee0e1ef54 --- /dev/null +++ b/ydb/library/yql/sql/v1/object_processing.h @@ -0,0 +1,76 @@ +#pragma once +#include "node.h" +#include "context.h" + +namespace NSQLTranslationV1 { + +class TObjectOperatorContext { +protected: + TScopedStatePtr Scoped; +public: + TString ServiceId; + TDeferredAtom Cluster; + TObjectOperatorContext(const TObjectOperatorContext& baseItem) = default; + TObjectOperatorContext(TScopedStatePtr scoped); +}; + +class TObjectProcessorImpl: public TAstListNode, public TObjectOperatorContext { +protected: + using TBase = TAstListNode; + TString ObjectId; + TString TypeId; + + virtual INode::TPtr BuildOptions() const = 0; + virtual INode::TPtr FillFeatures(INode::TPtr options) const = 0; + INode::TPtr BuildKeys() const; +public: + TObjectProcessorImpl(TPosition pos, const TString& objectId, const TString& typeId, const TObjectOperatorContext& context); + + bool DoInit(TContext& ctx, ISource* src) override; + + TPtr DoClone() const final { + return {}; + } +}; + +class TCreateObject: public TObjectProcessorImpl { +private: + using TBase = TObjectProcessorImpl; + std::map<TString, TDeferredAtom> Features; +protected: + virtual INode::TPtr BuildOptions() const override { + return Y(Q(Y(Q("mode"), Q("createObject")))); + } + virtual INode::TPtr FillFeatures(INode::TPtr options) const override; +public: + TCreateObject(TPosition pos, const TString& objectId, + const TString& typeId, std::map<TString, TDeferredAtom>&& features, const TObjectOperatorContext& context) + : TBase(pos, objectId, typeId, context) + , Features(std::move(features)) { + + } +}; + +class TAlterObject final: public TCreateObject { +private: + using TBase = TCreateObject; +protected: + virtual INode::TPtr BuildOptions() const override { + return Y(Q(Y(Q("mode"), Q("alterObject")))); + } +public: + using TBase::TBase; +}; + +class TDropObject final: public TCreateObject { +private: + using TBase = TCreateObject; +protected: + virtual INode::TPtr BuildOptions() const override { + return Y(Q(Y(Q("mode"), Q("dropObject")))); + } +public: + using TBase::TBase; +}; + +} diff --git a/ydb/library/yql/sql/v1/query.cpp b/ydb/library/yql/sql/v1/query.cpp index fe45a5ffc49..359fb2e1b05 100644 --- a/ydb/library/yql/sql/v1/query.cpp +++ b/ydb/library/yql/sql/v1/query.cpp @@ -1,5 +1,6 @@ #include "node.h" #include "context.h" +#include "object_processing.h" #include <ydb/library/yql/ast/yql_type_string.h> #include <ydb/library/yql/core/yql_callable_names.h> @@ -1492,6 +1493,21 @@ private: TSourcePtr FakeSource; }; +TNodePtr BuildCreateObjectOperation(TPosition pos, const TString& objectId, const TString& typeId, + std::map<TString, TDeferredAtom>&& features, const TObjectOperatorContext& context) { + return new TCreateObject(pos, objectId, typeId, std::move(features), context); +} +TNodePtr BuildAlterObjectOperation(TPosition pos, const TString& secretId, const TString& typeId, + std::map<TString, TDeferredAtom>&& features, const TObjectOperatorContext& context) +{ + return new TAlterObject(pos, secretId, typeId, std::move(features), context); +} +TNodePtr BuildDropObjectOperation(TPosition pos, const TString& secretId, const TString& typeId, + std::map<TString, TDeferredAtom>&& options, const TObjectOperatorContext& context) +{ + return new TDropObject(pos, secretId, typeId, std::move(options), context); +} + TNodePtr BuildDropRoles(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TVector<TDeferredAtom>& toDrop, bool isUser, bool force, TScopedStatePtr scoped) { return new TDropRoles(pos, service, cluster, toDrop, isUser, force, scoped); } diff --git a/ydb/library/yql/sql/v1/sql.cpp b/ydb/library/yql/sql/v1/sql.cpp index 76bc57bc943..4a89518ead9 100644 --- a/ydb/library/yql/sql/v1/sql.cpp +++ b/ydb/library/yql/sql/v1/sql.cpp @@ -3,6 +3,7 @@ #include "context.h" #include "node.h" #include "sql_call_param.h" +#include "object_processing.h" #include "ydb/library/yql/ast/yql_ast.h" #include <ydb/library/yql/parser/lexer_common/hints.h> #include <ydb/library/yql/parser/proto_ast/collect_issues/collect_issues.h> @@ -496,27 +497,6 @@ static TIdentifier IdEx(const TRule& node, TTranslation& ctx) { return TIdentifier(pos, name); } -static TString OptIdPrefixAsStr(const TRule_opt_id_prefix& node, TTranslation& ctx, const TString& defaultStr = {}) { - if (!node.HasBlock1()) { - return defaultStr; - } - return Id(node.GetBlock1().GetRule_an_id1(), ctx); -} - -static TString OptIdPrefixAsStr(const TRule_opt_id_prefix_or_type& node, TTranslation& ctx, const TString& defaultStr = {}) { - if (!node.HasBlock1()) { - return defaultStr; - } - return Id(node.GetBlock1().GetRule_an_id_or_type1(), ctx); -} - -static void PureColumnListStr(const TRule_pure_column_list& node, TTranslation& ctx, TVector<TString>& outList) { - outList.push_back(Id(node.GetRule_an_id2(), ctx)); - for (auto& block: node.GetBlock3()) { - outList.push_back(Id(block.GetRule_an_id2(), ctx)); - } -} - static bool NamedNodeImpl(const TRule_bind_parameter& node, TString& name, TTranslation& ctx) { // bind_parameter: DOLLAR (an_id_or_type | TRUE | FALSE); TString id; @@ -543,6 +523,27 @@ static bool NamedNodeImpl(const TRule_bind_parameter& node, TString& name, TTran return true; } +static TString OptIdPrefixAsStr(const TRule_opt_id_prefix& node, TTranslation& ctx, const TString& defaultStr = {}) { + if (!node.HasBlock1()) { + return defaultStr; + } + return Id(node.GetBlock1().GetRule_an_id1(), ctx); +} + +static TString OptIdPrefixAsStr(const TRule_opt_id_prefix_or_type& node, TTranslation& ctx, const TString& defaultStr = {}) { + if (!node.HasBlock1()) { + return defaultStr; + } + return Id(node.GetBlock1().GetRule_an_id_or_type1(), ctx); +} + +static void PureColumnListStr(const TRule_pure_column_list& node, TTranslation& ctx, TVector<TString>& outList) { + outList.push_back(Id(node.GetRule_an_id2(), ctx)); + for (auto& block: node.GetBlock3()) { + outList.push_back(Id(block.GetRule_an_id2(), ctx)); + } +} + static bool NamedNodeImpl(const TRule_opt_bind_parameter& node, TString& name, bool& isOptional, TTranslation& ctx) { // opt_bind_parameter: bind_parameter QUESTION?; isOptional = false; @@ -896,6 +897,10 @@ protected: bool IsDistinctOptSet(const TRule_opt_set_quantifier& node) const; bool IsDistinctOptSet(const TRule_opt_set_quantifier& node, TPosition& distinctPos) const; + bool AddObjectFeature(std::map<TString, TDeferredAtom>& result, const TRule_object_feature& feature); + bool BindParameterClause(const TRule_bind_parameter& node, TDeferredAtom& result); + bool ObjectFeatureValueClause(const TRule_object_feature_value & node, TDeferredAtom & result); + bool ParseObjectFeatures(std::map<TString, TDeferredAtom> & result, const TRule_object_features & features); bool RoleNameClause(const TRule_role_name& node, TDeferredAtom& result, bool allowSystemRoles); bool RoleParameters(const TRule_create_user_option& node, TRoleParameters& result) ; private: @@ -3143,13 +3148,13 @@ bool TSqlTranslation::SimpleTableRefCoreImpl(const TRule_simple_table_ref_core& TDeferredAtom cluster = Context().Scoped->CurrCluster; switch (node.Alt_case()) { case TRule_simple_table_ref_core::AltCase::kAltSimpleTableRefCore1: { - if (node.GetAlt_simple_table_ref_core1().GetBlock1().HasBlock1()) { + if (node.GetAlt_simple_table_ref_core1().GetRule_object_ref1().HasBlock1()) { if (Mode == NSQLTranslation::ESqlMode::LIMITED_VIEW) { Error() << "Cluster should not be used in limited view"; return false; } - if (!ClusterExpr(node.GetAlt_simple_table_ref_core1().GetBlock1().GetBlock1().GetRule_cluster_expr1(), false, service, cluster)) { + if (!ClusterExpr(node.GetAlt_simple_table_ref_core1().GetRule_object_ref1().GetBlock1().GetRule_cluster_expr1(), false, service, cluster)) { return false; } } @@ -3160,7 +3165,7 @@ bool TSqlTranslation::SimpleTableRefCoreImpl(const TRule_simple_table_ref_core& } result = TTableRef(Context().MakeName("table"), service, cluster, nullptr); - auto tableOrAt = Id(node.GetAlt_simple_table_ref_core1().GetBlock1().GetRule_id_or_at2(), *this); + auto tableOrAt = Id(node.GetAlt_simple_table_ref_core1().GetRule_object_ref1().GetRule_id_or_at2(), *this); auto tableAndView = TableKeyImpl(tableOrAt, "", *this); result.Keys = BuildTableKey(Context().Pos(), result.Service, result.Cluster, TDeferredAtom(Context().Pos(), tableAndView.first), tableAndView.second); @@ -6407,22 +6412,17 @@ bool TSqlTranslation::IsDistinctOptSet(const TRule_opt_set_quantifier& node, TPo bool TSqlTranslation::RoleNameClause(const TRule_role_name& node, TDeferredAtom& result, bool allowSystemRoles) { // role_name: an_id_or_type | bind_parameter; switch (node.Alt_case()) { - case TRule_role_name::kAltRoleName1: { + case TRule_role_name::kAltRoleName1: + { TString name = Id(node.GetAlt_role_name1().GetRule_an_id_or_type1(), *this); result = TDeferredAtom(Ctx.Pos(), name); break; } - case TRule_role_name::kAltRoleName2: { - TString paramName; - if (!NamedNodeImpl(node.GetAlt_role_name2().GetRule_bind_parameter1(), paramName, *this)) { - return false; - } - auto named = GetNamedNode(paramName); - if (!named) { + case TRule_role_name::kAltRoleName2: + { + if (!BindParameterClause(node.GetAlt_role_name2().GetRule_bind_parameter1(), result)) { return false; } - - result = MakeAtomFromExpression(Ctx, named); break; } default: @@ -8219,9 +8219,9 @@ TNodePtr TSqlIntoTable::Build(const TRule_into_table_stmt& node) { bool isBinding = false; switch (tableRefCore.Alt_case()) { case TRule_simple_table_ref_core::AltCase::kAltSimpleTableRefCore1: { - if (tableRefCore.GetAlt_simple_table_ref_core1().GetBlock1().HasBlock1()) { - const auto& clusterExpr = tableRefCore.GetAlt_simple_table_ref_core1().GetBlock1().GetBlock1().GetRule_cluster_expr1(); - bool hasAt = tableRefCore.GetAlt_simple_table_ref_core1().GetBlock1().GetRule_id_or_at2().HasBlock1(); + if (tableRefCore.GetAlt_simple_table_ref_core1().GetRule_object_ref1().HasBlock1()) { + const auto& clusterExpr = tableRefCore.GetAlt_simple_table_ref_core1().GetRule_object_ref1().GetBlock1().GetRule_cluster_expr1(); + bool hasAt = tableRefCore.GetAlt_simple_table_ref_core1().GetRule_object_ref1().GetRule_id_or_at2().HasBlock1(); bool result = !hasAt ? ClusterExprOrBinding(clusterExpr, service, cluster, isBinding) : ClusterExpr(clusterExpr, false, service, cluster); if (!result) { @@ -8234,7 +8234,7 @@ TNodePtr TSqlIntoTable::Build(const TRule_into_table_stmt& node) { return nullptr; } - auto id = Id(tableRefCore.GetAlt_simple_table_ref_core1().GetBlock1().GetRule_id_or_at2(), *this); + auto id = Id(tableRefCore.GetAlt_simple_table_ref_core1().GetRule_object_ref1().GetRule_id_or_at2(), *this); nameOrAt = std::make_pair(id.first, TDeferredAtom(Ctx.Pos(), id.second)); break; } @@ -9000,7 +9000,8 @@ bool TSqlQuery::Statement(TVector<TNodePtr>& blocks, const TRule_sql_stmt_core& AddStatementToBlocks(blocks, stmt); break; } - case TRule_sql_stmt_core::kAltSqlStmtCore25: { + case TRule_sql_stmt_core::kAltSqlStmtCore25: + { // drop_role_stmt: DROP (USER|GROUP) (IF EXISTS)? role_name (COMMA role_name)* COMMA?; Ctx.BodyPart(); auto& node = core.GetAlt_sql_stmt_core25().GetRule_drop_role_stmt1(); @@ -9035,6 +9036,76 @@ bool TSqlQuery::Statement(TVector<TNodePtr>& blocks, const TRule_sql_stmt_core& AddStatementToBlocks(blocks, BuildDropRoles(pos, service, cluster, roles, isUser, force, Ctx.Scoped)); break; } + case TRule_sql_stmt_core::kAltSqlStmtCore26: + { + // create_object_stmt: CREATE OBJECT name (TYPE type [WITH k=v,...]); + auto& node = core.GetAlt_sql_stmt_core26().GetRule_create_object_stmt1(); + TObjectOperatorContext context(Ctx.Scoped); + if (node.GetRule_object_ref3().HasBlock1()) { + if (!ClusterExpr(node.GetRule_object_ref3().GetBlock1().GetRule_cluster_expr1(), + false, context.ServiceId, context.Cluster)) { + return false; + } + } + + const TString& objectId = Id(node.GetRule_object_ref3().GetRule_id_or_at2(), *this).second; + const TString& typeId = Id(node.GetRule_object_type_ref6().GetRule_an_id_or_type1(), *this); + std::map<TString, TDeferredAtom> kv; + if (node.HasBlock7()) { + if (!ParseObjectFeatures(kv, node.GetBlock7().GetRule_create_object_features1().GetRule_object_features2())) { + return false; + } + } + + AddStatementToBlocks(blocks, BuildCreateObjectOperation(Ctx.Pos(), objectId, typeId, std::move(kv), context)); + break; + } + case TRule_sql_stmt_core::kAltSqlStmtCore27: + { + // create_object_stmt: ALTER OBJECT name (TYPE type [SET k=v,...]); + auto& node = core.GetAlt_sql_stmt_core27().GetRule_alter_object_stmt1(); + TObjectOperatorContext context(Ctx.Scoped); + if (node.GetRule_object_ref3().HasBlock1()) { + if (!ClusterExpr(node.GetRule_object_ref3().GetBlock1().GetRule_cluster_expr1(), + false, context.ServiceId, context.Cluster)) { + return false; + } + } + + const TString& objectId = Id(node.GetRule_object_ref3().GetRule_id_or_at2(), *this).second; + const TString& typeId = Id(node.GetRule_object_type_ref6().GetRule_an_id_or_type1(), *this); + std::map<TString, TDeferredAtom> kv; + if (!ParseObjectFeatures(kv, node.GetRule_alter_object_features7().GetRule_object_features2())) { + return false; + } + + AddStatementToBlocks(blocks, BuildAlterObjectOperation(Ctx.Pos(), objectId, typeId, std::move(kv), context)); + break; + } + case TRule_sql_stmt_core::kAltSqlStmtCore28: + { + // create_object_stmt: DROP OBJECT name (TYPE type [WITH k=v,...]); + auto& node = core.GetAlt_sql_stmt_core28().GetRule_drop_object_stmt1(); + TObjectOperatorContext context(Ctx.Scoped); + if (node.GetRule_object_ref3().HasBlock1()) { + if (!ClusterExpr(node.GetRule_object_ref3().GetBlock1().GetRule_cluster_expr1(), + false, context.ServiceId, context.Cluster)) { + return false; + } + } + + const TString& objectId = Id(node.GetRule_object_ref3().GetRule_id_or_at2(), *this).second; + const TString& typeId = Id(node.GetRule_object_type_ref6().GetRule_an_id_or_type1(), *this); + std::map<TString, TDeferredAtom> kv; + if (node.HasBlock7()) { + if (!ParseObjectFeatures(kv, node.GetBlock7().GetRule_drop_object_options1().GetRule_object_features2())) { + return false; + } + } + + AddStatementToBlocks(blocks, BuildDropObjectOperation(Ctx.Pos(), objectId, typeId, std::move(kv), context)); + break; + } default: Ctx.IncrementMonCounter("sql_errors", "UnknownStatement" + internalStatementName); AltNotImplemented("sql_stmt_core", core); @@ -10512,4 +10583,68 @@ NYql::TAstParseResult SqlToYql(const TString& query, const NSQLTranslation::TTra return res; } +bool TSqlTranslation::BindParameterClause(const TRule_bind_parameter& node, TDeferredAtom& result) { + TString paramName; + if (!NamedNodeImpl(node, paramName, *this)) { + return false; + } + auto named = GetNamedNode(paramName); + if (!named) { + return false; + } + + result = MakeAtomFromExpression(Ctx, named); + return true; +} + +bool TSqlTranslation::ObjectFeatureValueClause(const TRule_object_feature_value& node, TDeferredAtom& result) { + // object_feature_value: an_id_or_type | bind_parameter; + switch (node.Alt_case()) { + case TRule_object_feature_value::kAltObjectFeatureValue1: + { + TString name = Id(node.GetAlt_object_feature_value1().GetRule_an_id_or_type1(), *this); + result = TDeferredAtom(Ctx.Pos(), name); + break; + } + case TRule_object_feature_value::kAltObjectFeatureValue2: + { + if (!BindParameterClause(node.GetAlt_object_feature_value2().GetRule_bind_parameter1(), result)) { + return false; + } + break; + } + default: + Y_FAIL("You should change implementation according to grammar changes"); + } + return true; +} + +bool TSqlTranslation::AddObjectFeature(std::map<TString, TDeferredAtom>& result, const TRule_object_feature& feature) { + if (feature.has_alt_object_feature1()) { + auto& kv = feature.GetAlt_object_feature1().GetRule_object_feature_kv1(); + const TString& key = Id(kv.GetRule_an_id_or_type1(), *this); + auto& ruleValue = kv.GetRule_object_feature_value3(); + TDeferredAtom value; + if (!ObjectFeatureValueClause(ruleValue, value)) { + return false; + } + result[key] = value; + } else if (feature.has_alt_object_feature2()) { + result[Id(feature.GetAlt_object_feature2().GetRule_object_feature_flag1().GetRule_an_id_or_type1(), *this)] = TDeferredAtom(); + } + return true; +} + +bool TSqlTranslation::ParseObjectFeatures(std::map<TString, TDeferredAtom>& result, const TRule_object_features& features) { + if (!AddObjectFeature(result, features.GetRule_object_feature1())) { + return false; + } + for (auto&& i : features.GetBlock2()) { + if (!AddObjectFeature(result, i.GetRule_object_feature2())) { + return false; + } + } + return true; +} + } // namespace NSQLTranslationV1 diff --git a/ydb/library/yql/sql/v1/sql_ut.cpp b/ydb/library/yql/sql/v1/sql_ut.cpp index 0d738034942..98a6b682b15 100644 --- a/ydb/library/yql/sql/v1/sql_ut.cpp +++ b/ydb/library/yql/sql/v1/sql_ut.cpp @@ -613,6 +613,127 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { UNIT_ASSERT(res.Root); } + Y_UNIT_TEST(CreateObjectWithFeatures) { + NYql::TAstParseResult res = SqlToYql("USE plato; CREATE OBJECT secretId (TYPE SECRET WITH Key1=Value1, K2=V2);"); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'('\"K2\" '\"V2\") '('\"Key1\" '\"Value1\")")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObject")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0}, {TString("SECRET"), 0} }; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SECRET"]); + } + + Y_UNIT_TEST(CreateObjectWithFeaturesAndFlags) { + NYql::TAstParseResult res = SqlToYql("USE plato; CREATE OBJECT secretId (TYPE SECRET WITH Key1=Value1, K2=V2, RECURSE);"); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'('\"Key1\" '\"Value1\") '('\"RECURSE\")")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObject")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0}, {TString("SECRET"), 0} }; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SECRET"]); + } + + Y_UNIT_TEST(CreateObjectNoFeatures) { + NYql::TAstParseResult res = SqlToYql("USE plato; CREATE OBJECT secretId (TYPE SECRET);"); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("'features")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObject")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0}, {TString("SECRET"), 0} }; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SECRET"]); + } + + Y_UNIT_TEST(AlterObjectWithFeatures) { + NYql::TAstParseResult res = SqlToYql( + "USE plato;\n" + "declare $path as String;\n" + "ALTER OBJECT secretId (TYPE SECRET SET Key1=$path, K2=V2);" + ); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'features")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'\"Key1\" (EvaluateAtom \"$path\"")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'\"K2\" '\"V2\"")); + + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("alterObject")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0}, {TString("SECRET"), 0} }; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SECRET"]); + } + + Y_UNIT_TEST(AlterObjectNoFeatures) { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER OBJECT secretId (TYPE SECRET);"); + UNIT_ASSERT(!res.Root); + Cerr << Err2Str(res) << Endl; + } + + Y_UNIT_TEST(DropObjectNoFeatures) { + NYql::TAstParseResult res = SqlToYql("USE plato; DROP OBJECT secretId (TYPE SECRET);"); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("'features")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("dropObject")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0}, {TString("SECRET"), 0} }; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SECRET"]); + } + + Y_UNIT_TEST(DropObjectWithFeatures) { + NYql::TAstParseResult res = SqlToYql("USE plato; DROP OBJECT secretId (TYPE SECRET WITH A, B, C);"); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'features")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("dropObject")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0}, {TString("SECRET"), 0} }; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SECRET"]); + } + Y_UNIT_TEST(PrimaryKeyParseCorrect) { NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE tableName (Key Uint32, Subkey Int64, Value String, PRIMARY KEY (Key, Subkey));"); UNIT_ASSERT(res.Root); |