diff --git a/ydb/core/kqp/provider/yql_kikimr_exec.cpp b/ydb/core/kqp/provider/yql_kikimr_exec.cpp index 8c1d07ed998a..8991acdc58c2 100644 --- a/ydb/core/kqp/provider/yql_kikimr_exec.cpp +++ b/ydb/core/kqp/provider/yql_kikimr_exec.cpp @@ -1397,15 +1397,25 @@ class TKiSinkCallableExecutionTransformer : public TAsyncCallbackTransformer()); if (alterColumnAction == "setDefault") { auto setDefault = alterColumnList.Item(1).Cast(); - auto func = TString(setDefault.Item(0).Cast()); - auto arg = TString(setDefault.Item(1).Cast()); - if (func != "nextval") { - ctx.AddError(TIssue(ctx.GetPosition(setDefault.Pos()), - TStringBuilder() << "Unsupported function to set default: " << func)); - return SyncError(); + if (setDefault.Size() == 1) { + auto defaultExpr = TString(setDefault.Item(0).Cast()); + if (defaultExpr != "Null") { + ctx.AddError(TIssue(ctx.GetPosition(setDefault.Pos()), + TStringBuilder() << "Unsupported value to set defualt: " << defaultExpr)); + return SyncError(); + } + alter_columns->set_drop_default(google::protobuf::NullValue()); + } else { + auto func = TString(setDefault.Item(0).Cast()); + auto arg = TString(setDefault.Item(1).Cast()); + if (func != "nextval") { + ctx.AddError(TIssue(ctx.GetPosition(setDefault.Pos()), + TStringBuilder() << "Unsupported function to set default: " << func)); + return SyncError(); + } + auto fromSequence = alter_columns->mutable_from_sequence(); + fromSequence->set_name(arg); } - auto fromSequence = alter_columns->mutable_from_sequence(); - fromSequence->set_name(arg); } else if (alterColumnAction == "setFamily") { auto families = alterColumnList.Item(1).Cast(); if (families.Size() > 1) { diff --git a/ydb/core/kqp/provider/yql_kikimr_type_ann.cpp b/ydb/core/kqp/provider/yql_kikimr_type_ann.cpp index a5746e0be2c0..f93f0ed04d94 100644 --- a/ydb/core/kqp/provider/yql_kikimr_type_ann.cpp +++ b/ydb/core/kqp/provider/yql_kikimr_type_ann.cpp @@ -1373,17 +1373,26 @@ virtual TStatus HandleCreateTable(TKiCreateTable create, TExprContext& ctx) over auto alterColumnAction = TString(alterColumnList.Item(0).Cast()); if (alterColumnAction == "setDefault") { auto setDefault = alterColumnList.Item(1).Cast(); - auto func = TString(setDefault.Item(0).Cast()); - auto arg = TString(setDefault.Item(1).Cast()); - if (func != "nextval") { - ctx.AddError(TIssue(ctx.GetPosition(nameNode.Pos()), - TStringBuilder() << "Unsupported function to set default: " << func)); - return TStatus::Error; - } - if (setDefault.Size() > 2) { - ctx.AddError(TIssue(ctx.GetPosition(nameNode.Pos()), - TStringBuilder() << "Function nextval has exactly one argument")); - return TStatus::Error; + if (setDefault.Size() == 1) { + auto defaultExpr = TString(setDefault.Item(0).Cast()); + if (defaultExpr != "Null") { + ctx.AddError(TIssue(ctx.GetPosition(setDefault.Pos()), + TStringBuilder() << "Unsupported value to set defualt: " << defaultExpr)); + return TStatus::Error; + } + } else { + auto func = TString(setDefault.Item(0).Cast()); + auto arg = TString(setDefault.Item(1).Cast()); + if (func != "nextval") { + ctx.AddError(TIssue(ctx.GetPosition(nameNode.Pos()), + TStringBuilder() << "Unsupported function to set default: " << func)); + return TStatus::Error; + } + if (setDefault.Size() > 2) { + ctx.AddError(TIssue(ctx.GetPosition(nameNode.Pos()), + TStringBuilder() << "Function nextval has exactly one argument")); + return TStatus::Error; + } } } else if (alterColumnAction == "setFamily") { auto families = alterColumnList.Item(1).Cast(); diff --git a/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp b/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp index 2854ea9d30fe..8651b1673186 100644 --- a/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp +++ b/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp @@ -2592,7 +2592,7 @@ Y_UNIT_TEST_SUITE(KqpPg) { auto result = session.ExecuteQuery(R"( --!syntax_pg CREATE TABLE Pg ( - key int4 PRIMARY KEY, + key int8 PRIMARY KEY, value int8 ); )", NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); @@ -2627,7 +2627,7 @@ Y_UNIT_TEST_SUITE(KqpPg) { { auto result = session.ExecuteQuery(R"( --!syntax_pg - ALTER TABLE Pg ALTER COLUMN value SET DEFAULT nextval('seq'); + ALTER TABLE Pg ALTER COLUMN key SET DEFAULT nextval('seq'); )", NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); UNIT_ASSERT(!result.IsSuccess()); } @@ -2650,7 +2650,7 @@ Y_UNIT_TEST_SUITE(KqpPg) { { auto result = session.ExecuteQuery(R"( --!syntax_pg - ALTER TABLE Pg ALTER COLUMN value SET DEFAULT nextval('seq1'); + ALTER TABLE Pg ALTER COLUMN key SET DEFAULT nextval('seq1'); )", NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString()); } @@ -2663,7 +2663,7 @@ Y_UNIT_TEST_SUITE(KqpPg) { const auto& tableDescription = describeResult.GetPathDescription().GetTable(); for (const auto& column: tableDescription.GetColumns()) { - if (column.GetName() == "value") { + if (column.GetName() == "key") { UNIT_ASSERT(column.HasDefaultFromSequence()); UNIT_ASSERT(column.GetDefaultFromSequence() == "/Root/seq1"); break; @@ -2674,7 +2674,7 @@ Y_UNIT_TEST_SUITE(KqpPg) { { const auto query = Q_(R"( --!syntax_pg - INSERT INTO Pg (key) values (2), (3); + INSERT INTO Pg (value) values (2), (3); )"); auto result = tableClientSession.ExecuteDataQuery(query, TTxControl::BeginTx().CommitTx()).ExtractValueSync(); @@ -2692,7 +2692,7 @@ Y_UNIT_TEST_SUITE(KqpPg) { UNIT_ASSERT_C(!result.GetResultSets().empty(), "results are empty"); CompareYson(R"( - [["1";"1"];["2";"10"];["3";"12"]] + [["1";"1"];["10";"2"];["12";"3"]] )", FormatResultSetYson(result.GetResultSet(0))); } @@ -2714,7 +2714,48 @@ Y_UNIT_TEST_SUITE(KqpPg) { { auto result = session.ExecuteQuery(R"( --!syntax_pg - ALTER TABLE Pg ALTER COLUMN value SET DEFAULT nextval('seq2'); + ALTER TABLE Pg ALTER COLUMN key SET DEFAULT nextval('seq2'); + )", NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString()); + } + + { + const auto query = Q_(R"( + --!syntax_pg + INSERT INTO Pg (value) values (4), (5); + )"); + + auto result = tableClientSession.ExecuteDataQuery(query, TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString()); + } + + { + const auto query = Q_(R"( + --!syntax_pg + SELECT * FROM Pg; + )"); + + auto result = tableClientSession.ExecuteDataQuery(query, TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + + UNIT_ASSERT_C(!result.GetResultSets().empty(), "results are empty"); + CompareYson(R"( + [["1";"1"];["5";"4"];["8";"5"];["10";"2"];["12";"3"]] + )", FormatResultSetYson(result.GetResultSet(0))); + } + + { + auto result = session.ExecuteQuery(R"( + --!syntax_pg + ALTER TABLE Pg ALTER COLUMN key DROP DEFAULT; + )", NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString()); + } + + { + auto result = session.ExecuteQuery(R"( + --!syntax_pg + ALTER TABLE Pg ALTER COLUMN value SET DEFAULT nextval('seq1'); )", NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString()); } @@ -2722,7 +2763,7 @@ Y_UNIT_TEST_SUITE(KqpPg) { { const auto query = Q_(R"( --!syntax_pg - INSERT INTO Pg (key) values (4), (5); + INSERT INTO Pg (key) values (13), (14); )"); auto result = tableClientSession.ExecuteDataQuery(query, TTxControl::BeginTx().CommitTx()).ExtractValueSync(); @@ -2740,7 +2781,7 @@ Y_UNIT_TEST_SUITE(KqpPg) { UNIT_ASSERT_C(!result.GetResultSets().empty(), "results are empty"); CompareYson(R"( - [["1";"1"];["2";"10"];["3";"12"];["4";"5"];["5";"8"]] + [["1";"1"];["5";"4"];["8";"5"];["10";"2"];["12";"3"];["13";"14"];["14";"16"]] )", FormatResultSetYson(result.GetResultSet(0))); } } diff --git a/ydb/core/protos/flat_scheme_op.proto b/ydb/core/protos/flat_scheme_op.proto index dfe39d11023c..318bd683fd40 100644 --- a/ydb/core/protos/flat_scheme_op.proto +++ b/ydb/core/protos/flat_scheme_op.proto @@ -22,6 +22,7 @@ import "ydb/core/tx/columnshard/engines/scheme/defaults/protos/data.proto"; import "ydb/core/tx/columnshard/common/protos/snapshot.proto"; import "google/protobuf/empty.proto"; +import "google/protobuf/struct.proto"; package NKikimrSchemeOp; option java_package = "ru.yandex.kikimr.proto"; @@ -90,6 +91,7 @@ message TColumnDescription { oneof DefaultValue { string DefaultFromSequence = 7; // Path to sequence for default values Ydb.TypedValue DefaultFromLiteral = 10; // Literal default value + google.protobuf.NullValue DropDefault = 12; // Drop default case } optional bool NotNull = 8; // flag that indicates that column is currently under the build diff --git a/ydb/core/tx/schemeshard/schemeshard_info_types.cpp b/ydb/core/tx/schemeshard/schemeshard_info_types.cpp index 54bc391e5c6a..8257492bcabb 100644 --- a/ydb/core/tx/schemeshard/schemeshard_info_types.cpp +++ b/ydb/core/tx/schemeshard/schemeshard_info_types.cpp @@ -324,9 +324,9 @@ TTableInfo::TAlterDataPtr TTableInfo::CreateAlterData( bool isAlterColumn = (source && colName2Id.contains(colName)); if (isAlterColumn) { - if (keys.contains(colName2Id.at(colName))) { + if (keys.contains(colName2Id.at(colName)) && columnFamily) { errStr = TStringBuilder() - << "Cannot alter key column ' " << colName << "' with id " << colName2Id.at(colName); + << "Cannot set family for key column ' " << colName << "' with id " << colName2Id.at(colName); return nullptr; } @@ -335,18 +335,23 @@ TTableInfo::TAlterDataPtr TTableInfo::CreateAlterData( return nullptr; } - if (!columnFamily && !col.HasDefaultFromSequence()) { + if (!columnFamily && !col.HasDefaultFromSequence() && !col.HasDropDefault()) { errStr = Sprintf("Nothing to alter for column '%s'", colName.data()); return nullptr; } - if (col.HasDefaultFromSequence()) { - if (!localSequences.contains(col.GetDefaultFromSequence())) { - errStr = Sprintf("Column '%s' cannot use an unknown sequence '%s'", colName.c_str(), col.GetDefaultFromSequence().c_str()); - return nullptr; + switch (col.GetDefaultValueCase()) { + case NKikimrSchemeOp::TColumnDescription::kDefaultFromSequence: { + if (!localSequences.contains(col.GetDefaultFromSequence())) { + errStr = Sprintf("Column '%s' cannot use an unknown sequence '%s'", colName.c_str(), col.GetDefaultFromSequence().c_str()); + return nullptr; + } + break; } - } else { - if (col.DefaultValue_case() != NKikimrSchemeOp::TColumnDescription::DEFAULTVALUE_NOT_SET) { + case NKikimrSchemeOp::TColumnDescription::kDropDefault: { + break; + } + default: { errStr = Sprintf("Cannot set default from literal for column '%s'", colName.c_str()); return nullptr; } @@ -373,12 +378,18 @@ TTableInfo::TAlterDataPtr TTableInfo::CreateAlterData( if (columnFamily) { column.Family = columnFamily->GetId(); } - if (col.HasDefaultFromSequence()) { - column.DefaultKind = ETableColumnDefaultKind::FromSequence; - column.DefaultValue = col.GetDefaultFromSequence(); - } else if (col.HasDefaultFromLiteral()) { - column.DefaultKind = ETableColumnDefaultKind::FromLiteral; - column.DefaultValue = col.GetDefaultFromLiteral().SerializeAsString(); + switch (col.GetDefaultValueCase()) { + case NKikimrSchemeOp::TColumnDescription::kDefaultFromSequence: { + column.DefaultKind = ETableColumnDefaultKind::FromSequence; + column.DefaultValue = col.GetDefaultFromSequence(); + break; + } + case NKikimrSchemeOp::TColumnDescription::kDropDefault: { + column.DefaultKind = ETableColumnDefaultKind::None; + column.DefaultValue = ""; + break; + } + default: break; } } else { if (colName2Id.contains(colName)) { diff --git a/ydb/core/ydb_convert/table_description.cpp b/ydb/core/ydb_convert/table_description.cpp index 5964d2d7267a..1d772fa259af 100644 --- a/ydb/core/ydb_convert/table_description.cpp +++ b/ydb/core/ydb_convert/table_description.cpp @@ -307,6 +307,10 @@ bool BuildAlterTableModifyScheme(const Ydb::Table::AlterTableRequest* req, NKiki } break; } + case Ydb::Table::ColumnMeta::kDropDefault: { + column->SetDropDefault(google::protobuf::NullValue()); + break; + } default: break; } } @@ -457,6 +461,10 @@ Ydb::Type* AddColumn(Ydb::Table::ColumnMeta fromSequence->set_name(column.GetDefaultFromSequence()); break; } + case NKikimrSchemeOp::TColumnDescription::kDropDefault: { + newColumn->set_drop_default(google::protobuf::NullValue()); + break; + } default: break; } @@ -684,6 +692,10 @@ bool FillColumnDescription(NKikimrSchemeOp::TTableDescription& out, *fromSequence = column.from_sequence().name(); break; } + case Ydb::Table::ColumnMeta::kDropDefault: { + cd->SetDropDefault(google::protobuf::NullValue()); + break; + } default: break; } } diff --git a/ydb/library/yql/sql/pg/pg_sql.cpp b/ydb/library/yql/sql/pg/pg_sql.cpp index c40b48d10cb2..a8df2b72b9b5 100644 --- a/ydb/library/yql/sql/pg/pg_sql.cpp +++ b/ydb/library/yql/sql/pg/pg_sql.cpp @@ -2835,7 +2835,6 @@ class TConverter : public IPGParseEvents { for (int i = 0; i < ListLength(value->options); ++i) { auto rawNode = ListNodeNth(value->options, i); - switch (NodeTag(rawNode)) { case T_DefElem: { const auto* defElem = CAST_NODE(DefElem, rawNode); @@ -2903,6 +2902,10 @@ class TConverter : public IPGParseEvents { case AT_ColumnDefault: { /* ALTER COLUMN DEFAULT */ const auto* def = cmd->def; const auto* colName = cmd->name; + if (def == nullptr) { + alterColumns.push_back(QL(QAX(colName), QL(QA("setDefault"), QL(QA("Null"))))); + break; + } switch (NodeTag(def)) { case T_FuncCall: { const auto* newDefault = CAST_NODE(FuncCall, def); diff --git a/ydb/library/yql/sql/pg/pg_sql_ut.cpp b/ydb/library/yql/sql/pg/pg_sql_ut.cpp index 120c901acd2a..3a962d5d6b34 100644 --- a/ydb/library/yql/sql/pg/pg_sql_ut.cpp +++ b/ydb/library/yql/sql/pg/pg_sql_ut.cpp @@ -312,7 +312,7 @@ Y_UNIT_TEST_SUITE(PgSqlParsingOnly) { UNIT_ASSERT_STRINGS_EQUAL(res.Root->ToString(), expectedAst.Root->ToString()); } - Y_UNIT_TEST(AlterTableStmt) { + Y_UNIT_TEST(AlterTableSetDefaultNextvalStmt) { auto res = PgSqlToYql("ALTER TABLE public.t ALTER COLUMN id SET DEFAULT nextval('seq');"); UNIT_ASSERT_C(res.Root, res.Issues.ToString()); TString program = R"( @@ -342,6 +342,21 @@ Y_UNIT_TEST_SUITE(PgSqlParsingOnly) { UNIT_ASSERT_STRINGS_EQUAL(res.Root->ToString(), expectedAst.Root->ToString()); } + Y_UNIT_TEST(AlterTableDropDefaultStmt) { + auto res = PgSqlToYql("ALTER TABLE public.t ALTER COLUMN id DROP DEFAULT;"); + 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 '('tablescheme (String '"t"))) (Void) '('('mode 'alter) '('actions '('('alterColumns '('('"id" '('setDefault '('Null)))))))))) + (let world (CommitAll! world)) (return world) + ) + )"; + const auto expectedAst = NYql::ParseAst(program); + UNIT_ASSERT_STRINGS_EQUAL(res.Root->ToString(), expectedAst.Root->ToString()); + } + Y_UNIT_TEST(VariableShowStmt) { auto res = PgSqlToYql("Show server_version_num"); UNIT_ASSERT(res.Root); diff --git a/ydb/public/api/protos/ydb_table.proto b/ydb/public/api/protos/ydb_table.proto index a698b71c8d66..731a1e0b05fb 100644 --- a/ydb/public/api/protos/ydb_table.proto +++ b/ydb/public/api/protos/ydb_table.proto @@ -14,6 +14,7 @@ import "ydb/public/api/protos/ydb_formats.proto"; import "google/protobuf/empty.proto"; import "google/protobuf/duration.proto"; +import "google/protobuf/struct.proto"; import "google/protobuf/timestamp.proto"; package Ydb.Table; @@ -384,6 +385,7 @@ message ColumnMeta { oneof default_value { TypedValue from_literal = 5; SequenceDescription from_sequence = 6; + google.protobuf.NullValue drop_default = 7; } }