diff options
author | Alexander Smirnov <alex@ydb.tech> | 2024-11-22 09:21:01 +0000 |
---|---|---|
committer | Alexander Smirnov <alex@ydb.tech> | 2024-11-22 09:21:01 +0000 |
commit | a7cac42c868ca5722777ccee944217410812e72c (patch) | |
tree | 7bff7ce2a3ade72f6f15dfc634490d13628066ee /yql/essentials/sql/v1 | |
parent | a18f18d81996ca8e681bb6cabd441b52833d99bf (diff) | |
parent | 9478cfdab4217d3710b96329466825bf47111d7d (diff) | |
download | ydb-a7cac42c868ca5722777ccee944217410812e72c.tar.gz |
Merge branch 'rightlib' into mergelibs-241122-0919
Diffstat (limited to 'yql/essentials/sql/v1')
-rw-r--r-- | yql/essentials/sql/v1/SQLv1.g.in | 29 | ||||
-rw-r--r-- | yql/essentials/sql/v1/SQLv1Antlr4.g.in | 29 | ||||
-rw-r--r-- | yql/essentials/sql/v1/builtin.cpp | 3 | ||||
-rw-r--r-- | yql/essentials/sql/v1/format/sql_format.cpp | 69 | ||||
-rw-r--r-- | yql/essentials/sql/v1/format/sql_format_ut.h | 21 | ||||
-rw-r--r-- | yql/essentials/sql/v1/node.cpp | 21 | ||||
-rw-r--r-- | yql/essentials/sql/v1/node.h | 19 | ||||
-rw-r--r-- | yql/essentials/sql/v1/query.cpp | 116 | ||||
-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_translation.cpp | 65 | ||||
-rw-r--r-- | yql/essentials/sql/v1/sql_ut.cpp | 227 | ||||
-rw-r--r-- | yql/essentials/sql/v1/sql_ut_antlr4.cpp | 227 |
15 files changed, 919 insertions, 39 deletions
diff --git a/yql/essentials/sql/v1/SQLv1.g.in b/yql/essentials/sql/v1/SQLv1.g.in index 9369b111a9..1b645f0b89 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: @@ -791,10 +792,16 @@ table_setting_value: | STRING_VALUE | integer | split_boundaries - | expr ON an_id (AS (SECONDS | MILLISECONDS | MICROSECONDS | NANOSECONDS))? + | ttl_tier_list ON an_id (AS (SECONDS | MILLISECONDS | MICROSECONDS | NANOSECONDS))? | bool_value ; +ttl_tier_list: expr (ttl_tier_action (COMMA expr ttl_tier_action)*)?; +ttl_tier_action: + TO EXTERNAL DATA SOURCE an_id + | DELETE +; + family_entry: FAMILY an_id family_settings; family_settings: LPAREN (family_settings_entry (COMMA family_settings_entry)*)? RPAREN; family_settings_entry: an_id EQUALS family_setting_value; @@ -1048,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; @@ -1333,6 +1348,7 @@ keyword_as_compat: | IMMEDIATE | IMPORT | IN + | INCREMENT | INCREMENTAL | INDEX | INDEXED @@ -1407,6 +1423,7 @@ keyword_as_compat: | REPLICATION | RESET | RESPECT + | RESTART | RESTORE | RESTRICT // | RESULT @@ -1424,7 +1441,9 @@ keyword_as_compat: | SETS | SHOW | SKIP + | SEQUENCE | SOURCE + | START | SUBQUERY | SUBSET | SYMBOLS @@ -1551,6 +1570,7 @@ keyword_compat: ( | IMMEDIATE | IMPORT | IN + | INCREMENT | INCREMENTAL | INDEX | INDEXED @@ -1625,6 +1645,7 @@ keyword_compat: ( | REPLICATION | RESET | RESPECT + | RESTART | RESTORE | RESTRICT | RESULT @@ -1642,7 +1663,9 @@ keyword_compat: ( | SETS | SHOW | SKIP + | SEQUENCE | SOURCE + | START | SUBQUERY | SUBSET | SYMBOLS @@ -1897,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; @@ -1986,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; @@ -2010,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 229b15dfae..5435535336 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: @@ -790,10 +791,16 @@ table_setting_value: | STRING_VALUE | integer | split_boundaries - | expr ON an_id (AS (SECONDS | MILLISECONDS | MICROSECONDS | NANOSECONDS))? + | ttl_tier_list ON an_id (AS (SECONDS | MILLISECONDS | MICROSECONDS | NANOSECONDS))? | bool_value ; +ttl_tier_list: expr (ttl_tier_action (COMMA expr ttl_tier_action)*)?; +ttl_tier_action: + TO EXTERNAL DATA SOURCE an_id + | DELETE +; + family_entry: FAMILY an_id family_settings; family_settings: LPAREN (family_settings_entry (COMMA family_settings_entry)*)? RPAREN; family_settings_entry: an_id EQUALS family_setting_value; @@ -1047,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; @@ -1332,6 +1347,7 @@ keyword_as_compat: | IMMEDIATE | IMPORT | IN + | INCREMENT | INCREMENTAL | INDEX | INDEXED @@ -1406,6 +1422,7 @@ keyword_as_compat: | REPLICATION | RESET | RESPECT + | RESTART | RESTORE | RESTRICT // | RESULT @@ -1423,7 +1440,9 @@ keyword_as_compat: | SETS | SHOW | TSKIP + | SEQUENCE | SOURCE + | START | SUBQUERY | SUBSET | SYMBOLS @@ -1550,6 +1569,7 @@ keyword_compat: ( | IMMEDIATE | IMPORT | IN + | INCREMENT | INCREMENTAL | INDEX | INDEXED @@ -1624,6 +1644,7 @@ keyword_compat: ( | REPLICATION | RESET | RESPECT + | RESTART | RESTORE | RESTRICT | RESULT @@ -1641,7 +1662,9 @@ keyword_compat: ( | SETS | SHOW | TSKIP + | SEQUENCE | SOURCE + | START | SUBQUERY | SUBSET | SYMBOLS @@ -1896,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; @@ -1985,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; @@ -2009,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/builtin.cpp b/yql/essentials/sql/v1/builtin.cpp index e327c2d2ea..94d8a3bc16 100644 --- a/yql/essentials/sql/v1/builtin.cpp +++ b/yql/essentials/sql/v1/builtin.cpp @@ -2916,6 +2916,9 @@ struct TBuiltinFuncData { {"listtopsort", BuildNamedArgcBuiltinFactoryCallback<TCallNodeImpl>("ListTopSort", 2, 3)}, {"listtopsortasc", BuildNamedArgcBuiltinFactoryCallback<TCallNodeImpl>("ListTopSortAsc", 2, 3)}, {"listtopsortdesc", BuildNamedArgcBuiltinFactoryCallback<TCallNodeImpl>("ListTopSortDesc", 2, 3)}, + {"listsample", BuildNamedArgcBuiltinFactoryCallback<TCallNodeImpl>("ListSample", 2, 3)}, + {"listsamplen", BuildNamedArgcBuiltinFactoryCallback<TCallNodeImpl>("ListSampleN", 2, 3)}, + {"listshuffle", BuildNamedArgcBuiltinFactoryCallback<TCallNodeImpl>("ListShuffle", 1, 2)}, // Dict builtins {"dictlength", BuildNamedArgcBuiltinFactoryCallback<TCallNodeImpl>("Length", 1, 1)}, diff --git a/yql/essentials/sql/v1/format/sql_format.cpp b/yql/essentials/sql/v1/format/sql_format.cpp index 80ce5d139e..3cc18b141b 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: @@ -2495,6 +2501,66 @@ private: Visit(msg.GetToken5()); } + void VisitTableSettingValue(const TRule_table_setting_value& msg) { + switch (msg.GetAltCase()) { + case TRule_table_setting_value::kAltTableSettingValue5: { + // | ttl_tier_list ON an_id (AS (SECONDS | MILLISECONDS | MICROSECONDS | NANOSECONDS))? + const auto& ttlSettings = msg.GetAlt_table_setting_value5(); + const auto& tierList = ttlSettings.GetRule_ttl_tier_list1(); + const bool needIndent = tierList.HasBlock2() && tierList.GetBlock2().Block2Size() > 0; // more then one tier + if (needIndent) { + NewLine(); + PushCurrentIndent(); + Visit(tierList.GetRule_expr1()); + VisitTtlTierAction(tierList.GetBlock2().GetRule_ttl_tier_action1()); + + for (const auto& tierEntry : tierList.GetBlock2().GetBlock2()) { + Visit(tierEntry.GetToken1()); // comma + NewLine(); + Visit(tierEntry.GetRule_expr2()); + VisitTtlTierAction(tierEntry.GetRule_ttl_tier_action3()); + } + + PopCurrentIndent(); + NewLine(); + } else { + Visit(tierList.GetRule_expr1()); + if (tierList.HasBlock2()) { + VisitTtlTierAction(tierList.GetBlock2().GetRule_ttl_tier_action1()); + } + } + + VisitKeyword(ttlSettings.GetToken2()); + Visit(ttlSettings.GetRule_an_id3()); + if (ttlSettings.HasBlock4()) { + VisitKeyword(ttlSettings.GetBlock4().GetToken1()); + VisitKeyword(ttlSettings.GetBlock4().GetToken2()); + } + } break; + default: + VisitAllFields(TRule_table_setting_value::GetDescriptor(), msg); + } + } + + void VisitTtlTierAction(const TRule_ttl_tier_action& msg) { + switch (msg.GetAltCase()) { + case TRule_ttl_tier_action::kAltTtlTierAction1: + // | TO EXTERNAL DATA SOURCE an_id + VisitKeyword(msg.GetAlt_ttl_tier_action1().GetToken1()); + VisitKeyword(msg.GetAlt_ttl_tier_action1().GetToken2()); + VisitKeyword(msg.GetAlt_ttl_tier_action1().GetToken3()); + VisitKeyword(msg.GetAlt_ttl_tier_action1().GetToken4()); + Visit(msg.GetAlt_ttl_tier_action1().GetRule_an_id5()); + break; + case TRule_ttl_tier_action::kAltTtlTierAction2: + // | DELETE + VisitKeyword(msg.GetAlt_ttl_tier_action2().GetToken1()); + break; + case TRule_ttl_tier_action::ALT_NOT_SET: + break; + } + } + void VisitExpr(const TRule_expr& msg) { if (msg.HasAlt_expr2()) { Visit(msg.GetAlt_expr2()); @@ -2783,6 +2849,8 @@ TStaticData::TStaticData() {TRule_case_expr::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitCaseExpr)}, {TRule_when_expr::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitWhenExpr)}, {TRule_with_table_settings::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitWithTableSettingsExpr)}, + {TRule_table_setting_value::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitTableSettingValue)}, + {TRule_ttl_tier_action::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitTtlTierAction)}, {TRule_expr::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitExpr)}, {TRule_or_subexpr::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitOrSubexpr)}, @@ -2853,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 6d92bd29eb..fc919b38c4 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"}, @@ -226,6 +237,16 @@ Y_UNIT_TEST(CreateTable) { "CREATE TABLE user (\n\tuser int32\n)\nWITH (ttl = interval('P1D') ON user AS MICROSECONDS);\n"}, {"create table user(user int32) with (ttl=interval('P1D') on user as nAnOsEcOnDs)", "CREATE TABLE user (\n\tuser int32\n)\nWITH (ttl = interval('P1D') ON user AS NANOSECONDS);\n"}, + {"create table user(user int32) with (ttl=interval('P1D') delete on user as nAnOsEcOnDs)", + "CREATE TABLE user (\n\tuser int32\n)\nWITH (ttl = interval('P1D') DELETE ON user AS NANOSECONDS);\n"}, + {"create table user(user int32) with (ttl=interval('P1D')to external data source tier1 ,interval('P10D')delete on user as seconds)", + "CREATE TABLE user (\n" + "\tuser int32\n" + ")\n" + "WITH (ttl =\n" + "\tinterval('P1D') TO EXTERNAL DATA SOURCE tier1,\n" + "\tinterval('P10D') DELETE\n" + "ON user AS SECONDS);\n"}, {"create table user(index user global unique sync on (user,user) with (user=user,user=user))", "CREATE TABLE user (\n\tINDEX user GLOBAL UNIQUE SYNC ON (user, user) WITH (user = user, user = user)\n);\n"}, {"create table user(index user global async on (user) with (user=user,))", diff --git a/yql/essentials/sql/v1/node.cpp b/yql/essentials/sql/v1/node.cpp index c7cafda7a5..b285142909 100644 --- a/yql/essentials/sql/v1/node.cpp +++ b/yql/essentials/sql/v1/node.cpp @@ -1894,9 +1894,14 @@ TMaybe<TStringContent> StringContentOrIdContent(TContext& ctx, TPosition pos, co (ctx.AnsiQuotedIdentifiers && input.StartsWith('"'))? EStringContentMode::AnsiIdent : EStringContentMode::Default); } -TTtlSettings::TTtlSettings(const TIdentifier& columnName, const TNodePtr& expr, const TMaybe<EUnit>& columnUnit) +TTtlSettings::TTierSettings::TTierSettings(const TNodePtr& evictionDelay, const std::optional<TIdentifier>& storageName) + : EvictionDelay(evictionDelay) + , StorageName(storageName) { +} + +TTtlSettings::TTtlSettings(const TIdentifier& columnName, const std::vector<TTierSettings>& tiers, const TMaybe<EUnit>& columnUnit) : ColumnName(columnName) - , Expr(expr) + , Tiers(tiers) , ColumnUnit(columnUnit) { } @@ -3131,10 +3136,10 @@ public: Y_DEBUG_ABORT_UNLESS(FuncNode); FuncNode->VisitTree(func, visited); } - + void CollectPreaggregateExprs(TContext& ctx, ISource& src, TVector<INode::TPtr>& exprs) override { if (ctx.DistinctOverWindow) { - FuncNode->CollectPreaggregateExprs(ctx, src, exprs); + FuncNode->CollectPreaggregateExprs(ctx, src, exprs); } else { INode::CollectPreaggregateExprs(ctx, src, exprs); } @@ -3274,7 +3279,7 @@ TSourcePtr TryMakeSourceFromExpression(TPosition pos, TContext& ctx, const TStri return nullptr; } - auto wrappedNode = new TAstListNodeImpl(pos, { + auto wrappedNode = new TAstListNodeImpl(pos, { new TAstAtomNodeImpl(pos, "EvaluateAtom", TNodeFlags::Default), node }); @@ -3303,7 +3308,7 @@ void MakeTableFromExpression(TPosition pos, TContext& ctx, TNodePtr node, TDefer node = node->Y("Concat", node->Y("String", node->Q(prefix)), node); } - auto wrappedNode = new TAstListNodeImpl(pos, { + auto wrappedNode = new TAstListNodeImpl(pos, { new TAstAtomNodeImpl(pos, "EvaluateAtom", TNodeFlags::Default), node }); @@ -3320,7 +3325,7 @@ TDeferredAtom MakeAtomFromExpression(TPosition pos, TContext& ctx, TNodePtr node node = node->Y("Concat", node->Y("String", node->Q(prefix)), node); } - auto wrappedNode = new TAstListNodeImpl(pos, { + auto wrappedNode = new TAstListNodeImpl(pos, { new TAstAtomNodeImpl(pos, "EvaluateAtom", TNodeFlags::Default), node }); @@ -3462,7 +3467,7 @@ bool TVectorIndexSettings::Validate(TContext& ctx) const { if (!Distance && !Similarity) { ctx.Error() << "either distance or similarity should be set"; return false; - } + } if (!VectorType) { ctx.Error() << "vector_type should be set"; return false; diff --git a/yql/essentials/sql/v1/node.h b/yql/essentials/sql/v1/node.h index 5805f92042..99f42f353c 100644 --- a/yql/essentials/sql/v1/node.h +++ b/yql/essentials/sql/v1/node.h @@ -1112,11 +1112,18 @@ namespace NSQLTranslationV1 { Nanoseconds /* "nanoseconds" */, }; + struct TTierSettings { + TNodePtr EvictionDelay; + std::optional<TIdentifier> StorageName; + + TTierSettings(const TNodePtr& evictionDelay, const std::optional<TIdentifier>& storageName = std::nullopt); + }; + TIdentifier ColumnName; - TNodePtr Expr; + std::vector<TTierSettings> Tiers; TMaybe<EUnit> ColumnUnit; - TTtlSettings(const TIdentifier& columnName, const TNodePtr& expr, const TMaybe<EUnit>& columnUnit = {}); + TTtlSettings(const TIdentifier& columnName, const std::vector<TTierSettings>& tiers, const TMaybe<EUnit>& columnUnit = {}); }; struct TTableSettings { @@ -1293,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 56dd8bd63d..8e71da3146 100644 --- a/yql/essentials/sql/v1/query.cpp +++ b/yql/essentials/sql/v1/query.cpp @@ -240,7 +240,17 @@ static INode::TPtr CreateTableSettings(const TTableSettings& tableSettings, ETab auto opts = Y(); opts = L(opts, Q(Y(Q("columnName"), BuildQuotedAtom(ttlSettings.ColumnName.Pos, ttlSettings.ColumnName.Name)))); - opts = L(opts, Q(Y(Q("expireAfter"), ttlSettings.Expr))); + + auto tiersDesc = Y(); + for (const auto& tier : ttlSettings.Tiers) { + auto tierDesc = Y(); + tierDesc = L(tierDesc, Q(Y(Q("evictionDelay"), tier.EvictionDelay))); + if (tier.StorageName) { + tierDesc = L(tierDesc, Q(Y(Q("storageName"), BuildQuotedAtom(tier.StorageName->Pos, tier.StorageName->Name)))); + } + tiersDesc = L(tiersDesc, Q(tierDesc)); + } + opts = L(opts, Q(Y(Q("tiers"), Q(tiersDesc)))); if (ttlSettings.ColumnUnit) { opts = L(opts, Q(Y(Q("columnUnit"), Q(ToString(*ttlSettings.ColumnUnit))))); @@ -2039,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 35129fffbb..ba904d6c21 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 506b3950d5..3e5dba78f3 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 5f2f31d776..4d9f30a452 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 99e1a9c4ef..03fd85df6b 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_translation.cpp b/yql/essentials/sql/v1/sql_translation.cpp index b298eb8abb..61a273b260 100644 --- a/yql/essentials/sql/v1/sql_translation.cpp +++ b/yql/essentials/sql/v1/sql_translation.cpp @@ -1963,19 +1963,68 @@ namespace { return true; } - bool StoreTtlSettings(const TRule_table_setting_value& from, TResetableSetting<TTtlSettings, void>& to, - TSqlExpression& expr, TContext& ctx, TTranslation& txc) { + bool FillTieringInterval(const TRule_expr& from, TNodePtr& tieringInterval, TSqlExpression& expr, TContext& ctx) { + auto exprNode = expr.Build(from); + if (!exprNode) { + return false; + } + + if (exprNode->GetOpName() != "Interval") { + ctx.Error() << "Literal of Interval type is expected for TTL"; + return false; + } + + tieringInterval = exprNode; + return true; + } + + bool FillTierAction(const TRule_ttl_tier_action& from, std::optional<TIdentifier>& storageName, TTranslation& txc) { + switch (from.GetAltCase()) { + case TRule_ttl_tier_action::kAltTtlTierAction1: + storageName = IdEx(from.GetAlt_ttl_tier_action1().GetRule_an_id5(), txc); + break; + case TRule_ttl_tier_action::kAltTtlTierAction2: + storageName.reset(); + break; + case TRule_ttl_tier_action::ALT_NOT_SET: + Y_ABORT("You should change implementation according to grammar changes"); + } + return true; + } + + bool StoreTtlSettings(const TRule_table_setting_value& from, TResetableSetting<TTtlSettings, void>& to, TSqlExpression& expr, TContext& ctx, + TTranslation& txc) { switch (from.Alt_case()) { case TRule_table_setting_value::kAltTableSettingValue5: { auto columnName = IdEx(from.GetAlt_table_setting_value5().GetRule_an_id3(), txc); - auto exprNode = expr.Build(from.GetAlt_table_setting_value5().GetRule_expr1()); - if (!exprNode) { + auto tiersLiteral = from.GetAlt_table_setting_value5().GetRule_ttl_tier_list1(); + + TNodePtr firstInterval; + if (!FillTieringInterval(tiersLiteral.GetRule_expr1(), firstInterval, expr, ctx)) { return false; } - if (exprNode->GetOpName() != "Interval") { - ctx.Error() << "Literal of Interval type is expected for TTL"; - return false; + std::vector<TTtlSettings::TTierSettings> tiers; + if (!tiersLiteral.HasBlock2()) { + tiers.emplace_back(firstInterval); + } else { + std::optional<TIdentifier> firstStorageName; + if (!FillTierAction(tiersLiteral.GetBlock2().GetRule_ttl_tier_action1(), firstStorageName, txc)) { + return false; + } + tiers.emplace_back(firstInterval, firstStorageName); + + for (const auto& tierLiteral : tiersLiteral.GetBlock2().GetBlock2()) { + TNodePtr intervalExpr; + if (!FillTieringInterval(tierLiteral.GetRule_expr2(), intervalExpr, expr, ctx)) { + return false; + } + std::optional<TIdentifier> storageName; + if (!FillTierAction(tierLiteral.GetRule_ttl_tier_action3(), storageName, txc)) { + return false; + } + tiers.emplace_back(intervalExpr, storageName); + } } TMaybe<TTtlSettings::EUnit> columnUnit; @@ -1988,7 +2037,7 @@ namespace { } } - to.Set(TTtlSettings(columnName, exprNode, columnUnit)); + to.Set(TTtlSettings(columnName, tiers, columnUnit)); break; } default: diff --git a/yql/essentials/sql/v1/sql_ut.cpp b/yql/essentials/sql/v1/sql_ut.cpp index 65ec39af2c..45272879c0 100644 --- a/yql/essentials/sql/v1/sql_ut.cpp +++ b/yql/essentials/sql/v1/sql_ut.cpp @@ -2053,7 +2053,8 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { if (word == "Write") { UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("setTtlSettings")); - UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("expireAfter")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("tiers")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("evictionDelay")); UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("86400000")); } }; @@ -2075,7 +2076,8 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { if (word == "Write") { UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("setTtlSettings")); - UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("expireAfter")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("tiers")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("evictionDelay")); UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("86400000")); UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("columnUnit")); UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("seconds")); @@ -2088,6 +2090,80 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); } + Y_UNIT_TEST(TtlTieringParseCorrect) { + NYql::TAstParseResult res = SqlToYql( + R"( USE plato; + CREATE TABLE tableName (Key Uint32, CreatedAt Uint32, PRIMARY KEY (Key)) + WITH (TTL = + Interval("P1D") TO EXTERNAL DATA SOURCE Tier1, + Interval("P2D") TO EXTERNAL DATA SOURCE Tier2, + Interval("P30D") DELETE + ON CreatedAt AS SECONDS);)" + ); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("setTtlSettings")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("tiers")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("evictionDelay")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("storageName")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("Tier1")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("Tier2")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("86400000")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("172800000")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("2592000000")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("columnUnit")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("seconds")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0} }; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + } + + Y_UNIT_TEST(TtlTieringWithOtherActionsParseCorrect) { + NYql::TAstParseResult res = SqlToYql( + R"( USE plato; + ALTER TABLE tableName + ADD FAMILY cold (DATA = "rot"), + SET TTL + Interval("P1D") TO EXTERNAL DATA SOURCE Tier1, + Interval("P2D") TO EXTERNAL DATA SOURCE Tier2, + Interval("P30D") DELETE + ON CreatedAt, + ALTER COLUMN payload_v2 SET FAMILY cold, + ALTER FAMILY default SET DATA "ssd" + ;)" + ); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("addColumnFamilies")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("cold")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("alterColumnFamilies")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("default")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("setTtlSettings")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("tiers")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("evictionDelay")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("storageName")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("Tier1")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("Tier2")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("86400000")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("172800000")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("2592000000")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0} }; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + } + Y_UNIT_TEST(TieringParseCorrect) { NYql::TAstParseResult res = SqlToYql( R"( USE plato; @@ -2614,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 e2a05cc229..91b85e92e8 100644 --- a/yql/essentials/sql/v1/sql_ut_antlr4.cpp +++ b/yql/essentials/sql/v1/sql_ut_antlr4.cpp @@ -2053,7 +2053,8 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { if (word == "Write") { UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("setTtlSettings")); - UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("expireAfter")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("tiers")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("evictionDelay")); UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("86400000")); } }; @@ -2075,7 +2076,8 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { if (word == "Write") { UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("setTtlSettings")); - UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("expireAfter")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("tiers")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("evictionDelay")); UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("86400000")); UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("columnUnit")); UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("seconds")); @@ -2088,6 +2090,80 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); } + Y_UNIT_TEST(TtlTieringParseCorrect) { + NYql::TAstParseResult res = SqlToYql( + R"( USE plato; + CREATE TABLE tableName (Key Uint32, CreatedAt Uint32, PRIMARY KEY (Key)) + WITH (TTL = + Interval("P1D") TO EXTERNAL DATA SOURCE Tier1, + Interval("P2D") TO EXTERNAL DATA SOURCE Tier2, + Interval("P30D") DELETE + On CreatedAt AS SECONDS);)" + ); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("setTtlSettings")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("tiers")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("evictionDelay")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("storageName")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("Tier1")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("Tier2")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("86400000")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("172800000")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("2592000000")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("columnUnit")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("seconds")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0} }; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + } + + Y_UNIT_TEST(TtlTieringWithOtherActionsParseCorrect) { + NYql::TAstParseResult res = SqlToYql( + R"( USE plato; + ALTER TABLE tableName + ADD FAMILY cold (DATA = "rot"), + SET TTL + Interval("P1D") TO EXTERNAL DATA SOURCE Tier1, + Interval("P2D") TO EXTERNAL DATA SOURCE Tier2, + Interval("P30D") DELETE + ON CreatedAt, + ALTER COLUMN payload_v2 SET FAMILY cold, + ALTER FAMILY default SET DATA "ssd" + ;)" + ); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("addColumnFamilies")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("cold")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("alterColumnFamilies")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("default")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("setTtlSettings")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("tiers")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("evictionDelay")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("storageName")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("Tier1")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("Tier2")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("86400000")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("172800000")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("2592000000")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0} }; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + } + Y_UNIT_TEST(TieringParseCorrect) { NYql::TAstParseResult res = SqlToYql( R"( USE plato; @@ -2614,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()); |