diff options
author | shumkovnd <[email protected]> | 2024-11-21 22:29:26 +0300 |
---|---|---|
committer | shumkovnd <[email protected]> | 2024-11-21 22:51:14 +0300 |
commit | 74e7baa2f49d69b2f0385db557749750b6121a20 (patch) | |
tree | 6e7f4732613e61769184fa4aeaca53dc8913c761 | |
parent | 56de0f56882d2401ca734478ff95d91878e5bdbd (diff) |
Support ALTER SEQUENCE command
<https://github.com/ydb-platform/ydb/issues/11763>
commit_hash:5611cbe2f0e09543749e9866c5db8d427649e754
-rw-r--r-- | yql/essentials/sql/v1/SQLv1.g.in | 21 | ||||
-rw-r--r-- | yql/essentials/sql/v1/SQLv1Antlr4.g.in | 21 | ||||
-rw-r--r-- | yql/essentials/sql/v1/format/sql_format.cpp | 7 | ||||
-rw-r--r-- | yql/essentials/sql/v1/format/sql_format_ut.h | 11 | ||||
-rw-r--r-- | yql/essentials/sql/v1/node.h | 8 | ||||
-rw-r--r-- | yql/essentials/sql/v1/query.cpp | 104 | ||||
-rw-r--r-- | yql/essentials/sql/v1/source.h | 1 | ||||
-rw-r--r-- | yql/essentials/sql/v1/sql.cpp | 27 | ||||
-rw-r--r-- | yql/essentials/sql/v1/sql_query.cpp | 101 | ||||
-rw-r--r-- | yql/essentials/sql/v1/sql_query.h | 3 | ||||
-rw-r--r-- | yql/essentials/sql/v1/sql_ut.cpp | 147 | ||||
-rw-r--r-- | yql/essentials/sql/v1/sql_ut_antlr4.cpp | 147 |
12 files changed, 584 insertions, 14 deletions
diff --git a/yql/essentials/sql/v1/SQLv1.g.in b/yql/essentials/sql/v1/SQLv1.g.in index d2cc702174c..1b645f0b898 100644 --- a/yql/essentials/sql/v1/SQLv1.g.in +++ b/yql/essentials/sql/v1/SQLv1.g.in @@ -75,6 +75,7 @@ sql_stmt_core: | drop_resource_pool_classifier_stmt | backup_stmt | restore_stmt + | alter_sequence_stmt ; expr: @@ -1054,6 +1055,14 @@ analyze_table: simple_table_ref (LPAREN column_list RPAREN)?; analyze_table_list: analyze_table (COMMA analyze_table)* COMMA?; analyze_stmt: ANALYZE analyze_table_list; +alter_sequence_stmt: ALTER SEQUENCE (IF EXISTS)? object_ref alter_sequence_action+; +alter_sequence_action: + START WITH? integer + | RESTART WITH? integer + | RESTART + | INCREMENT BY? integer +; + // Special rules that allow to use certain keywords as identifiers. identifier: ID_PLAIN | ID_QUOTED; id: identifier | keyword; @@ -1339,6 +1348,7 @@ keyword_as_compat: | IMMEDIATE | IMPORT | IN + | INCREMENT | INCREMENTAL | INDEX | INDEXED @@ -1413,6 +1423,7 @@ keyword_as_compat: | REPLICATION | RESET | RESPECT + | RESTART | RESTORE | RESTRICT // | RESULT @@ -1430,7 +1441,9 @@ keyword_as_compat: | SETS | SHOW | SKIP + | SEQUENCE | SOURCE + | START | SUBQUERY | SUBSET | SYMBOLS @@ -1557,6 +1570,7 @@ keyword_compat: ( | IMMEDIATE | IMPORT | IN + | INCREMENT | INCREMENTAL | INDEX | INDEXED @@ -1631,6 +1645,7 @@ keyword_compat: ( | REPLICATION | RESET | RESPECT + | RESTART | RESTORE | RESTRICT | RESULT @@ -1648,7 +1663,9 @@ keyword_compat: ( | SETS | SHOW | SKIP + | SEQUENCE | SOURCE + | START | SUBQUERY | SUBSET | SYMBOLS @@ -1903,6 +1920,7 @@ ILIKE: I L I K E; IMMEDIATE: I M M E D I A T E; IMPORT: I M P O R T; IN: I N; +INCREMENT: I N C R E M E N T; INCREMENTAL: I N C R E M E N T A L; INDEX: I N D E X; INDEXED: I N D E X E D; @@ -1992,6 +2010,7 @@ REPLICATION: R E P L I C A T I O N; RESET: R E S E T; RESOURCE: R E S O U R C E; RESPECT: R E S P E C T; +RESTART: R E S T A R T; RESTORE: R E S T O R E; RESTRICT: R E S T R I C T; RESULT: R E S U L T; @@ -2016,7 +2035,9 @@ SET: S E T; SETS: S E T S; SHOW: S H O W; SKIP: S K I P; +SEQUENCE: S E Q U E N C E; SOURCE: S O U R C E; +START: S T A R T; STREAM: S T R E A M; STRUCT: S T R U C T; SUBQUERY: S U B Q U E R Y; diff --git a/yql/essentials/sql/v1/SQLv1Antlr4.g.in b/yql/essentials/sql/v1/SQLv1Antlr4.g.in index 02282d8ebf0..54355353365 100644 --- a/yql/essentials/sql/v1/SQLv1Antlr4.g.in +++ b/yql/essentials/sql/v1/SQLv1Antlr4.g.in @@ -74,6 +74,7 @@ sql_stmt_core: | drop_resource_pool_classifier_stmt | backup_stmt | restore_stmt + | alter_sequence_stmt ; expr: @@ -1053,6 +1054,14 @@ analyze_table: simple_table_ref (LPAREN column_list RPAREN)?; analyze_table_list: analyze_table (COMMA analyze_table)* COMMA?; analyze_stmt: ANALYZE analyze_table_list; +alter_sequence_stmt: ALTER SEQUENCE (IF EXISTS)? object_ref alter_sequence_action+; +alter_sequence_action: + START WITH? integer + | RESTART WITH? integer + | RESTART + | INCREMENT BY? integer +; + // Special rules that allow to use certain keywords as identifiers. identifier: ID_PLAIN | ID_QUOTED; id: identifier | keyword; @@ -1338,6 +1347,7 @@ keyword_as_compat: | IMMEDIATE | IMPORT | IN + | INCREMENT | INCREMENTAL | INDEX | INDEXED @@ -1412,6 +1422,7 @@ keyword_as_compat: | REPLICATION | RESET | RESPECT + | RESTART | RESTORE | RESTRICT // | RESULT @@ -1429,7 +1440,9 @@ keyword_as_compat: | SETS | SHOW | TSKIP + | SEQUENCE | SOURCE + | START | SUBQUERY | SUBSET | SYMBOLS @@ -1556,6 +1569,7 @@ keyword_compat: ( | IMMEDIATE | IMPORT | IN + | INCREMENT | INCREMENTAL | INDEX | INDEXED @@ -1630,6 +1644,7 @@ keyword_compat: ( | REPLICATION | RESET | RESPECT + | RESTART | RESTORE | RESTRICT | RESULT @@ -1647,7 +1662,9 @@ keyword_compat: ( | SETS | SHOW | TSKIP + | SEQUENCE | SOURCE + | START | SUBQUERY | SUBSET | SYMBOLS @@ -1902,6 +1919,7 @@ ILIKE: I L I K E; IMMEDIATE: I M M E D I A T E; IMPORT: I M P O R T; IN: I N; +INCREMENT: I N C R E M E N T; INCREMENTAL: I N C R E M E N T A L; INDEX: I N D E X; INDEXED: I N D E X E D; @@ -1991,6 +2009,7 @@ REPLICATION: R E P L I C A T I O N; RESET: R E S E T; RESOURCE: R E S O U R C E; RESPECT: R E S P E C T; +RESTART: R E S T A R T; RESTORE: R E S T O R E; RESTRICT: R E S T R I C T; RESULT: R E S U L T; @@ -2015,7 +2034,9 @@ SET: S E T; SETS: S E T S; SHOW: S H O W; TSKIP: S K I P; +SEQUENCE: S E Q U E N C E; SOURCE: S O U R C E; +START: S T A R T; STREAM: S T R E A M; STRUCT: S T R U C T; SUBQUERY: S U B Q U E R Y; diff --git a/yql/essentials/sql/v1/format/sql_format.cpp b/yql/essentials/sql/v1/format/sql_format.cpp index 262f9b29198..3cc18b141bb 100644 --- a/yql/essentials/sql/v1/format/sql_format.cpp +++ b/yql/essentials/sql/v1/format/sql_format.cpp @@ -962,6 +962,12 @@ private: VisitAllFields(TRule_use_stmt::GetDescriptor(), msg); } + void VisitAlterSequence(const TRule_alter_sequence_stmt& msg) { + PosFromToken(msg.GetToken1()); + NewLine(); + VisitAllFields(TRule_alter_sequence_stmt::GetDescriptor(), msg); + } + void VisitIntoTable(const TRule_into_table_stmt& msg) { switch (msg.GetBlock1().Alt_case()) { case TRule_into_table_stmt_TBlock1::AltCase::kAlt1: @@ -2915,6 +2921,7 @@ TStaticData::TStaticData() {TRule_drop_resource_pool_classifier_stmt::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitDropResourcePoolClassifier)}, {TRule_backup_stmt::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitBackup)}, {TRule_restore_stmt::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitRestore)}, + {TRule_alter_sequence_stmt::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitAlterSequence)}, }) , ObfuscatingVisitDispatch({ {TToken::GetDescriptor(), MakeObfuscatingFunctor(&TObfuscatingVisitor::VisitToken)}, diff --git a/yql/essentials/sql/v1/format/sql_format_ut.h b/yql/essentials/sql/v1/format/sql_format_ut.h index 021d57c8b13..fc919b38c43 100644 --- a/yql/essentials/sql/v1/format/sql_format_ut.h +++ b/yql/essentials/sql/v1/format/sql_format_ut.h @@ -115,6 +115,17 @@ Y_UNIT_TEST(AlterGroup) { setup.Run(cases); } +Y_UNIT_TEST(AlterSequence) { + TCases cases = { + {"use plato;alter sequence sequence start with 10 increment 2 restart with 5;","USE plato;\n\nALTER SEQUENCE sequence START WITH 10 INCREMENT 2 RESTART WITH 5;\n"}, + {"use plato;alter sequence if exists sequence increment 1000 start 100 restart;","USE plato;\n\nALTER SEQUENCE IF EXISTS sequence INCREMENT 1000 START 100 RESTART;\n"}, + }; + + TSetup setup; + setup.Run(cases); +} + + Y_UNIT_TEST(Use) { TCases cases = { {"use user;","USE user;\n"}, diff --git a/yql/essentials/sql/v1/node.h b/yql/essentials/sql/v1/node.h index 53f606cc6b0..99f42f353cd 100644 --- a/yql/essentials/sql/v1/node.h +++ b/yql/essentials/sql/v1/node.h @@ -1300,6 +1300,14 @@ namespace NSQLTranslationV1 { TVector<TDeferredAtom> Roles; }; + struct TSequenceParameters { + bool MissingOk = false; + TMaybe<TDeferredAtom> StartValue; + bool IsRestart = false; + TMaybe<TDeferredAtom> RestartValue; + TMaybe<TDeferredAtom> Increment; + }; + struct TTopicConsumerSettings { struct TLocalSinkSettings { // no special settings diff --git a/yql/essentials/sql/v1/query.cpp b/yql/essentials/sql/v1/query.cpp index dc71f573811..8e71da31460 100644 --- a/yql/essentials/sql/v1/query.cpp +++ b/yql/essentials/sql/v1/query.cpp @@ -2049,6 +2049,110 @@ TNodePtr BuildAlterUser(TPosition pos, const TString& service, const TDeferredAt return new TAlterUser(pos, service, cluster, name, params, scoped); } +class TAlterSequence final: public TAstListNode { +public: + TAlterSequence(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TString& id, const TSequenceParameters& params, TScopedStatePtr scoped) + : TAstListNode(pos) + , Service(service) + , Cluster(cluster) + , Id(id) + , Params(params) + , Scoped(scoped) + { + FakeSource = BuildFakeSource(pos); + scoped->UseCluster(service, cluster); + } + + bool DoInit(TContext& ctx, ISource* src) override { + Y_UNUSED(src); + + TNodePtr cluster = Scoped->WrapCluster(Cluster, ctx); + + if (!cluster->Init(ctx, FakeSource.Get())) { + return false; + } + + auto options = Y(); + TString mode = Params.MissingOk ? "alter_if_exists" : "alter"; + options = L(options, Q(Y(Q("mode"), Q(mode)))); + + if (Params.IsRestart) { + if (Params.RestartValue) { + TString strValue = Params.RestartValue->Build()->GetLiteralValue(); + ui64 value = FromString<ui64>(strValue); + ui64 maxValue = ui64(std::numeric_limits<i64>::max()); + ui64 minValue = 1; + if (value > maxValue) { + ctx.Error(Pos) << "Restart value: " << value << " cannot be greater than max value: " << maxValue; + return false; + } + if (value < minValue) { + ctx.Error(Pos) << "Restart value: " << value << " cannot be less than min value: " << minValue; + return false; + } + options = L(options, Q(Y(Q("restart"), Q(ToString(value))))); + } else { + options = L(options, Q(Y(Q("restart"), Q(TString())))); + } + } + if (Params.StartValue) { + TString strValue = Params.StartValue->Build()->GetLiteralValue(); + ui64 value = FromString<ui64>(strValue); + ui64 maxValue = ui64(std::numeric_limits<i64>::max()); + ui64 minValue = 1; + if (value > maxValue) { + ctx.Error(Pos) << "Start value: " << value << " cannot be greater than max value: " << maxValue; + return false; + } + if (value < minValue) { + ctx.Error(Pos) << "Start value: " << value << " cannot be less than min value: " << minValue; + return false; + } + options = L(options, Q(Y(Q("start"), Q(ToString(value))))); + } + + if (Params.Increment) { + TString strValue = Params.Increment->Build()->GetLiteralValue(); + ui64 value = FromString<ui64>(strValue); + ui64 maxValue = ui64(std::numeric_limits<i64>::max()); + if (value > maxValue) { + ctx.Error(Pos) << "Increment: " << value << " cannot be greater than max value: " << maxValue; + return false; + } + if (value == 0) { + ctx.Error(Pos) << "Increment must not be zero"; + return false; + } + options = L(options, Q(Y(Q("increment"), Q(ToString(value))))); + } + + Add("block", Q(Y( + Y("let", "sink", Y("DataSink", BuildQuotedAtom(Pos, TString(KikimrProviderName)), + Scoped->WrapCluster(Cluster, ctx))), + Y("let", "world", Y(TString(WriteName), "world", "sink", Y("Key", Q(Y(Q("sequence"), Y("String", BuildQuotedAtom(Pos, Id))))), Y("Void"), Q(options))), + Y("return", ctx.PragmaAutoCommit ? Y(TString(CommitName), "world", "sink") : AstNode("world")) + ))); + + return TAstListNode::DoInit(ctx, src); + } + + TPtr DoClone() const final { + return {}; + } +private: + const TString Service; + TDeferredAtom Cluster; + TString Id; + const TSequenceParameters Params; + + TScopedStatePtr Scoped; + TSourcePtr FakeSource; +}; + +TNodePtr BuildAlterSequence(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TString& id, const TSequenceParameters& params, TScopedStatePtr scoped) { + return new TAlterSequence(pos, service, cluster, id, params, scoped); +} + class TRenameRole final: public TAstListNode { public: TRenameRole(TPosition pos, bool isUser, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TDeferredAtom& newName, TScopedStatePtr scoped) diff --git a/yql/essentials/sql/v1/source.h b/yql/essentials/sql/v1/source.h index 35129fffbb8..ba904d6c21e 100644 --- a/yql/essentials/sql/v1/source.h +++ b/yql/essentials/sql/v1/source.h @@ -312,6 +312,7 @@ namespace NSQLTranslationV1 { TNodePtr BuildWriteTable(TPosition pos, const TString& label, const TTableRef& table, EWriteColumnMode mode, TNodePtr options, TScopedStatePtr scoped); TNodePtr BuildAnalyze(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TAnalyzeParams& params, TScopedStatePtr scoped); + TNodePtr BuildAlterSequence(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TString& id, const TSequenceParameters& params, TScopedStatePtr scoped); TSourcePtr TryMakeSourceFromExpression(TPosition pos, TContext& ctx, const TString& currService, const TDeferredAtom& currCluster, TNodePtr node, const TString& view = {}); void MakeTableFromExpression(TPosition pos, TContext& ctx, TNodePtr node, TDeferredAtom& table, const TString& prefix = {}); diff --git a/yql/essentials/sql/v1/sql.cpp b/yql/essentials/sql/v1/sql.cpp index 506b3950d54..3e5dba78f3c 100644 --- a/yql/essentials/sql/v1/sql.cpp +++ b/yql/essentials/sql/v1/sql.cpp @@ -140,22 +140,22 @@ bool NeedUseForAllStatements(const TRule_sql_stmt_core::AltCase& subquery) { case TRule_sql_stmt_core::kAltSqlStmtCore17: // do case TRule_sql_stmt_core::kAltSqlStmtCore19: // if case TRule_sql_stmt_core::kAltSqlStmtCore20: // for - case TRule_sql_stmt_core::kAltSqlStmtCore21: // values + case TRule_sql_stmt_core::kAltSqlStmtCore21: // values case TRule_sql_stmt_core::kAltSqlStmtCore22: // create user case TRule_sql_stmt_core::kAltSqlStmtCore23: // alter user case TRule_sql_stmt_core::kAltSqlStmtCore24: // create group - case TRule_sql_stmt_core::kAltSqlStmtCore25: // alter group - case TRule_sql_stmt_core::kAltSqlStmtCore26: // drop role - case TRule_sql_stmt_core::kAltSqlStmtCore27: // create object - case TRule_sql_stmt_core::kAltSqlStmtCore28: // alter object - case TRule_sql_stmt_core::kAltSqlStmtCore29: // drop object - case TRule_sql_stmt_core::kAltSqlStmtCore30: // create external data source - case TRule_sql_stmt_core::kAltSqlStmtCore31: // alter external data source - case TRule_sql_stmt_core::kAltSqlStmtCore32: // drop external data source - case TRule_sql_stmt_core::kAltSqlStmtCore33: // create replication - case TRule_sql_stmt_core::kAltSqlStmtCore34: // drop replication - case TRule_sql_stmt_core::kAltSqlStmtCore35: // create topic - case TRule_sql_stmt_core::kAltSqlStmtCore36: // alter topic + case TRule_sql_stmt_core::kAltSqlStmtCore25: // alter group + case TRule_sql_stmt_core::kAltSqlStmtCore26: // drop role + case TRule_sql_stmt_core::kAltSqlStmtCore27: // create object + case TRule_sql_stmt_core::kAltSqlStmtCore28: // alter object + case TRule_sql_stmt_core::kAltSqlStmtCore29: // drop object + case TRule_sql_stmt_core::kAltSqlStmtCore30: // create external data source + case TRule_sql_stmt_core::kAltSqlStmtCore31: // alter external data source + case TRule_sql_stmt_core::kAltSqlStmtCore32: // drop external data source + case TRule_sql_stmt_core::kAltSqlStmtCore33: // create replication + case TRule_sql_stmt_core::kAltSqlStmtCore34: // drop replication + case TRule_sql_stmt_core::kAltSqlStmtCore35: // create topic + case TRule_sql_stmt_core::kAltSqlStmtCore36: // alter topic case TRule_sql_stmt_core::kAltSqlStmtCore37: // drop topic case TRule_sql_stmt_core::kAltSqlStmtCore38: // grant permissions case TRule_sql_stmt_core::kAltSqlStmtCore39: // revoke permissions @@ -176,6 +176,7 @@ bool NeedUseForAllStatements(const TRule_sql_stmt_core::AltCase& subquery) { case TRule_sql_stmt_core::kAltSqlStmtCore54: // drop resource pool classifier case TRule_sql_stmt_core::kAltSqlStmtCore55: // backup case TRule_sql_stmt_core::kAltSqlStmtCore56: // restore + case TRule_sql_stmt_core::kAltSqlStmtCore57: // alter sequence return false; } } diff --git a/yql/essentials/sql/v1/sql_query.cpp b/yql/essentials/sql/v1/sql_query.cpp index 5f2f31d7763..4d9f30a4525 100644 --- a/yql/essentials/sql/v1/sql_query.cpp +++ b/yql/essentials/sql/v1/sql_query.cpp @@ -1674,6 +1674,50 @@ bool TSqlQuery::Statement(TVector<TNodePtr>& blocks, const TRule_sql_stmt_core& context)); break; } + case TRule_sql_stmt_core::kAltSqlStmtCore57: { + // alter_sequence_stmt: ALTER SEQUENCE (IF EXISTS)? object_ref alter_sequence_action (COMMA alter_sequence_action)*; + Ctx.BodyPart(); + auto& node = core.GetAlt_sql_stmt_core57().GetRule_alter_sequence_stmt1(); + + Ctx.Token(node.GetToken1()); + const TPosition pos = Ctx.Pos(); + + TString service = Ctx.Scoped->CurrService; + TDeferredAtom cluster = Ctx.Scoped->CurrCluster; + if (cluster.Empty()) { + Error() << "USE statement is missing - no default cluster is selected"; + return false; + } + TObjectOperatorContext context(Ctx.Scoped); + + if (node.GetRule_object_ref4().HasBlock1()) { + if (!ClusterExpr(node.GetRule_object_ref4().GetBlock1().GetRule_cluster_expr1(), + false, context.ServiceId, context.Cluster)) { + return false; + } + } + + const TString id = Id(node.GetRule_object_ref4().GetRule_id_or_at2(), *this).second; + + TSequenceParameters params; + + if (node.HasBlock3()) { // IF EXISTS + params.MissingOk = true; + Y_DEBUG_ABORT_UNLESS( + IS_TOKEN(node.GetBlock3().GetToken1().GetId(), IF) && + IS_TOKEN(node.GetBlock3().GetToken2().GetId(), EXISTS) + ); + } + + for (const auto& block : node.GetBlock5()) { + if (!AlterSequenceAction(block.GetRule_alter_sequence_action1(), params)) { + return false; + } + } + + AddStatementToBlocks(blocks, BuildAlterSequence(pos, service, cluster, id, params, Ctx.Scoped)); + break; + } case TRule_sql_stmt_core::ALT_NOT_SET: Ctx.IncrementMonCounter("sql_errors", "UnknownStatement" + internalStatementName); AltNotImplemented("sql_stmt_core", core); @@ -2177,6 +2221,63 @@ bool TSqlQuery::AlterTableAlterIndex(const TRule_alter_table_alter_index& node, return true; } +bool TSqlQuery::AlterSequenceAction(const TRule_alter_sequence_action& node, TSequenceParameters& params) { + switch (node.Alt_case()) { + case TRule_alter_sequence_action::kAltAlterSequenceAction1: { + if (params.StartValue) { + Ctx.Error(Ctx.Pos()) << "Start value defined more than once"; + return false; + } + auto literalNumber = LiteralNumber(Ctx, node.GetAlt_alter_sequence_action1().GetRule_integer3()); + if (literalNumber) { + params.StartValue = TDeferredAtom(literalNumber, Ctx); + } else { + return false; + } + break; + } + case TRule_alter_sequence_action::kAltAlterSequenceAction2: { + if (params.IsRestart) { + Ctx.Error(Ctx.Pos()) << "Restart value defined more than once"; + return false; + } + auto literalNumber = LiteralNumber(Ctx, node.GetAlt_alter_sequence_action2().GetRule_integer3()); + if (literalNumber) { + params.IsRestart = true; + params.RestartValue = TDeferredAtom(literalNumber, Ctx); + } else { + return false; + } + break; + } + case TRule_alter_sequence_action::kAltAlterSequenceAction3: { + if (params.IsRestart) { + Ctx.Error(Ctx.Pos()) << "Restart value defined more than once"; + return false; + } + params.IsRestart = true; + break; + } + case TRule_alter_sequence_action::kAltAlterSequenceAction4: { + if (params.Increment) { + Ctx.Error(Ctx.Pos()) << "Increment defined more than once"; + return false; + } + auto literalNumber = LiteralNumber(Ctx, node.GetAlt_alter_sequence_action4().GetRule_integer3()); + if (literalNumber) { + params.Increment = TDeferredAtom(literalNumber, Ctx); + } else { + return false; + } + break; + } + case TRule_alter_sequence_action::ALT_NOT_SET: + Y_ABORT("You should change implementation according to grammar changes"); + } + + return true; +} + bool TSqlQuery::AlterTableAlterColumnDropNotNull(const TRule_alter_table_alter_column_drop_not_null& node, TAlterTableParameters& params) { TString name = Id(node.GetRule_an_id3(), *this); const TPosition pos(Context().Pos()); diff --git a/yql/essentials/sql/v1/sql_query.h b/yql/essentials/sql/v1/sql_query.h index 99e1a9c4efd..03fd85df6b3 100644 --- a/yql/essentials/sql/v1/sql_query.h +++ b/yql/essentials/sql/v1/sql_query.h @@ -42,6 +42,7 @@ private: void AlterTableDropChangefeed(const TRule_alter_table_drop_changefeed& node, TAlterTableParameters& params); void AlterTableRenameIndexTo(const TRule_alter_table_rename_index_to& node, TAlterTableParameters& params); bool AlterTableAlterIndex(const TRule_alter_table_alter_index& node, TAlterTableParameters& params); + bool AlterSequenceAction(const TRule_alter_sequence_action& node, TSequenceParameters& params); TNodePtr PragmaStatement(const TRule_pragma_stmt& stmt, bool& success); void AddStatementToBlocks(TVector<TNodePtr>& blocks, TNodePtr node); bool ParseTableStoreFeatures(std::map<TString, TDeferredAtom> & result, const TRule_alter_table_store_action & actions); @@ -64,7 +65,7 @@ private: if (!Ctx.Settings.Antlr4Parser) { const auto pos = descr.find(": "); Y_DEBUG_ABORT_UNLESS(pos != TString::npos); - Split(TString(descr.begin() + pos + 2, descr.end()), "_", parts); + Split(TString(descr.begin() + pos + 2, descr.end()), "_", parts); } else { Split(descr, "_", parts); } diff --git a/yql/essentials/sql/v1/sql_ut.cpp b/yql/essentials/sql/v1/sql_ut.cpp index a9720a6c68c..45272879c01 100644 --- a/yql/essentials/sql/v1/sql_ut.cpp +++ b/yql/essentials/sql/v1/sql_ut.cpp @@ -2690,6 +2690,153 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { UNIT_ASSERT_VALUES_EQUAL(1, elementStat["\'mode \'alter"]); } + Y_UNIT_TEST(AlterSequence) { + UNIT_ASSERT(SqlToYql(R"( + USE plato; + ALTER SEQUENCE sequence START WITH 10 INCREMENT 2 RESTART WITH 5; + )").IsOk()); + UNIT_ASSERT(SqlToYql(R"( + USE plato; + ALTER SEQUENCE sequence INCREMENT 2; + )").IsOk()); + UNIT_ASSERT(SqlToYql(R"( + USE plato; + ALTER SEQUENCE sequence INCREMENT 2 START 1000; + )").IsOk()); + UNIT_ASSERT(SqlToYql(R"( + USE plato; + ALTER SEQUENCE sequence RESTART START 1000; + )").IsOk()); + UNIT_ASSERT(SqlToYql(R"( + USE plato; + ALTER SEQUENCE IF EXISTS sequence INCREMENT 1000 START 100 RESTART; + )").IsOk()); + UNIT_ASSERT(SqlToYql(R"( + USE plato; + ALTER SEQUENCE IF EXISTS sequence RESTART 1000 START WITH 100 INCREMENT BY 7; + )").IsOk()); + } + + Y_UNIT_TEST(AlterSequenceIncorrect) { + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence START WITH 10 INCREMENT 2 RESTART WITH 5 RESTART;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:75: Error: Restart value defined more than once\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence START WITH 10 INCREMENT 2 START 100 RESTART WITH 5;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:60: Error: Start value defined more than once\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence INCREMENT BY 7 START WITH 10 INCREMENT 2 RESTART WITH 5 RESTART;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:62: Error: Increment defined more than once\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 100 START WITH 10 INCREMENT 2 RESTART WITH 5;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:77: Error: Restart value defined more than once\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 1234234543563435151456 START WITH 10 INCREMENT 2;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:49: Error: Failed to parse number from string: 1234234543563435151456, number limit overflow\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 1 START WITH 9223372036854775817 INCREMENT 4;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Start value: 9223372036854775817 cannot be greater than max value: 9223372036854775807\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 9223372036854775827 START WITH 5 INCREMENT 4;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Restart value: 9223372036854775827 cannot be greater than max value: 9223372036854775807\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 1 START WITH 4 INCREMENT 0;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Increment must not be zero\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 0 START WITH 4 INCREMENT 1;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Restart value: 0 cannot be less than min value: 1\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 1 START WITH 0 INCREMENT 1;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Start value: 0 cannot be less than min value: 1\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 1 START WITH 1 INCREMENT 9223372036854775837;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Increment: 9223372036854775837 cannot be greater than max value: 9223372036854775807\n"); + } + } + + Y_UNIT_TEST(AlterSequenceCorrect) { + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence START WITH 10 INCREMENT 2 RESTART WITH 5;"); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("sequence")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("alter")); + UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("alter_if_exists")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("start")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("increment")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("restart")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0}}; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + } + + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE IF EXISTS sequence INCREMENT 2 RESTART;"); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("sequence")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("alter_if_exists")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("increment")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("restart")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0}}; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + } + + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE IF EXISTS sequence START 10 INCREMENT BY 2;"); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("sequence")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("alter_if_exists")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("start")); + UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("restart")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("increment")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0}}; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + } + } + Y_UNIT_TEST(OptionalAliases) { UNIT_ASSERT(SqlToYql("USE plato; SELECT foo FROM (SELECT key foo FROM Input);").IsOk()); UNIT_ASSERT(SqlToYql("USE plato; SELECT a.x FROM Input1 a JOIN Input2 b ON a.key = b.key;").IsOk()); diff --git a/yql/essentials/sql/v1/sql_ut_antlr4.cpp b/yql/essentials/sql/v1/sql_ut_antlr4.cpp index 28690f89a4c..91b85e92e8f 100644 --- a/yql/essentials/sql/v1/sql_ut_antlr4.cpp +++ b/yql/essentials/sql/v1/sql_ut_antlr4.cpp @@ -2690,6 +2690,153 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { UNIT_ASSERT_VALUES_EQUAL(1, elementStat["\'mode \'alter"]); } + Y_UNIT_TEST(AlterSequence) { + UNIT_ASSERT(SqlToYql(R"( + USE plato; + ALTER SEQUENCE sequence START WITH 10 INCREMENT 2 RESTART WITH 5; + )").IsOk()); + UNIT_ASSERT(SqlToYql(R"( + USE plato; + ALTER SEQUENCE sequence INCREMENT 2; + )").IsOk()); + UNIT_ASSERT(SqlToYql(R"( + USE plato; + ALTER SEQUENCE sequence INCREMENT 2 START 1000; + )").IsOk()); + UNIT_ASSERT(SqlToYql(R"( + USE plato; + ALTER SEQUENCE sequence RESTART START 1000; + )").IsOk()); + UNIT_ASSERT(SqlToYql(R"( + USE plato; + ALTER SEQUENCE IF EXISTS sequence INCREMENT 1000 START 100 RESTART; + )").IsOk()); + UNIT_ASSERT(SqlToYql(R"( + USE plato; + ALTER SEQUENCE IF EXISTS sequence RESTART 1000 START WITH 100 INCREMENT BY 7; + )").IsOk()); + } + + Y_UNIT_TEST(AlterSequenceIncorrect) { + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence START WITH 10 INCREMENT 2 RESTART WITH 5 RESTART;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:75: Error: Restart value defined more than once\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence START WITH 10 INCREMENT 2 START 100 RESTART WITH 5;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:60: Error: Start value defined more than once\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence INCREMENT BY 7 START WITH 10 INCREMENT 2 RESTART WITH 5 RESTART;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:62: Error: Increment defined more than once\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 100 START WITH 10 INCREMENT 2 RESTART WITH 5;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:77: Error: Restart value defined more than once\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 1234234543563435151456 START WITH 10 INCREMENT 2;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:49: Error: Failed to parse number from string: 1234234543563435151456, number limit overflow\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 1 START WITH 9223372036854775817 INCREMENT 4;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Start value: 9223372036854775817 cannot be greater than max value: 9223372036854775807\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 9223372036854775827 START WITH 5 INCREMENT 4;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Restart value: 9223372036854775827 cannot be greater than max value: 9223372036854775807\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 1 START WITH 4 INCREMENT 0;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Increment must not be zero\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 0 START WITH 4 INCREMENT 1;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Restart value: 0 cannot be less than min value: 1\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 1 START WITH 0 INCREMENT 1;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Start value: 0 cannot be less than min value: 1\n"); + } + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 1 START WITH 1 INCREMENT 9223372036854775837;"); + UNIT_ASSERT(!res.Root); + UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Increment: 9223372036854775837 cannot be greater than max value: 9223372036854775807\n"); + } + } + + Y_UNIT_TEST(AlterSequenceCorrect) { + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence START WITH 10 INCREMENT 2 RESTART WITH 5;"); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("sequence")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("alter")); + UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("alter_if_exists")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("start")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("increment")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("restart")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0}}; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + } + + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE IF EXISTS sequence INCREMENT 2 RESTART;"); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("sequence")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("alter_if_exists")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("increment")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("restart")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0}}; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + } + + { + NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE IF EXISTS sequence START 10 INCREMENT BY 2;"); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("sequence")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("alter_if_exists")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("start")); + UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("restart")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("increment")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0}}; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + } + } + Y_UNIT_TEST(OptionalAliases) { UNIT_ASSERT(SqlToYql("USE plato; SELECT foo FROM (SELECT key foo FROM Input);").IsOk()); UNIT_ASSERT(SqlToYql("USE plato; SELECT a.x FROM Input1 a JOIN Input2 b ON a.key = b.key;").IsOk()); |