From 3dc81324d00bc97806e6602479f17e9719983f58 Mon Sep 17 00:00:00 2001 From: KirillKurdyukov Date: Tue, 30 Sep 2025 13:24:50 +0300 Subject: [PATCH 1/4] feat(TableService): CreateTable with default value options --- table/pom.xml | 1 - .../description/SequenceDescription.java | 124 +++++++++ .../ydb/table/description/TableColumn.java | 36 ++- .../table/description/TableDescription.java | 78 +++++- .../java/tech/ydb/table/impl/BaseSession.java | 138 +++++++--- .../table/integration/CreateTableTest.java | 248 ++++++++++++++++++ 6 files changed, 591 insertions(+), 34 deletions(-) create mode 100644 table/src/main/java/tech/ydb/table/description/SequenceDescription.java create mode 100644 table/src/test/java/tech/ydb/table/integration/CreateTableTest.java diff --git a/table/pom.xml b/table/pom.xml index cc47655b..f5518e02 100644 --- a/table/pom.xml +++ b/table/pom.xml @@ -51,7 +51,6 @@ true ydbplatform/local-ydb:trunk - enable_vector_index diff --git a/table/src/main/java/tech/ydb/table/description/SequenceDescription.java b/table/src/main/java/tech/ydb/table/description/SequenceDescription.java new file mode 100644 index 00000000..0f6f30c9 --- /dev/null +++ b/table/src/main/java/tech/ydb/table/description/SequenceDescription.java @@ -0,0 +1,124 @@ +package tech.ydb.table.description; + +import javax.annotation.Nullable; + +/** + * @author Kirill Kurdyukov + */ +public class SequenceDescription { + + private final String name; + @Nullable + private final Long minValue; + @Nullable + private final Long maxValue; + @Nullable + private final Long startValue; + @Nullable + private final Long cache; + @Nullable + private final Long increment; + @Nullable + private final Boolean cycle; + + private SequenceDescription(Builder builder) { + this.name = builder.name; + this.minValue = builder.minValue; + this.maxValue = builder.maxValue; + this.startValue = builder.startValue; + this.cache = builder.cache; + this.increment = builder.increment; + this.cycle = builder.cycle; + } + + public String getName() { + return name; + } + + @Nullable + public Long getMinValue() { + return minValue; + } + + @Nullable + public Long getMaxValue() { + return maxValue; + } + + @Nullable + public Long getStartValue() { + return startValue; + } + + @Nullable + public Long getCache() { + return cache; + } + + @Nullable + public Long getIncrement() { + return increment; + } + + @Nullable + public Boolean getCycle() { + return cycle; + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static class Builder { + private String name = "sequence_default"; + private Long minValue; + private Long maxValue; + private Long startValue; + private Long cache; + private Long increment; + private Boolean cycle; + + public Builder setName(String name) { + this.name = name; + return this; + } + + public Builder setMinValue(@Nullable Long minValue) { + this.minValue = minValue; + return this; + } + + public Builder setMaxValue(@Nullable Long maxValue) { + this.maxValue = maxValue; + return this; + } + + public Builder setStartValue(@Nullable Long startValue) { + this.startValue = startValue; + return this; + } + + public Builder setCache(@Nullable Long cache) { + this.cache = cache; + return this; + } + + public Builder setIncrement(@Nullable Long increment) { + this.increment = increment; + return this; + } + + public Builder setCycle(@Nullable Boolean cycle) { + this.cycle = cycle; + return this; + } + + public SequenceDescription build() { + if (name == null) { + throw new IllegalStateException("name is required"); + } + + return new SequenceDescription(this); + } + } +} diff --git a/table/src/main/java/tech/ydb/table/description/TableColumn.java b/table/src/main/java/tech/ydb/table/description/TableColumn.java index 0f18082a..2a8a83c9 100644 --- a/table/src/main/java/tech/ydb/table/description/TableColumn.java +++ b/table/src/main/java/tech/ydb/table/description/TableColumn.java @@ -2,6 +2,7 @@ import javax.annotation.Nullable; +import tech.ydb.table.values.PrimitiveValue; import tech.ydb.table.values.Type; @@ -14,14 +15,37 @@ public class TableColumn { private final Type type; @Nullable private final String family; - private final boolean hasDefaultValue; + @Nullable + private final PrimitiveValue literalDefaultValue; + @Nullable + private final SequenceDescription sequenceDescription; public TableColumn(String name, Type type, String family, boolean hasDefaultValue) { this.name = name; this.type = type; this.family = family; this.hasDefaultValue = hasDefaultValue; + this.literalDefaultValue = null; + this.sequenceDescription = null; + } + + public TableColumn(String name, Type type, @Nullable String family, PrimitiveValue literalDefaultValue) { + this.name = name; + this.type = type; + this.family = family; + this.hasDefaultValue = true; + this.literalDefaultValue = literalDefaultValue; + this.sequenceDescription = null; + } + + public TableColumn(String name, Type type, @Nullable String family, SequenceDescription sequenceDescription) { + this.name = name; + this.type = type; + this.family = family; + this.hasDefaultValue = true; + this.literalDefaultValue = null; + this.sequenceDescription = sequenceDescription; } public TableColumn(String name, Type type, String family) { @@ -53,4 +77,14 @@ public String getFamily() { public String toString() { return name + ' ' + type; } + + @Nullable + public PrimitiveValue getLiteralDefaultValue() { + return literalDefaultValue; + } + + @Nullable + public SequenceDescription getSequenceDescription() { + return sequenceDescription; + } } diff --git a/table/src/main/java/tech/ydb/table/description/TableDescription.java b/table/src/main/java/tech/ydb/table/description/TableDescription.java index f7dcc522..dcc6c984 100644 --- a/table/src/main/java/tech/ydb/table/description/TableDescription.java +++ b/table/src/main/java/tech/ydb/table/description/TableDescription.java @@ -18,6 +18,8 @@ import tech.ydb.table.settings.AlterTableSettings; import tech.ydb.table.settings.PartitioningSettings; import tech.ydb.table.values.OptionalType; +import tech.ydb.table.values.PrimitiveType; +import tech.ydb.table.values.PrimitiveValue; import tech.ydb.table.values.Type; /** @@ -139,7 +141,7 @@ public Builder addColumn(TableColumn column) { } public Builder addNonnullColumn(String name, Type type) { - return addNonnullColumn(name, type, null); + return addNonnullColumn(name, type, (String) null); } public Builder addNonnullColumn(String name, Type type, String family) { @@ -147,6 +149,80 @@ public Builder addNonnullColumn(String name, Type type, String family) { return this; } + public Builder addColumn(String name, Type type, PrimitiveValue defaultValue) { + columns.put(name, new TableColumn(name, type, null, defaultValue)); + return this; + } + + public Builder addColumn(String name, Type type, String family, PrimitiveValue defaultValue) { + columns.put(name, new TableColumn(name, type, family, defaultValue)); + return this; + } + + public Builder addSequenceColumn(String name, Type type) { + return addSequenceColumn(name, type, null, SequenceDescription.newBuilder().build()); + } + + public Builder addSequenceColumn(String name, Type type, String family) { + return addSequenceColumn(name, type, family, SequenceDescription.newBuilder().build()); + } + + public Builder addSequenceColumn(String name, Type type, String family, SequenceDescription sequenceDescription) { + if (type instanceof PrimitiveType) { + PrimitiveType primitiveType = (PrimitiveType) type; + + switch (primitiveType) { + case Int16: + columns.put(name, new TableColumn(name, PrimitiveType.Int16, family, sequenceDescription)); + return this; + case Int32: + columns.put(name, new TableColumn(name, PrimitiveType.Int32, family, sequenceDescription)); + return this; + case Int64: + columns.put(name, new TableColumn(name, PrimitiveType.Int64, family, sequenceDescription)); + return this; + } + } + + throw new IllegalArgumentException("Type " + type + " cannot be used as a sequence column"); + } + + public Builder addSmallSerialColumn(String name) { + return addSmallSerialColumn(name, null, SequenceDescription.newBuilder().build()); + } + + public Builder addSerialColumn(String name) { + return addSerialColumn(name, null, SequenceDescription.newBuilder().build()); + } + + public Builder addBigSerialColumn(String name) { + return addBigSerialColumn(name, null, SequenceDescription.newBuilder().build()); + } + + public Builder addSmallSerialColumn(String name, SequenceDescription sequenceDescription) { + return addSmallSerialColumn(name, null, sequenceDescription); + } + + public Builder addSerialColumn(String name, SequenceDescription sequenceDescription) { + return addSerialColumn(name, null, sequenceDescription); + } + + public Builder addBigSerialColumn(String name, SequenceDescription sequenceDescription) { + return addBigSerialColumn(name, null, sequenceDescription); + } + + public Builder addSmallSerialColumn(String name, String family, SequenceDescription sequenceDescription) { + return addSequenceColumn(name, PrimitiveType.Int16, family, sequenceDescription); + } + + public Builder addSerialColumn(String name, String family, SequenceDescription sequenceDescription) { + return addSequenceColumn(name, PrimitiveType.Int32, family, sequenceDescription); + } + + public Builder addBigSerialColumn(String name, String family, SequenceDescription sequenceDescription) { + return addSequenceColumn(name, PrimitiveType.Int64, family, sequenceDescription); + } + public Builder addKeyRange(KeyRange value) { keyRanges.add(value); return this; diff --git a/table/src/main/java/tech/ydb/table/impl/BaseSession.java b/table/src/main/java/tech/ydb/table/impl/BaseSession.java index 3ecd7844..062f791c 100644 --- a/table/src/main/java/tech/ydb/table/impl/BaseSession.java +++ b/table/src/main/java/tech/ydb/table/impl/BaseSession.java @@ -50,6 +50,7 @@ import tech.ydb.table.description.KeyBound; import tech.ydb.table.description.KeyRange; import tech.ydb.table.description.RenameIndex; +import tech.ydb.table.description.SequenceDescription; import tech.ydb.table.description.StoragePool; import tech.ydb.table.description.TableColumn; import tech.ydb.table.description.TableDescription; @@ -99,6 +100,7 @@ import tech.ydb.table.transaction.TxControl; import tech.ydb.table.values.ListType; import tech.ydb.table.values.ListValue; +import tech.ydb.table.values.PrimitiveValue; import tech.ydb.table.values.StructValue; import tech.ydb.table.values.TupleValue; import tech.ydb.table.values.Type; @@ -106,8 +108,6 @@ import tech.ydb.table.values.proto.ProtoType; import tech.ydb.table.values.proto.ProtoValue; - - /** * @author Sergey Polovko * @author Alexandr Gorshenin @@ -169,7 +169,7 @@ public String getId() { } public static CompletableFuture> createSessionId(TableRpc rpc, CreateSessionSettings settings, - boolean useServerBalancer) { + boolean useServerBalancer) { YdbTable.CreateSessionRequest request = YdbTable.CreateSessionRequest.newBuilder() .setOperationParams(Operation.buildParams(settings.toOperationSettings())) .build(); @@ -228,6 +228,48 @@ private static YdbTable.ColumnMeta buildColumnMeta(TableColumn column) { if (column.getType().getKind() != Type.Kind.OPTIONAL) { builder.setNotNull(true); } + if (column.hasDefaultValue()) { + if (column.getLiteralDefaultValue() != null) { + builder.setFromLiteral(ValueProtos.TypedValue.newBuilder() + .setType(column.getType().toPb()) + .setValue(column.getLiteralDefaultValue().toPb()).build() + ); + } + + if (column.getSequenceDescription() != null) { + SequenceDescription sequenceDescription = column.getSequenceDescription(); + YdbTable.SequenceDescription.Builder sequenceDescriptionBuilder = YdbTable.SequenceDescription + .newBuilder() + .setName(sequenceDescription.getName()); + + if (sequenceDescription.getMinValue() != null) { + sequenceDescriptionBuilder.setMinValue(sequenceDescription.getMinValue()); + } + + if (sequenceDescription.getMaxValue() != null) { + sequenceDescriptionBuilder.setMaxValue(sequenceDescription.getMaxValue()); + } + + if (sequenceDescription.getStartValue() != null) { + sequenceDescriptionBuilder.setStartValue(sequenceDescription.getStartValue()); + } + + if (sequenceDescription.getCache() != null) { + sequenceDescriptionBuilder.setCache(sequenceDescription.getCache()); + } + + if (sequenceDescription.getIncrement() != null) { + sequenceDescriptionBuilder.setIncrement(sequenceDescription.getIncrement()); + } + + if (sequenceDescription.getCycle() != null) { + sequenceDescriptionBuilder.setCycle(sequenceDescription.getCycle()); + } + + builder.setFromSequence(sequenceDescriptionBuilder.build()); + } + } + return builder.build(); } @@ -401,7 +443,7 @@ public CompletableFuture createTable( break; } - for (ColumnFamily family: description.getColumnFamilies()) { + for (ColumnFamily family : description.getColumnFamilies()) { request.addColumnFamilies(buildColumnFamily(family)); } @@ -540,11 +582,11 @@ public CompletableFuture alterTable(String path, AlterTableSettings sett .setPath(path) .setOperationParams(Operation.buildParams(settings.toOperationSettings())); - for (TableColumn addColumn: settings.getAddColumns()) { + for (TableColumn addColumn : settings.getAddColumns()) { builder.addAddColumns(buildColumnMeta(addColumn)); } - for (Changefeed addChangefeed: settings.getAddChangefeeds()) { + for (Changefeed addChangefeed : settings.getAddChangefeeds()) { builder.addAddChangefeeds(buildChangefeed(addChangefeed)); } @@ -565,15 +607,15 @@ public CompletableFuture alterTable(String path, AlterTableSettings sett builder.setAlterPartitioningSettings(buildPartitioningSettings(settings.getPartitioningSettings())); } - for (String dropColumn: settings.getDropColumns()) { + for (String dropColumn : settings.getDropColumns()) { builder.addDropColumns(dropColumn); } - for (String dropChangefeed: settings.getDropChangefeeds()) { + for (String dropChangefeed : settings.getDropChangefeeds()) { builder.addDropChangefeeds(dropChangefeed); } - for (String dropIndex: settings.getDropIndexes()) { + for (String dropIndex : settings.getDropIndexes()) { builder.addDropIndexes(dropIndex); } @@ -764,8 +806,9 @@ private static ChangefeedDescription.State mapChangefeedState(YdbTable.Changefee } } + @SuppressWarnings("checkstyle:MethodLength") private static Result mapDescribeTable(Result describeResult, - DescribeTableSettings settings) { + DescribeTableSettings settings) { if (!describeResult.isSuccess()) { return describeResult.map(r -> null); } @@ -794,12 +837,43 @@ private static Result mapDescribeTable(Result mapDescribeTable(Result> readRows(String pathToTable, Re .setPath(pathToTable) .addAllColumns(settings.getColumns()) .setKeys(settings.getKeys().isEmpty() ? TypedValue.newBuilder().build() : - ValueProtos.TypedValue.newBuilder() - .setType(ListType.of(settings.getKeys().get(0).getType()).toPb()) - .setValue(ValueProtos.Value.newBuilder() - .addAllItems(settings.getKeys().stream().map(StructValue::toPb) - .collect(Collectors.toList()))) - .build()); + ValueProtos.TypedValue.newBuilder() + .setType(ListType.of(settings.getKeys().get(0).getType()).toPb()) + .setValue(ValueProtos.Value.newBuilder() + .addAllItems(settings.getKeys().stream().map(StructValue::toPb) + .collect(Collectors.toList()))) + .build()); return interceptResult(rpc.readRows(requestBuilder.build(), makeOptions(settings).build())) .thenApply(result -> result.map(ReadRowsResult::new)); } @@ -1241,7 +1315,7 @@ ReadTablePart readValue(YdbTable.ReadTableResponse message) { @Override public GrpcReadStream executeScanQuery(String query, Params params, - ExecuteScanQuerySettings settings) { + ExecuteScanQuerySettings settings) { YdbTable.ExecuteScanQueryRequest req = YdbTable.ExecuteScanQueryRequest.newBuilder() .setQuery(YdbTable.Query.newBuilder().setYqlText(query)) .setMode(settings.getMode().toPb()) @@ -1406,7 +1480,9 @@ private abstract class ProxyStream implements GrpcReadStream { } abstract StatusIds.StatusCode readStatusCode(R message); + abstract List readIssues(R message); + abstract T readValue(R message); private void onClose(Status streamStatus, Throwable streamError) { @@ -1492,7 +1568,7 @@ public CompletableFuture> executeDataQuery( currentStatusFuture.complete(Status .of(StatusCode.ABORTED) .withIssues(Issue.of("ExecuteDataQuery on transaction failed with status " - + result.getStatus(), Issue.Severity.ERROR))); + + result.getStatus(), Issue.Severity.ERROR))); } }); } diff --git a/table/src/test/java/tech/ydb/table/integration/CreateTableTest.java b/table/src/test/java/tech/ydb/table/integration/CreateTableTest.java new file mode 100644 index 00000000..ecb2d0c1 --- /dev/null +++ b/table/src/test/java/tech/ydb/table/integration/CreateTableTest.java @@ -0,0 +1,248 @@ +package tech.ydb.table.integration; + +import org.junit.Assert; +import org.junit.ClassRule; + +import org.junit.Test; + +import tech.ydb.core.Result; +import tech.ydb.core.Status; +import tech.ydb.table.SessionRetryContext; +import tech.ydb.table.description.SequenceDescription; +import tech.ydb.table.description.TableColumn; +import tech.ydb.table.description.TableDescription; +import tech.ydb.table.impl.SimpleTableClient; +import tech.ydb.table.rpc.grpc.GrpcTableRpc; +import tech.ydb.table.values.PrimitiveType; +import tech.ydb.table.values.PrimitiveValue; +import tech.ydb.test.junit4.GrpcTransportRule; + +import java.util.stream.Collectors; + +/** + * @author Kirill Kurdyukov + */ +public class CreateTableTest { + + @ClassRule + public final static GrpcTransportRule ydbTransport = new GrpcTransportRule(); + + private final SimpleTableClient tableClient = SimpleTableClient.newClient( + GrpcTableRpc.useTransport(ydbTransport) + ).build(); + + private final SessionRetryContext ctx = SessionRetryContext.create(tableClient).build(); + + @Test + public void smallSerialTest() { + String tablePath = ydbTransport.getDatabase() + "/small_serial_table"; + + TableDescription tableDescription = TableDescription.newBuilder() + .addSmallSerialColumn("id") + .setPrimaryKey("id") + .build(); + + Status createStatus = ctx.supplyStatus(session -> session.createTable(tablePath, tableDescription)).join(); + Assert.assertTrue("Create table with small serial " + createStatus, createStatus.isSuccess()); + + Result describeResult = ctx.supplyResult(session -> session.describeTable(tablePath)).join(); + Assert.assertTrue("Describe table with small serial " + describeResult.getStatus(), describeResult.isSuccess()); + TableColumn tableColumn = describeResult.getValue().getColumns().get(0); + Assert.assertNotNull(tableColumn.getSequenceDescription()); + Assert.assertEquals("sequence_default", tableColumn.getSequenceDescription().getName()); + Assert.assertEquals(PrimitiveType.Int16, tableColumn.getType()); + } + + @Test + public void serialTest() { + String tablePath = ydbTransport.getDatabase() + "/serial_table"; + + TableDescription tableDescription = TableDescription.newBuilder() + .addSerialColumn("id") + .setPrimaryKey("id") + .build(); + + Status createStatus = ctx.supplyStatus(session -> + session.createTable(tablePath, tableDescription)).join(); + Assert.assertTrue("Create table with serial " + createStatus, createStatus.isSuccess()); + + Result describeResult = ctx.supplyResult(session -> session.describeTable(tablePath)).join(); + Assert.assertTrue("Describe table with serial " + describeResult.getStatus(), describeResult.isSuccess()); + TableColumn tableColumn = describeResult.getValue().getColumns().get(0); + Assert.assertNotNull(tableColumn.getSequenceDescription()); + Assert.assertEquals("sequence_default", tableColumn.getSequenceDescription().getName()); + Assert.assertEquals(PrimitiveType.Int32, tableColumn.getType()); + + ctx.supplyStatus(session -> session.dropTable(tablePath)).join(); + } + + @Test + public void bigSerialTest() { + String tablePath = ydbTransport.getDatabase() + "/big_serial_table"; + + TableDescription tableDescription = TableDescription.newBuilder() + .addBigSerialColumn("id") + .setPrimaryKey("id") + .build(); + + Status createStatus = ctx.supplyStatus(session -> + session.createTable(tablePath, tableDescription)).join(); + Assert.assertTrue("Create table with big serial " + createStatus, createStatus.isSuccess()); + Result describeResult = ctx.supplyResult(session -> session.describeTable(tablePath)).join(); + Assert.assertTrue("Describe table with big serial " + describeResult.getStatus(), describeResult.isSuccess()); + TableDescription description = describeResult.getValue(); + TableColumn tableColumn = description.getColumns().get(0); + Assert.assertNotNull(tableColumn.getSequenceDescription()); + Assert.assertEquals("sequence_default", tableColumn.getSequenceDescription().getName()); + Assert.assertEquals(PrimitiveType.Int64, tableColumn.getType()); + ctx.supplyStatus(session -> session.dropTable(tablePath)).join(); + } + + @Test + public void defaultValueTest() { + String tablePath = ydbTransport.getDatabase() + "/default_value_table"; + + TableDescription tableDescription = TableDescription.newBuilder() + .addColumn("id", PrimitiveType.Text, PrimitiveValue.newText("text")) + .setPrimaryKey("id") + .build(); + + Status createStatus = ctx.supplyStatus(session -> session.createTable(tablePath, tableDescription)).join(); + Assert.assertTrue("Create table with indexes " + createStatus, createStatus.isSuccess()); + Result describeResult = ctx.supplyResult(session -> session.describeTable(tablePath)).join(); + Assert.assertTrue("Describe table with indexes " + describeResult.getStatus(), describeResult.isSuccess()); + TableColumn tableColumn = describeResult.getValue().getColumns().get(0); + Assert.assertNull(tableColumn.getSequenceDescription()); + Assert.assertEquals("text", tableColumn.getLiteralDefaultValue().getText()); + Assert.assertEquals(PrimitiveType.Text, tableColumn.getType()); + ctx.supplyStatus(session -> session.dropTable(tablePath)).join(); + } + + @Test + public void customSequenceDescriptionTest() { + String tablePath = ydbTransport.getDatabase() + "/default_value_table"; + + TableDescription tableDescription = TableDescription.newBuilder() + .addBigSerialColumn("id", SequenceDescription.newBuilder() + .setCache(5L) + .setMaxValue((long) Integer.MAX_VALUE) + .setMinValue(10L) + .setName("custom_sequence_description") + .setCycle(true) + .setIncrement(2L) + .setStartValue(12L) + .build() + ) + .setPrimaryKey("id") + .build(); + + Status createStatus = ctx.supplyStatus(session -> session.createTable(tablePath, tableDescription)).join(); + Assert.assertTrue("Create table with sequence description " + createStatus, createStatus.isSuccess()); + Result describeResult = ctx.supplyResult(session -> session.describeTable(tablePath)).join(); + Assert.assertTrue("Describe table with sequence description " + describeResult.getStatus(), + describeResult.isSuccess()); + TableDescription description = describeResult.getValue(); + SequenceDescription sequenceDescription = description.getColumns().get(0).getSequenceDescription(); + Assert.assertNotNull(sequenceDescription); + Assert.assertEquals("custom_sequence_description", sequenceDescription.getName()); + Assert.assertEquals(Integer.MAX_VALUE, sequenceDescription.getMaxValue().intValue()); + Assert.assertEquals(10L, (long) sequenceDescription.getMinValue()); + Assert.assertEquals(5L, (long) sequenceDescription.getCache()); + Assert.assertEquals(true, sequenceDescription.getCycle()); + Assert.assertEquals(2L, (long) sequenceDescription.getIncrement()); + Assert.assertEquals(12L, (long) sequenceDescription.getStartValue()); + ctx.supplyStatus(session -> session.dropTable(tablePath)).join(); + } + + @Test + public void copyTableWithSequenceAndDefaultValue() { + String tablePath = ydbTransport.getDatabase() + "/simple_table"; + + TableDescription tableDescription = TableDescription.newBuilder() + .addBigSerialColumn("id", SequenceDescription.newBuilder() + .setCache(5L) + .setMaxValue((long) Integer.MAX_VALUE) + .setMinValue(10L) + .setName("custom_sequence_description") + .setCycle(true) + .setIncrement(2L) + .setStartValue(12L) + .build() + ) + .addColumn("name", PrimitiveType.Text, PrimitiveValue.newText("new_name")) + .addNonnullColumn("another_name", PrimitiveType.Bool) + .setPrimaryKey("id") + .build(); + Status createStatus = ctx.supplyStatus(session -> session.createTable(tablePath, tableDescription)).join(); + Assert.assertTrue("Create table " + createStatus, createStatus.isSuccess()); + Result describeResult = ctx.supplyResult(session -> session.describeTable(tablePath)).join(); + Assert.assertTrue("Describe table " + describeResult.getStatus(), + describeResult.isSuccess()); + TableDescription description = describeResult.getValue(); + Assert.assertEquals(3, description.getColumns().size()); + SequenceDescription sequenceDescription = description.getColumns().get(0).getSequenceDescription(); + Assert.assertNotNull(sequenceDescription); + Assert.assertEquals("custom_sequence_description", sequenceDescription.getName()); + Assert.assertEquals(Integer.MAX_VALUE, sequenceDescription.getMaxValue().intValue()); + Assert.assertEquals(10L, (long) sequenceDescription.getMinValue()); + Assert.assertEquals(5L, (long) sequenceDescription.getCache()); + Assert.assertEquals(true, sequenceDescription.getCycle()); + Assert.assertEquals(2L, (long) sequenceDescription.getIncrement()); + Assert.assertEquals(12L, (long) sequenceDescription.getStartValue()); + TableColumn tableColumn = describeResult.getValue().getColumns().get(1); + Assert.assertNull(tableColumn.getSequenceDescription()); + Assert.assertEquals("new_name", tableColumn.getLiteralDefaultValue().getText()); + Assert.assertEquals(PrimitiveType.Text, tableColumn.getType()); + TableColumn anotherTableColumn = describeResult.getValue().getColumns().get(2); + Assert.assertNull(anotherTableColumn.getSequenceDescription()); + Assert.assertNull(anotherTableColumn.getLiteralDefaultValue()); + Assert.assertEquals("new_name", tableColumn.getLiteralDefaultValue().getText()); + Assert.assertEquals(PrimitiveType.Text, tableColumn.getType()); + + TableDescription.Builder copyTableDescription = TableDescription.newBuilder(); + + for (TableColumn columnTable : description.getColumns()) { + if (columnTable.getSequenceDescription() != null) { + copyTableDescription.addSequenceColumn("copy_" + columnTable.getName(), + columnTable.getType(), columnTable.getFamily(), columnTable.getSequenceDescription()); + + continue; + } + + copyTableDescription.addColumn(columnTable.getName(), columnTable.getType(), columnTable.getFamily(), + columnTable.getLiteralDefaultValue()); + } + + copyTableDescription.setPrimaryKeys(description.getPrimaryKeys().stream() + .map(key -> "copy_" + key).collect(Collectors.toList())); + + createStatus = ctx.supplyStatus(session -> session + .createTable(tablePath + "_copy", copyTableDescription.build())).join(); + Assert.assertTrue("Create copy table " + createStatus, createStatus.isSuccess()); + describeResult = ctx.supplyResult(session -> session.describeTable(tablePath + "_copy")).join(); + Assert.assertTrue("Describe copy table " + describeResult.getStatus(), + describeResult.isSuccess()); + description = describeResult.getValue(); + Assert.assertEquals(3, description.getColumns().size()); + sequenceDescription = description.getColumns().get(0).getSequenceDescription(); + Assert.assertNotNull(sequenceDescription); + Assert.assertEquals("custom_sequence_description", sequenceDescription.getName()); + Assert.assertEquals(Integer.MAX_VALUE, sequenceDescription.getMaxValue().intValue()); + Assert.assertEquals(10L, (long) sequenceDescription.getMinValue()); + Assert.assertEquals(5L, (long) sequenceDescription.getCache()); + Assert.assertEquals(true, sequenceDescription.getCycle()); + Assert.assertEquals(2L, (long) sequenceDescription.getIncrement()); + Assert.assertEquals(12L, (long) sequenceDescription.getStartValue()); + tableColumn = describeResult.getValue().getColumns().get(1); + Assert.assertNull(tableColumn.getSequenceDescription()); + Assert.assertEquals("new_name", tableColumn.getLiteralDefaultValue().getText()); + Assert.assertEquals(PrimitiveType.Text, tableColumn.getType()); + anotherTableColumn = describeResult.getValue().getColumns().get(2); + Assert.assertNull(anotherTableColumn.getSequenceDescription()); + Assert.assertNull(anotherTableColumn.getLiteralDefaultValue()); + Assert.assertEquals("new_name", tableColumn.getLiteralDefaultValue().getText()); + Assert.assertEquals(PrimitiveType.Text, tableColumn.getType()); + + ctx.supplyStatus(session -> session.dropTable(tablePath)).join(); + } +} From 7058bb639d98ffd8a83b678549152147a8268f72 Mon Sep 17 00:00:00 2001 From: KirillKurdyukov Date: Thu, 2 Oct 2025 16:50:04 +0300 Subject: [PATCH 2/4] fix linter & update CHANGELOG.md --- CHANGELOG.md | 1 + .../java/tech/ydb/table/description/TableDescription.java | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee8db87b..6c07e22e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +* Table: CreateTable with default value options * Table: AlterTable supports index renaming ## 2.3.20 ## diff --git a/table/src/main/java/tech/ydb/table/description/TableDescription.java b/table/src/main/java/tech/ydb/table/description/TableDescription.java index dcc6c984..afe5b575 100644 --- a/table/src/main/java/tech/ydb/table/description/TableDescription.java +++ b/table/src/main/java/tech/ydb/table/description/TableDescription.java @@ -167,7 +167,12 @@ public Builder addSequenceColumn(String name, Type type, String family) { return addSequenceColumn(name, type, family, SequenceDescription.newBuilder().build()); } - public Builder addSequenceColumn(String name, Type type, String family, SequenceDescription sequenceDescription) { + public Builder addSequenceColumn( + String name, + Type type, + String family, + SequenceDescription sequenceDescription + ) { if (type instanceof PrimitiveType) { PrimitiveType primitiveType = (PrimitiveType) type; @@ -181,6 +186,7 @@ public Builder addSequenceColumn(String name, Type type, String family, Sequence case Int64: columns.put(name, new TableColumn(name, PrimitiveType.Int64, family, sequenceDescription)); return this; + default: } } From b3766dce98a58414eb7e8b5215a0f457b97ec59b Mon Sep 17 00:00:00 2001 From: KirillKurdyukov Date: Thu, 2 Oct 2025 17:07:41 +0300 Subject: [PATCH 3/4] delete unused constructor --- .../tech/ydb/table/description/TableColumn.java | 16 ++-------------- .../java/tech/ydb/table/impl/BaseSession.java | 15 ++++++++------- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/table/src/main/java/tech/ydb/table/description/TableColumn.java b/table/src/main/java/tech/ydb/table/description/TableColumn.java index 2a8a83c9..d860bf53 100644 --- a/table/src/main/java/tech/ydb/table/description/TableColumn.java +++ b/table/src/main/java/tech/ydb/table/description/TableColumn.java @@ -15,26 +15,15 @@ public class TableColumn { private final Type type; @Nullable private final String family; - private final boolean hasDefaultValue; @Nullable private final PrimitiveValue literalDefaultValue; @Nullable private final SequenceDescription sequenceDescription; - public TableColumn(String name, Type type, String family, boolean hasDefaultValue) { - this.name = name; - this.type = type; - this.family = family; - this.hasDefaultValue = hasDefaultValue; - this.literalDefaultValue = null; - this.sequenceDescription = null; - } - public TableColumn(String name, Type type, @Nullable String family, PrimitiveValue literalDefaultValue) { this.name = name; this.type = type; this.family = family; - this.hasDefaultValue = true; this.literalDefaultValue = literalDefaultValue; this.sequenceDescription = null; } @@ -43,13 +32,12 @@ public TableColumn(String name, Type type, @Nullable String family, SequenceDesc this.name = name; this.type = type; this.family = family; - this.hasDefaultValue = true; this.literalDefaultValue = null; this.sequenceDescription = sequenceDescription; } public TableColumn(String name, Type type, String family) { - this(name, type, family, false); + this(name, type, family, (PrimitiveValue) null); } public TableColumn(String name, Type type) { @@ -65,7 +53,7 @@ public Type getType() { } public boolean hasDefaultValue() { - return hasDefaultValue; + return literalDefaultValue != null && sequenceDescription != null; } @Nullable diff --git a/table/src/main/java/tech/ydb/table/impl/BaseSession.java b/table/src/main/java/tech/ydb/table/impl/BaseSession.java index 062f791c..62df0856 100644 --- a/table/src/main/java/tech/ydb/table/impl/BaseSession.java +++ b/table/src/main/java/tech/ydb/table/impl/BaseSession.java @@ -839,11 +839,7 @@ private static Result mapDescribeTable(Result mapDescribeTable(Result Date: Thu, 2 Oct 2025 17:09:39 +0300 Subject: [PATCH 4/4] fix --- table/src/main/java/tech/ydb/table/description/TableColumn.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/table/src/main/java/tech/ydb/table/description/TableColumn.java b/table/src/main/java/tech/ydb/table/description/TableColumn.java index d860bf53..18fc6167 100644 --- a/table/src/main/java/tech/ydb/table/description/TableColumn.java +++ b/table/src/main/java/tech/ydb/table/description/TableColumn.java @@ -53,7 +53,7 @@ public Type getType() { } public boolean hasDefaultValue() { - return literalDefaultValue != null && sequenceDescription != null; + return literalDefaultValue != null || sequenceDescription != null; } @Nullable