diff --git a/ydb/core/kqp/executer_actor/kqp_scheme_executer.cpp b/ydb/core/kqp/executer_actor/kqp_scheme_executer.cpp index 11db54b315fc..155c223ce8f8 100644 --- a/ydb/core/kqp/executer_actor/kqp_scheme_executer.cpp +++ b/ydb/core/kqp/executer_actor/kqp_scheme_executer.cpp @@ -265,6 +265,12 @@ class TKqpSchemeExecuter : public TActorBootstrapped { break; } + case NKqpProto::TKqpSchemeOperation::kAlterSequence: { + const auto& modifyScheme = schemeOp.GetAlterSequence(); + ev->Record.MutableTransaction()->MutableModifyScheme()->CopyFrom(modifyScheme); + break; + } + default: InternalError(TStringBuilder() << "Unexpected scheme operation: " << (ui32) schemeOp.GetOperationCase()); diff --git a/ydb/core/kqp/gateway/kqp_ic_gateway.cpp b/ydb/core/kqp/gateway/kqp_ic_gateway.cpp index d2b8e660651f..e84a6963aee5 100644 --- a/ydb/core/kqp/gateway/kqp_ic_gateway.cpp +++ b/ydb/core/kqp/gateway/kqp_ic_gateway.cpp @@ -966,6 +966,14 @@ class TKikimrIcGateway : public IKqpGateway { return NotImplemented(); } + TFuture AlterSequence(const TString& cluster, + const NYql::TAlterSequenceSettings& settings, bool missingOk) override { + Y_UNUSED(cluster); + Y_UNUSED(settings); + Y_UNUSED(missingOk); + return NotImplemented(); + } + TFuture CreateTopic(const TString& cluster, Ydb::Topic::CreateTopicRequest&& request) override { try { if (!CheckCluster(cluster)) { diff --git a/ydb/core/kqp/host/kqp_gateway_proxy.cpp b/ydb/core/kqp/host/kqp_gateway_proxy.cpp index 0b9f4ade14f9..6a2887672bf3 100644 --- a/ydb/core/kqp/host/kqp_gateway_proxy.cpp +++ b/ydb/core/kqp/host/kqp_gateway_proxy.cpp @@ -1468,6 +1468,13 @@ class TKqpGatewayProxy : public IKikimrGateway { const NYql::TDropSequenceSettings& settings, bool missingOk) override { CHECK_PREPARED_DDL(DropSequence); + if (!SessionCtx->Config().EnableSequences) { + IKqpGateway::TGenericResult errResult; + errResult.AddIssue(NYql::TIssue("Sequences are not supported yet.")); + errResult.SetStatus(NYql::YqlStatusFromYdbStatus(Ydb::StatusIds::UNSUPPORTED)); + return MakeFuture(std::move(errResult)); + } + try { if (cluster != SessionCtx->GetCluster()) { return MakeFuture(ResultFromError("Invalid cluster: " + cluster)); @@ -1507,6 +1514,76 @@ class TKqpGatewayProxy : public IKikimrGateway { } } + TFuture AlterSequence(const TString& cluster, + const TAlterSequenceSettings& settings, bool missingOk) override { + CHECK_PREPARED_DDL(AlterSequence); + + if (!SessionCtx->Config().EnableSequences) { + IKqpGateway::TGenericResult errResult; + errResult.AddIssue(NYql::TIssue("Sequences are not supported yet.")); + errResult.SetStatus(NYql::YqlStatusFromYdbStatus(Ydb::StatusIds::UNSUPPORTED)); + return MakeFuture(std::move(errResult)); + } + + try { + + if (cluster != SessionCtx->GetCluster()) { + return MakeFuture(ResultFromError("Invalid cluster: " + cluster)); + } + + std::pair pathPair; + { + TString error; + if (!NSchemeHelpers::SplitTablePath(settings.Name, GetDatabase(), pathPair, error, false)) { + return MakeFuture(ResultFromError(error)); + } + } + + NKikimrSchemeOp::TModifyScheme schemeTx; + schemeTx.SetWorkingDir(pathPair.first); + schemeTx.SetOperationType(NKikimrSchemeOp::ESchemeOpAlterSequence); + schemeTx.SetSuccessOnNotExist(missingOk); + + NKikimrSchemeOp::TSequenceDescription* seqDesc = schemeTx.MutableSequence(); + seqDesc->SetName(pathPair.second); + + if (settings.SequenceSettings.MinValue) { + seqDesc->SetMinValue(*settings.SequenceSettings.MinValue); + } + if (settings.SequenceSettings.MaxValue) { + seqDesc->SetMaxValue(*settings.SequenceSettings.MaxValue); + } + if (settings.SequenceSettings.Increment) { + seqDesc->SetIncrement(*settings.SequenceSettings.Increment); + } + if (settings.SequenceSettings.StartValue) { + seqDesc->SetStartValue(*settings.SequenceSettings.StartValue); + } + if (settings.SequenceSettings.Cache) { + seqDesc->SetCache(*settings.SequenceSettings.Cache); + } + if (settings.SequenceSettings.Cycle) { + seqDesc->SetCycle(*settings.SequenceSettings.Cycle); + } + + if (IsPrepare()) { + auto& phyQuery = *SessionCtx->Query().PreparingQuery->MutablePhysicalQuery(); + auto& phyTx = *phyQuery.AddTransactions(); + phyTx.SetType(NKqpProto::TKqpPhyTx::TYPE_SCHEME); + phyTx.MutableSchemeOperation()->MutableAlterSequence()->Swap(&schemeTx); + + TGenericResult result; + result.SetSuccess(); + return MakeFuture(result); + } else { + return Gateway->ModifyScheme(std::move(schemeTx)); + } + } + catch (yexception& e) { + return MakeFuture(ResultFromException(e)); + } + } + TFuture CreateTableStore(const TString& cluster, const TCreateTableStoreSettings& settings, bool existingOk) override { diff --git a/ydb/core/kqp/provider/yql_kikimr_datasink.cpp b/ydb/core/kqp/provider/yql_kikimr_datasink.cpp index fecd2df8fe21..77a03073c5cb 100644 --- a/ydb/core/kqp/provider/yql_kikimr_datasink.cpp +++ b/ydb/core/kqp/provider/yql_kikimr_datasink.cpp @@ -127,6 +127,12 @@ class TKiSinkIntentDeterminationTransformer: public TKiSinkVisitorTransformer { return TStatus::Ok; } + TStatus HandleAlterSequence(NNodes::TKiAlterSequence node, TExprContext& ctx) override { + Y_UNUSED(ctx); + Y_UNUSED(node); + return TStatus::Ok; + } + TStatus HandleModifyPermissions(TKiModifyPermissions node, TExprContext& ctx) override { ctx.AddError(TIssue(ctx.GetPosition(node.Pos()), TStringBuilder() << "ModifyPermissions is not yet implemented for intent determination transformer")); @@ -515,7 +521,8 @@ class TKikimrDataSink : public TDataProviderBase } if (node.IsCallable(TKiCreateSequence::CallableName()) - || node.IsCallable(TKiDropSequence::CallableName())) { + || node.IsCallable(TKiDropSequence::CallableName()) + || node.IsCallable(TKiAlterSequence::CallableName())) { return true; } @@ -707,7 +714,6 @@ class TKikimrDataSink : public TDataProviderBase const NCommon::TWriteSequenceSettings& settings, const TKikimrKey& key, TExprContext& ctx) { YQL_ENSURE(settings.Mode); - auto mode = settings.Mode.Cast(); if (node->Child(3)->Content() != "Void") { ctx.AddError(TIssue(ctx.GetPosition(node->Pos()), "Creating sequence with data is not supported.")); return nullptr; @@ -715,7 +721,7 @@ class TKikimrDataSink : public TDataProviderBase auto valueType = settings.ValueType.IsValid() ? settings.ValueType.Cast() - : Build(ctx, node->Pos()).Value("bigint").Done(); + : Build(ctx, node->Pos()).Value("int8").Done(); auto temporary = settings.Temporary.IsValid() ? settings.Temporary.Cast() @@ -755,6 +761,30 @@ class TKikimrDataSink : public TDataProviderBase .Ptr(); } + static TExprNode::TPtr MakeAlterSequence(const TExprNode::TPtr& node, + const NCommon::TWriteSequenceSettings& settings, const TKikimrKey& key, TExprContext& ctx) + { + YQL_ENSURE(settings.Mode); + bool missingOk = (settings.Mode.Cast().Value() == "alter_if_exists"); + + if (node->Child(3)->Content() != "Void") { + ctx.AddError(TIssue(ctx.GetPosition(node->Pos()), "Alter sequence with data is not supported.")); + return nullptr; + } + + return Build(ctx, node->Pos()) + .World(node->Child(0)) + .DataSink(node->Child(1)) + .Sequence().Build(key.GetPGObjectId()) + .SequenceSettings(settings.SequenceSettings.Cast()) + .Settings(settings.Other) + .MissingOk() + .Value(missingOk) + .Build() + .Done() + .Ptr(); + } + bool RewriteIOExternal(const TKikimrKey& key, const TExprNode::TPtr& node, const TCoAtom& mode, TExprContext& ctx, TExprNode::TPtr& resultNode) { TKiDataSink dataSink(node->ChildPtr(1)); auto& tableDesc = SessionCtx->Tables().GetTable(TString{dataSink.Cluster()}, key.GetTablePath()); @@ -1305,6 +1335,8 @@ class TKikimrDataSink : public TDataProviderBase return MakeCreateSequence(node, settings, key, ctx); } else if (mode == "drop" || mode == "drop_if_exists") { return MakeDropSequence(node, settings, key, ctx); + } else if (mode == "alter" || mode == "alter_if_exists") { + return MakeAlterSequence(node, settings, key, ctx); } else { YQL_ENSURE(false, "unknown Sequence mode \"" << TString(mode) << "\""); } @@ -1544,6 +1576,10 @@ IGraphTransformer::TStatus TKiSinkVisitorTransformer::DoTransform(TExprNode::TPt return HandleDropSequence(node.Cast(), ctx); } + if (auto node = callable.Maybe()) { + return HandleAlterSequence(node.Cast(), ctx); + } + ctx.AddError(TIssue(ctx.GetPosition(input->Pos()), TStringBuilder() << "(Kikimr DataSink) Unsupported function: " << callable.CallableName())); return TStatus::Error; diff --git a/ydb/core/kqp/provider/yql_kikimr_exec.cpp b/ydb/core/kqp/provider/yql_kikimr_exec.cpp index 40732ba8be94..4e9449c72dd8 100644 --- a/ydb/core/kqp/provider/yql_kikimr_exec.cpp +++ b/ydb/core/kqp/provider/yql_kikimr_exec.cpp @@ -285,27 +285,33 @@ namespace { }; } - TCreateSequenceSettings ParseCreateSequenceSettings(TKiCreateSequence createSequence) { - TCreateSequenceSettings createSequenceSettings; - createSequenceSettings.Name = TString(createSequence.Sequence()); - createSequenceSettings.Temporary = TString(createSequence.Temporary()) == "true" ? true : false; - for (const auto& setting: createSequence.SequenceSettings()) { + TSequenceSettings ParseSequenceSettings(const TCoNameValueTupleList& sequenceSettings) { + TSequenceSettings result; + for (const auto& setting: sequenceSettings) { auto name = setting.Name().Value(); auto value = TString(setting.Value().template Cast().Value()); if (name == "start") { - createSequenceSettings.SequenceSettings.StartValue = FromString(value); + result.StartValue = FromString(value); } else if (name == "maxvalue") { - createSequenceSettings.SequenceSettings.MaxValue = FromString(value); + result.MaxValue = FromString(value); } else if (name == "minvalue") { - createSequenceSettings.SequenceSettings.MinValue = FromString(value); + result.MinValue = FromString(value); } else if (name == "cache") { - createSequenceSettings.SequenceSettings.Cache = FromString(value); + result.Cache = FromString(value); } else if (name == "cycle") { - createSequenceSettings.SequenceSettings.Cycle = value == "1" ? true : false; + result.Cycle = value == "1" ? true : false; } else if (name == "increment") { - createSequenceSettings.SequenceSettings.Increment = FromString(value); + result.Increment = FromString(value); } } + return result; + } + + TCreateSequenceSettings ParseCreateSequenceSettings(TKiCreateSequence createSequence) { + TCreateSequenceSettings createSequenceSettings; + createSequenceSettings.Name = TString(createSequence.Sequence()); + createSequenceSettings.Temporary = TString(createSequence.Temporary()) == "true" ? true : false; + createSequenceSettings.SequenceSettings = ParseSequenceSettings(createSequence.SequenceSettings()); return createSequenceSettings; } @@ -316,6 +322,14 @@ namespace { }; } + TAlterSequenceSettings ParseAlterSequenceSettings(TKiAlterSequence alterSequence) { + TAlterSequenceSettings alterSequenceSettings; + alterSequenceSettings.Name = TString(alterSequence.Sequence()); + alterSequenceSettings.SequenceSettings = ParseSequenceSettings(alterSequence.SequenceSettings()); + + return alterSequenceSettings; + } + [[nodiscard]] TString AddConsumerToTopicRequest( Ydb::Topic::Consumer* protoConsumer, const TCoTopicConsumer& consumer ) { @@ -1722,6 +1736,26 @@ class TKiSinkCallableExecutionTransformer : public TAsyncCallbackTransformer(input)) { + auto requireStatus = RequireChild(*input, 0); + if (requireStatus.Level != TStatus::Ok) { + return SyncStatus(requireStatus); + } + + auto cluster = TString(maybeAlterSequence.Cast().DataSink().Cluster()); + TAlterSequenceSettings alterSequenceSettings = ParseAlterSequenceSettings(maybeAlterSequence.Cast()); + bool missingOk = (maybeAlterSequence.MissingOk().Cast().Value() == "1"); + + auto future = Gateway->AlterSequence(cluster, alterSequenceSettings, missingOk); + + return WrapFuture(future, + [](const IKikimrGateway::TGenericResult& res, const TExprNode::TPtr& input, TExprContext& ctx) { + Y_UNUSED(res); + auto resultNode = ctx.NewWorld(input->Pos()); + return resultNode; + }, "Executing CREATE SEQUENCE"); + } + if (auto maybeAlter = TMaybeNode(input)) { auto requireStatus = RequireChild(*input, 0); if (requireStatus.Level != TStatus::Ok) { diff --git a/ydb/core/kqp/provider/yql_kikimr_expr_nodes.json b/ydb/core/kqp/provider/yql_kikimr_expr_nodes.json index ed4a2c545b4e..4d8f0946cacb 100644 --- a/ydb/core/kqp/provider/yql_kikimr_expr_nodes.json +++ b/ydb/core/kqp/provider/yql_kikimr_expr_nodes.json @@ -445,6 +445,19 @@ {"Index": 4, "Name": "MissingOk", "Type": "TCoAtom"} ] }, + { + "Name": "TKiAlterSequence", + "Base": "TCallable", + "Match": {"Type": "Callable", "Name": "KiAlterSequence!"}, + "Children": [ + {"Index": 0, "Name": "World", "Type": "TExprBase"}, + {"Index": 1, "Name": "DataSink", "Type": "TKiDataSink"}, + {"Index": 2, "Name": "Sequence", "Type": "TCoAtom"}, + {"Index": 3, "Name": "SequenceSettings", "Type": "TCoNameValueTupleList"}, + {"Index": 4, "Name": "Settings", "Type": "TCoNameValueTupleList"}, + {"Index": 5, "Name": "MissingOk", "Type": "TCoAtom"} + ] + }, { "Name": "TKiCreateReplication", "Base": "TCallable", diff --git a/ydb/core/kqp/provider/yql_kikimr_gateway.h b/ydb/core/kqp/provider/yql_kikimr_gateway.h index b0b78fe1800b..8a8c16f253a0 100644 --- a/ydb/core/kqp/provider/yql_kikimr_gateway.h +++ b/ydb/core/kqp/provider/yql_kikimr_gateway.h @@ -678,6 +678,11 @@ struct TDropSequenceSettings { TString Name; }; +struct TAlterSequenceSettings { + TString Name; + TSequenceSettings SequenceSettings; +}; + struct TAlterExternalTableSettings { TString ExternalTable; }; @@ -936,6 +941,8 @@ class IKikimrGateway : public TThrRefBase { const TCreateSequenceSettings& settings, bool existingOk) = 0; virtual NThreading::TFuture DropSequence(const TString& cluster, const TDropSequenceSettings& settings, bool missingOk) = 0; + virtual NThreading::TFuture AlterSequence(const TString& cluster, + const TAlterSequenceSettings& settings, bool missingOk) = 0; virtual NThreading::TFuture CreateColumnTable( TKikimrTableMetadataPtr metadata, bool createDir, bool existingOk = false) = 0; diff --git a/ydb/core/kqp/provider/yql_kikimr_provider.cpp b/ydb/core/kqp/provider/yql_kikimr_provider.cpp index 58449c223c81..7a4a70040393 100644 --- a/ydb/core/kqp/provider/yql_kikimr_provider.cpp +++ b/ydb/core/kqp/provider/yql_kikimr_provider.cpp @@ -70,6 +70,7 @@ struct TKikimrData { DataSinkNames.insert(TKiReturningList::CallableName()); DataSinkNames.insert(TKiCreateSequence::CallableName()); DataSinkNames.insert(TKiDropSequence::CallableName()); + DataSinkNames.insert(TKiAlterSequence::CallableName()); CommitModes.insert(CommitModeFlush); CommitModes.insert(CommitModeRollback); diff --git a/ydb/core/kqp/provider/yql_kikimr_provider_impl.h b/ydb/core/kqp/provider/yql_kikimr_provider_impl.h index 393a6d4c3e14..695e7c767840 100644 --- a/ydb/core/kqp/provider/yql_kikimr_provider_impl.h +++ b/ydb/core/kqp/provider/yql_kikimr_provider_impl.h @@ -69,6 +69,7 @@ class TKiSinkVisitorTransformer : public TSyncTransformerBase { virtual TStatus HandleCreateSequence(NNodes::TKiCreateSequence node, TExprContext& ctx) = 0; virtual TStatus HandleDropSequence(NNodes::TKiDropSequence node, TExprContext& ctx) = 0; + virtual TStatus HandleAlterSequence(NNodes::TKiAlterSequence node, TExprContext& ctx) = 0; virtual TStatus HandleModifyPermissions(NNodes::TKiModifyPermissions node, TExprContext& ctx) = 0; diff --git a/ydb/core/kqp/provider/yql_kikimr_type_ann.cpp b/ydb/core/kqp/provider/yql_kikimr_type_ann.cpp index dd54022b2322..482c1d455e88 100644 --- a/ydb/core/kqp/provider/yql_kikimr_type_ann.cpp +++ b/ydb/core/kqp/provider/yql_kikimr_type_ann.cpp @@ -1480,7 +1480,7 @@ virtual TStatus HandleCreateTable(TKiCreateTable create, TExprContext& ctx) over return true; } - static bool CheckCreateSequenceSettings(const TCoNameValueTupleList& settings, TExprContext& ctx) { + static bool CheckSequenceSettings(const TCoNameValueTupleList& settings, TExprContext& ctx) { const static std::unordered_set sequenceSettingNames = {"start", "increment", "cache", "minvalue", "maxvalue", "cycle"}; for (const auto& setting : settings) { @@ -1509,7 +1509,7 @@ virtual TStatus HandleCreateTable(TKiCreateTable create, TExprContext& ctx) over } virtual TStatus HandleCreateSequence(TKiCreateSequence node, TExprContext& ctx) override { - if(!CheckCreateSequenceSettings(node.SequenceSettings(), ctx)) { + if(!CheckSequenceSettings(node.SequenceSettings(), ctx)) { return TStatus::Error; } @@ -1548,6 +1548,21 @@ virtual TStatus HandleCreateTable(TKiCreateTable create, TExprContext& ctx) over return TStatus::Ok; } + virtual TStatus HandleAlterSequence(TKiAlterSequence node, TExprContext& ctx) override { + if(!CheckSequenceSettings(node.SequenceSettings(), ctx)) { + return TStatus::Error; + } + + if (!node.Settings().Empty()) { + ctx.AddError(TIssue(ctx.GetPosition(node.Pos()), TStringBuilder() + << "Unsupported sequence settings")); + return TStatus::Error; + } + + node.Ptr()->SetTypeAnn(node.World().Ref().GetTypeAnn()); + return TStatus::Ok; + } + virtual TStatus HandleAlterTopic(TKiAlterTopic node, TExprContext& ctx) override { if (!CheckTopicSettings(node.Settings(), ctx)) { return TStatus::Error; diff --git a/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp b/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp index 090d6785ca36..3bc957fdb79b 100644 --- a/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp +++ b/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp @@ -2457,6 +2457,97 @@ Y_UNIT_TEST_SUITE(KqpPg) { } } + Y_UNIT_TEST(AlterSequence) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnablePreparedDdl(true);; + auto setting = NKikimrKqp::TKqpSetting(); + auto serverSettings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetKqpSettings({setting}); + TKikimrRunner kikimr( + serverSettings.SetWithSampleTables(false)); + auto clientConfig = NGRpcProxy::TGRpcClientConfig(kikimr.GetEndpoint()); + auto client = kikimr.GetQueryClient(); + { + auto session = client.GetSession().GetValueSync().GetSession(); + auto id = session.GetId(); + + const auto queryCreate = R"( + --!syntax_pg + CREATE SEQUENCE IF NOT EXISTS seq + START WITH 10 + INCREMENT BY 2 + MINVALUE 1 + CACHE 3 + CYCLE; + )"; + + auto resultCreate = session.ExecuteQuery(queryCreate, NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_C(resultCreate.IsSuccess(), resultCreate.GetIssues().ToString()); + } + + { + auto runtime = kikimr.GetTestServer().GetRuntime(); + TActorId sender = runtime->AllocateEdgeActor(); + auto describeResult = DescribeTable(&kikimr.GetTestServer(), sender, "/Root/seq"); + UNIT_ASSERT_VALUES_EQUAL(describeResult.GetStatus(), NKikimrScheme::StatusSuccess); + auto& sequenceDescription = describeResult.GetPathDescription().GetSequenceDescription(); + UNIT_ASSERT_VALUES_EQUAL(sequenceDescription.GetName(), "seq"); + UNIT_ASSERT_VALUES_EQUAL(sequenceDescription.GetMinValue(), 1); + UNIT_ASSERT_VALUES_EQUAL(sequenceDescription.GetMaxValue(), Max()); + UNIT_ASSERT_VALUES_EQUAL(sequenceDescription.GetStartValue(), 10); + UNIT_ASSERT_VALUES_EQUAL(sequenceDescription.GetCache(), 3); + UNIT_ASSERT_VALUES_EQUAL(sequenceDescription.GetIncrement(), 2); + UNIT_ASSERT_VALUES_EQUAL(sequenceDescription.GetCycle(), true); + } + + { + auto session = client.GetSession().GetValueSync().GetSession(); + auto id = session.GetId(); + + const auto queryAlter = R"( + --!syntax_pg + ALTER SEQUENCE IF EXISTS seq + START WITH 20 + INCREMENT BY 5 + MAXVALUE 30 + NO CYCLE; + )"; + + auto resultAlter = session.ExecuteQuery(queryAlter, NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_C(resultAlter.IsSuccess(), resultAlter.GetIssues().ToString()); + } + + { + auto runtime = kikimr.GetTestServer().GetRuntime(); + TActorId sender = runtime->AllocateEdgeActor(); + auto describeResult = DescribeTable(&kikimr.GetTestServer(), sender, "/Root/seq"); + UNIT_ASSERT_VALUES_EQUAL(describeResult.GetStatus(), NKikimrScheme::StatusSuccess); + auto& sequenceDescription = describeResult.GetPathDescription().GetSequenceDescription(); + UNIT_ASSERT_VALUES_EQUAL(sequenceDescription.GetName(), "seq"); + UNIT_ASSERT_VALUES_EQUAL(sequenceDescription.GetMinValue(), 1); + UNIT_ASSERT_VALUES_EQUAL(sequenceDescription.GetMaxValue(), 30); + UNIT_ASSERT_VALUES_EQUAL(sequenceDescription.GetStartValue(), 20); + UNIT_ASSERT_VALUES_EQUAL(sequenceDescription.GetCache(), 3); + UNIT_ASSERT_VALUES_EQUAL(sequenceDescription.GetIncrement(), 5); + UNIT_ASSERT_VALUES_EQUAL(sequenceDescription.GetCycle(), false); + } + + { + auto session = client.GetSession().GetValueSync().GetSession(); + auto id = session.GetId(); + + const auto queryAlter = R"( + --!syntax_pg + ALTER SEQUENCE IF EXISTS seq + START WITH 31; + )"; + + auto resultAlter = session.ExecuteQuery(queryAlter, NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT(!resultAlter.IsSuccess()); + } + } + Y_UNIT_TEST(TempTablesSessionsIsolation) { NKikimrConfig::TAppConfig appConfig; appConfig.MutableTableServiceConfig()->SetEnablePreparedDdl(true); diff --git a/ydb/core/protos/kqp_physical.proto b/ydb/core/protos/kqp_physical.proto index bd13c8d6a530..eb0a8b4ff00f 100644 --- a/ydb/core/protos/kqp_physical.proto +++ b/ydb/core/protos/kqp_physical.proto @@ -444,6 +444,7 @@ message TKqpSchemeOperation { NKikimrSchemeOp.TModifyScheme CreateReplication = 34; NKikimrSchemeOp.TModifyScheme AlterReplication = 35; NKikimrSchemeOp.TModifyScheme DropReplication = 36; + NKikimrSchemeOp.TModifyScheme AlterSequence = 37; } } diff --git a/ydb/library/yql/sql/pg/pg_sql.cpp b/ydb/library/yql/sql/pg/pg_sql.cpp index 5991ecbc873f..06bca1242d6b 100644 --- a/ydb/library/yql/sql/pg/pg_sql.cpp +++ b/ydb/library/yql/sql/pg/pg_sql.cpp @@ -2813,14 +2813,10 @@ class TConverter : public IPGParseEvents { [[nodiscard]] TAstNode* ParseAlterSeqStmt(const AlterSeqStmt* value) { - if (value->missing_ok) { - AddError("alter if exists is not supported yet"); - return nullptr; - } - std::vector options; + TString mode = (value->missing_ok) ? "alter_if_exists" : "alter"; - options.push_back(QL(QA("mode"), QA("alter"))); + options.push_back(QL(QA("mode"), QA(mode))); auto [sink, key] = ParseQualifiedPgObjectName( value->sequence->catalogname, diff --git a/ydb/library/yql/sql/pg/pg_sql_ut.cpp b/ydb/library/yql/sql/pg/pg_sql_ut.cpp index ed02b883d7eb..6b69e4b5b108 100644 --- a/ydb/library/yql/sql/pg/pg_sql_ut.cpp +++ b/ydb/library/yql/sql/pg/pg_sql_ut.cpp @@ -297,14 +297,14 @@ Y_UNIT_TEST_SUITE(PgSqlParsingOnly) { } Y_UNIT_TEST(AlterSequenceStmt) { - auto res = PgSqlToYql("ALTER SEQUENCE seq AS integer START WITH 10 INCREMENT BY 2 NO MINVALUE NO MAXVALUE CACHE 3;"); + auto res = PgSqlToYql("ALTER SEQUENCE IF EXISTS seq AS integer START WITH 10 INCREMENT BY 2 NO MINVALUE NO MAXVALUE CACHE 3;"); UNIT_ASSERT_C(res.Root, res.Issues.ToString()); TString program = R"( ( (let world (Configure! world (DataSource 'config) 'OrderedColumns)) (let world (Write! world (DataSink '"kikimr" '"") (Key '('pgObject (String '"seq") (String 'pgSequence))) - (Void) '('('mode 'alter) '('"as" '"int4") '('"start" '10) '('"increment" '2) '('"cache" '3)))) + (Void) '('('mode 'alter_if_exists) '('"as" '"int4") '('"start" '10) '('"increment" '2) '('"cache" '3)))) (let world (CommitAll! world)) (return world) ) )";