From 98f87d41cda4265528653fd7c872b9c23af81671 Mon Sep 17 00:00:00 2001 From: Alexandr Gorshenin Date: Wed, 5 Nov 2025 15:28:05 +0000 Subject: [PATCH 1/2] Updated implementation of serial types and columns with default value --- .../description/SequenceDescription.java | 9 +- .../table/description/TableDescription.java | 71 +++++++++------ .../java/tech/ydb/table/impl/BaseSession.java | 88 +++++++++++-------- 3 files changed, 98 insertions(+), 70 deletions(-) diff --git a/table/src/main/java/tech/ydb/table/description/SequenceDescription.java b/table/src/main/java/tech/ydb/table/description/SequenceDescription.java index 0f6f30c9..9cd3341b 100644 --- a/table/src/main/java/tech/ydb/table/description/SequenceDescription.java +++ b/table/src/main/java/tech/ydb/table/description/SequenceDescription.java @@ -6,7 +6,9 @@ * @author Kirill Kurdyukov */ public class SequenceDescription { + public static final SequenceDescription DEFAULT = SequenceDescription.newBuilder().build(); + @Nullable private final String name; @Nullable private final Long minValue; @@ -31,6 +33,7 @@ private SequenceDescription(Builder builder) { this.cycle = builder.cycle; } + @Nullable public String getName() { return name; } @@ -70,7 +73,7 @@ public static Builder newBuilder() { } public static class Builder { - private String name = "sequence_default"; + private String name; private Long minValue; private Long maxValue; private Long startValue; @@ -114,10 +117,6 @@ public Builder setCycle(@Nullable Boolean cycle) { } 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/TableDescription.java b/table/src/main/java/tech/ydb/table/description/TableDescription.java index afe5b575..ee44912e 100644 --- a/table/src/main/java/tech/ydb/table/description/TableDescription.java +++ b/table/src/main/java/tech/ydb/table/description/TableDescription.java @@ -141,32 +141,62 @@ public Builder addColumn(TableColumn column) { } public Builder addNonnullColumn(String name, Type type) { - return addNonnullColumn(name, type, (String) null); + return addColumn(new TableColumn(name, type, null)); } public Builder addNonnullColumn(String name, Type type, String family) { - columns.put(name, new TableColumn(name, type, family)); - return this; + return addColumn(new TableColumn(name, type, family)); + } + + public Builder addNonnullColumn(String name, Type type, PrimitiveValue defaultValue) { + return addColumn(new TableColumn(name, type, null, defaultValue)); } + public Builder addNullableColumn(String name, Type type) { + return addColumn(new TableColumn(name, OptionalType.of(type))); + } + + public Builder addNullableColumn(String name, Type type, String family) { + return addColumn(new TableColumn(name, OptionalType.of(type), family)); + } + + public Builder addNullableColumn(String name, Type type, PrimitiveValue defaultValue) { + return addColumn(new TableColumn(name, OptionalType.of(type), null, defaultValue)); + } + + public Builder addSmallSerialColumn(String name) { + return addColumn(new TableColumn(name, PrimitiveType.Int16, null, SequenceDescription.DEFAULT)); + } + + public Builder addSerialColumn(String name) { + return addColumn(new TableColumn(name, PrimitiveType.Int32, null, SequenceDescription.DEFAULT)); + } + + public Builder addBigSerialColumn(String name) { + return addColumn(new TableColumn(name, PrimitiveType.Int64, null, SequenceDescription.DEFAULT)); + } + + @Deprecated public Builder addColumn(String name, Type type, PrimitiveValue defaultValue) { - columns.put(name, new TableColumn(name, type, null, defaultValue)); - return this; + return addColumn(new TableColumn(name, type, null, defaultValue)); } + @Deprecated public Builder addColumn(String name, Type type, String family, PrimitiveValue defaultValue) { - columns.put(name, new TableColumn(name, type, family, defaultValue)); - return this; + return addColumn(new TableColumn(name, type, family, defaultValue)); } + @Deprecated public Builder addSequenceColumn(String name, Type type) { return addSequenceColumn(name, type, null, SequenceDescription.newBuilder().build()); } + @Deprecated public Builder addSequenceColumn(String name, Type type, String family) { return addSequenceColumn(name, type, family, SequenceDescription.newBuilder().build()); } + @Deprecated public Builder addSequenceColumn( String name, Type type, @@ -193,38 +223,32 @@ public Builder addSequenceColumn( 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()); - } - + @Deprecated public Builder addSmallSerialColumn(String name, SequenceDescription sequenceDescription) { return addSmallSerialColumn(name, null, sequenceDescription); } + @Deprecated public Builder addSerialColumn(String name, SequenceDescription sequenceDescription) { return addSerialColumn(name, null, sequenceDescription); } + @Deprecated public Builder addBigSerialColumn(String name, SequenceDescription sequenceDescription) { return addBigSerialColumn(name, null, sequenceDescription); } + @Deprecated public Builder addSmallSerialColumn(String name, String family, SequenceDescription sequenceDescription) { return addSequenceColumn(name, PrimitiveType.Int16, family, sequenceDescription); } + @Deprecated public Builder addSerialColumn(String name, String family, SequenceDescription sequenceDescription) { return addSequenceColumn(name, PrimitiveType.Int32, family, sequenceDescription); } + @Deprecated public Builder addBigSerialColumn(String name, String family, SequenceDescription sequenceDescription) { return addSequenceColumn(name, PrimitiveType.Int64, family, sequenceDescription); } @@ -234,15 +258,6 @@ public Builder addKeyRange(KeyRange value) { return this; } - public Builder addNullableColumn(String name, Type type) { - return addNullableColumn(name, type, null); - } - - public Builder addNullableColumn(String name, Type type, String family) { - columns.put(name, new TableColumn(name, OptionalType.of(type), family)); - return this; - } - public Builder setPrimaryKey(String name) { checkColumnKnown(name); primaryKeys = ImmutableList.of(name); 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 975956f1..4a8d6023 100644 --- a/table/src/main/java/tech/ydb/table/impl/BaseSession.java +++ b/table/src/main/java/tech/ydb/table/impl/BaseSession.java @@ -98,6 +98,7 @@ import tech.ydb.table.transaction.Transaction; import tech.ydb.table.transaction.TxControl; import tech.ydb.table.values.ListType; +import tech.ydb.table.values.OptionalValue; import tech.ydb.table.values.PrimitiveValue; import tech.ydb.table.values.StructValue; import tech.ydb.table.values.TupleValue; @@ -228,43 +229,41 @@ private static YdbTable.ColumnMeta buildColumnMeta(TableColumn column) { } if (column.hasDefaultValue()) { if (column.getLiteralDefaultValue() != null) { - builder.setFromLiteral(ValueProtos.TypedValue.newBuilder() - .setType(column.getType().toPb()) - .setValue(column.getLiteralDefaultValue().toPb()).build() - ); + builder.setFromLiteral(ProtoValue.toTypedValue(column.getLiteralDefaultValue())); } - if (column.getSequenceDescription() != null) { - SequenceDescription sequenceDescription = column.getSequenceDescription(); - YdbTable.SequenceDescription.Builder sequenceDescriptionBuilder = YdbTable.SequenceDescription + SequenceDescription seqDescription = column.getSequenceDescription(); + if (seqDescription != null) { + String seqName = seqDescription.getName(); + YdbTable.SequenceDescription.Builder seqBuilder = YdbTable.SequenceDescription .newBuilder() - .setName(sequenceDescription.getName()); + .setName(seqName != null ? seqName : "_serial_column_" + column.getName()); - if (sequenceDescription.getMinValue() != null) { - sequenceDescriptionBuilder.setMinValue(sequenceDescription.getMinValue()); + if (seqDescription.getMinValue() != null) { + seqBuilder.setMinValue(seqDescription.getMinValue()); } - if (sequenceDescription.getMaxValue() != null) { - sequenceDescriptionBuilder.setMaxValue(sequenceDescription.getMaxValue()); + if (seqDescription.getMaxValue() != null) { + seqBuilder.setMaxValue(seqDescription.getMaxValue()); } - if (sequenceDescription.getStartValue() != null) { - sequenceDescriptionBuilder.setStartValue(sequenceDescription.getStartValue()); + if (seqDescription.getStartValue() != null) { + seqBuilder.setStartValue(seqDescription.getStartValue()); } - if (sequenceDescription.getCache() != null) { - sequenceDescriptionBuilder.setCache(sequenceDescription.getCache()); + if (seqDescription.getCache() != null) { + seqBuilder.setCache(seqDescription.getCache()); } - if (sequenceDescription.getIncrement() != null) { - sequenceDescriptionBuilder.setIncrement(sequenceDescription.getIncrement()); + if (seqDescription.getIncrement() != null) { + seqBuilder.setIncrement(seqDescription.getIncrement()); } - if (sequenceDescription.getCycle() != null) { - sequenceDescriptionBuilder.setCycle(sequenceDescription.getCycle()); + if (seqDescription.getCycle() != null) { + seqBuilder.setCycle(seqDescription.getCycle()); } - builder.setFromSequence(sequenceDescriptionBuilder.build()); + builder.setFromSequence(seqBuilder.build()); } } @@ -442,7 +441,9 @@ public CompletableFuture createTable( } for (ColumnFamily family : description.getColumnFamilies()) { - request.addColumnFamilies(buildColumnFamily(family)); + if (!"default".equals(family.getName())) { + request.addColumnFamilies(buildColumnFamily(family)); + } } for (TableColumn column : description.getColumns()) { @@ -839,40 +840,53 @@ private static Result mapDescribeTable(Result literalValue = ProtoValue.fromPb(literalType, literalPb.getValue()); + if (literalType.getKind() == Type.Kind.OPTIONAL) { // unwrap optional value + OptionalValue optional = literalValue.asOptional(); + if (optional.isPresent()) { + literalType = type.unwrapOptional(); + literalValue = optional.get(); + } + } + if (literalType.getKind() == Type.Kind.PRIMITIVE) { + defaultValue = literalValue.asData(); + } + } + + description.addColumn(new TableColumn(column.getName(), type, column.getFamily(), defaultValue)); } description.setPrimaryKeys(desc.getPrimaryKeyList()); for (int i = 0; i < desc.getIndexesCount(); i++) { From 9ad32397e882f0b5458ccce589d59ed3cdd47b28 Mon Sep 17 00:00:00 2001 From: Alexandr Gorshenin Date: Wed, 5 Nov 2025 15:27:21 +0000 Subject: [PATCH 2/2] Updated test for serial columns and columns with default value --- .../table/integration/CreateTableTest.java | 248 ------- .../table/integration/SerialColumnsTest.java | 648 ++++++++++++++++++ 2 files changed, 648 insertions(+), 248 deletions(-) delete mode 100644 table/src/test/java/tech/ydb/table/integration/CreateTableTest.java create mode 100644 table/src/test/java/tech/ydb/table/integration/SerialColumnsTest.java diff --git a/table/src/test/java/tech/ydb/table/integration/CreateTableTest.java b/table/src/test/java/tech/ydb/table/integration/CreateTableTest.java deleted file mode 100644 index ecb2d0c1..00000000 --- a/table/src/test/java/tech/ydb/table/integration/CreateTableTest.java +++ /dev/null @@ -1,248 +0,0 @@ -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(); - } -} diff --git a/table/src/test/java/tech/ydb/table/integration/SerialColumnsTest.java b/table/src/test/java/tech/ydb/table/integration/SerialColumnsTest.java new file mode 100644 index 00000000..92f17d7c --- /dev/null +++ b/table/src/test/java/tech/ydb/table/integration/SerialColumnsTest.java @@ -0,0 +1,648 @@ +package tech.ydb.table.integration; + + +import org.junit.After; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; + +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.query.DataQueryResult; +import tech.ydb.table.result.ResultSetReader; +import tech.ydb.table.rpc.grpc.GrpcTableRpc; +import tech.ydb.table.transaction.TxControl; +import tech.ydb.table.values.PrimitiveType; +import tech.ydb.table.values.PrimitiveValue; +import tech.ydb.test.junit4.GrpcTransportRule; + +/** + * @author Kirill Kurdyukov + */ +public class SerialColumnsTest { + + @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(); + private final static String TABLE = "create_table_test"; + + private String tablePath() { + return ydbTransport.getDatabase() + "/" + TABLE; + } + + @After + public void dropTable() { + ctx.supplyStatus(session -> session.dropTable(tablePath())).join(); + } + + @Test + public void nullableSerialColumnTest() { + TableDescription createTable = TableDescription.newBuilder() + .addColumn(new TableColumn("id", PrimitiveType.Int32.makeOptional(), null, SequenceDescription.DEFAULT)) + .addNullableColumn("value", PrimitiveType.Text) + .setPrimaryKey("id") + .build(); + + ctx.supplyStatus(session -> session.createTable(tablePath(), createTable)).join() + .expectSuccess("cannot create table " + tablePath()); + + TableDescription desc = ctx.supplyResult(session -> session.describeTable(tablePath())).join().getValue(); + Assert.assertEquals(2, desc.getColumns().size()); + + TableColumn id = desc.getColumns().get(0); + TableColumn value = desc.getColumns().get(1); + + Assert.assertEquals("id", id.getName()); + Assert.assertNull(id.getLiteralDefaultValue()); + Assert.assertNotNull(id.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Int32.makeOptional(), id.getType()); + + Assert.assertEquals("value", value.getName()); + Assert.assertNull(value.getLiteralDefaultValue()); + Assert.assertNull(value.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Text.makeOptional(), value.getType()); + + SequenceDescription sequence = id.getSequenceDescription(); + Assert.assertNotNull(sequence); + Assert.assertEquals("_serial_column_id", sequence.getName()); + + DataQueryResult dataQueryResult = ctx.supplyResult(session -> session.executeDataQuery( + "INSERT INTO " + TABLE + " (value) VALUES ('1'), ('2'), ('3') RETURNING id;", + TxControl.serializableRw() + )).join().getValue(); + + Assert.assertEquals(1, dataQueryResult.getResultSetCount()); + ResultSetReader rs = dataQueryResult.getResultSet(0); + Assert.assertTrue(rs.next()); + Assert.assertEquals(1, rs.getColumn("id").getInt32()); + Assert.assertTrue(rs.next()); + Assert.assertEquals(2, rs.getColumn("id").getInt32()); + Assert.assertTrue(rs.next()); + Assert.assertEquals(3, rs.getColumn("id").getInt32()); + Assert.assertFalse(rs.next()); + } + + @Test + public void addSmallSerialColumnTest() { + TableDescription createTable = TableDescription.newBuilder() + .addSmallSerialColumn("id") + .addNullableColumn("value", PrimitiveType.Text) + .setPrimaryKey("id") + .build(); + + ctx.supplyStatus(session -> session.createTable(tablePath(), createTable)).join() + .expectSuccess("cannot create table " + tablePath()); + + TableDescription desc = ctx.supplyResult(session -> session.describeTable(tablePath())).join().getValue(); + Assert.assertEquals(2, desc.getColumns().size()); + + TableColumn id = desc.getColumns().get(0); + TableColumn value = desc.getColumns().get(1); + + Assert.assertEquals("id", id.getName()); + Assert.assertNull(id.getLiteralDefaultValue()); + Assert.assertNotNull(id.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Int16, id.getType()); + + Assert.assertEquals("value", value.getName()); + Assert.assertNull(value.getLiteralDefaultValue()); + Assert.assertNull(value.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Text.makeOptional(), value.getType()); + + SequenceDescription sequence = id.getSequenceDescription(); + Assert.assertNotNull(sequence); + Assert.assertEquals("_serial_column_id", sequence.getName()); + + DataQueryResult dataQueryResult = ctx.supplyResult(session -> session.executeDataQuery( + "INSERT INTO " + TABLE + " (value) VALUES ('1'), ('2'), ('3') RETURNING id;", + TxControl.serializableRw() + )).join().getValue(); + + Assert.assertEquals(1, dataQueryResult.getResultSetCount()); + ResultSetReader rs = dataQueryResult.getResultSet(0); + Assert.assertTrue(rs.next()); + Assert.assertEquals(1, rs.getColumn("id").getInt16()); + Assert.assertTrue(rs.next()); + Assert.assertEquals(2, rs.getColumn("id").getInt16()); + Assert.assertTrue(rs.next()); + Assert.assertEquals(3, rs.getColumn("id").getInt16()); + Assert.assertFalse(rs.next()); + } + + @Test + public void addSerialColumnTest() { + TableDescription createTable = TableDescription.newBuilder() + .addSerialColumn("id") + .addNullableColumn("value", PrimitiveType.Text) + .setPrimaryKey("id") + .build(); + + ctx.supplyStatus(session -> session.createTable(tablePath(), createTable)).join() + .expectSuccess("cannot create table " + tablePath()); + + TableDescription desc = ctx.supplyResult(session -> session.describeTable(tablePath())).join().getValue(); + Assert.assertEquals(2, desc.getColumns().size()); + + TableColumn id = desc.getColumns().get(0); + TableColumn value = desc.getColumns().get(1); + + Assert.assertEquals("id", id.getName()); + Assert.assertNull(id.getLiteralDefaultValue()); + Assert.assertNotNull(id.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Int32, id.getType()); + + Assert.assertEquals("value", value.getName()); + Assert.assertNull(value.getLiteralDefaultValue()); + Assert.assertNull(value.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Text.makeOptional(), value.getType()); + + SequenceDescription sequence = id.getSequenceDescription(); + Assert.assertNotNull(sequence); + Assert.assertEquals("_serial_column_id", sequence.getName()); + + DataQueryResult dataQueryResult = ctx.supplyResult(session -> session.executeDataQuery( + "INSERT INTO " + TABLE + " (value) VALUES ('1'), ('2'), ('3') RETURNING id;", + TxControl.serializableRw() + )).join().getValue(); + + Assert.assertEquals(1, dataQueryResult.getResultSetCount()); + ResultSetReader rs = dataQueryResult.getResultSet(0); + Assert.assertTrue(rs.next()); + Assert.assertEquals(1, rs.getColumn("id").getInt32()); + Assert.assertTrue(rs.next()); + Assert.assertEquals(2, rs.getColumn("id").getInt32()); + Assert.assertTrue(rs.next()); + Assert.assertEquals(3, rs.getColumn("id").getInt32()); + Assert.assertFalse(rs.next()); + } + + @Test + public void addBigSerialColumnTest() { + TableDescription createTable = TableDescription.newBuilder() + .addBigSerialColumn("id") + .addNullableColumn("value", PrimitiveType.Text) + .setPrimaryKey("id") + .build(); + + ctx.supplyStatus(session -> session.createTable(tablePath(), createTable)).join() + .expectSuccess("cannot create table " + tablePath()); + + TableDescription desc = ctx.supplyResult(session -> session.describeTable(tablePath())).join().getValue(); + Assert.assertEquals(2, desc.getColumns().size()); + + TableColumn id = desc.getColumns().get(0); + TableColumn value = desc.getColumns().get(1); + + Assert.assertEquals("id", id.getName()); + Assert.assertNull(id.getLiteralDefaultValue()); + Assert.assertNotNull(id.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Int64, id.getType()); + + Assert.assertEquals("value", value.getName()); + Assert.assertNull(value.getLiteralDefaultValue()); + Assert.assertNull(value.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Text.makeOptional(), value.getType()); + + SequenceDescription sequence = id.getSequenceDescription(); + Assert.assertNotNull(sequence); + Assert.assertEquals("_serial_column_id", sequence.getName()); + + DataQueryResult dataQueryResult = ctx.supplyResult(session -> session.executeDataQuery( + "INSERT INTO " + TABLE + " (value) VALUES ('1'), ('2'), ('3') RETURNING id;", + TxControl.serializableRw() + )).join().getValue(); + + Assert.assertEquals(1, dataQueryResult.getResultSetCount()); + ResultSetReader rs = dataQueryResult.getResultSet(0); + Assert.assertTrue(rs.next()); + Assert.assertEquals(1, rs.getColumn("id").getInt64()); + Assert.assertTrue(rs.next()); + Assert.assertEquals(2, rs.getColumn("id").getInt64()); + Assert.assertTrue(rs.next()); + Assert.assertEquals(3, rs.getColumn("id").getInt64()); + Assert.assertFalse(rs.next()); + } + + @Test + public void smallSerialYqlTest() { + ctx.supplyStatus(session -> session.executeSchemeQuery("" + + "CREATE TABLE " + TABLE + "(" + + " id SmallSerial," + + " value Text," + + " PRIMARY KEY(id))" + )).join().expectSuccess("cannot create table " + TABLE); + + TableDescription desc = ctx.supplyResult(session -> session.describeTable(tablePath())).join().getValue(); + Assert.assertEquals(2, desc.getColumns().size()); + + TableColumn id = desc.getColumns().get(0); + TableColumn value = desc.getColumns().get(1); + + Assert.assertEquals("id", id.getName()); + Assert.assertNull(id.getLiteralDefaultValue()); + Assert.assertNotNull(id.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Int16, id.getType()); + + Assert.assertEquals("value", value.getName()); + Assert.assertNull(value.getLiteralDefaultValue()); + Assert.assertNull(value.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Text.makeOptional(), value.getType()); + + SequenceDescription sequence = id.getSequenceDescription(); + Assert.assertNotNull(sequence); + Assert.assertEquals("_serial_column_id", sequence.getName()); + + DataQueryResult dataQueryResult = ctx.supplyResult(session -> session.executeDataQuery( + "INSERT INTO " + TABLE + " (value) VALUES ('1'), ('2'), ('3') RETURNING id;", + TxControl.serializableRw() + )).join().getValue(); + + Assert.assertEquals(1, dataQueryResult.getResultSetCount()); + ResultSetReader rs = dataQueryResult.getResultSet(0); + Assert.assertTrue(rs.next()); + Assert.assertEquals(1, rs.getColumn("id").getInt16()); + Assert.assertTrue(rs.next()); + Assert.assertEquals(2, rs.getColumn("id").getInt16()); + Assert.assertTrue(rs.next()); + Assert.assertEquals(3, rs.getColumn("id").getInt16()); + Assert.assertFalse(rs.next()); + } + + @Test + public void serialYqlTest() { + ctx.supplyStatus(session -> session.executeSchemeQuery("" + + "CREATE TABLE " + TABLE + "(" + + " id Serial," + + " value Text," + + " PRIMARY KEY(id))" + )).join().expectSuccess("cannot create table " + TABLE); + + TableDescription desc = ctx.supplyResult(session -> session.describeTable(tablePath())).join().getValue(); + Assert.assertEquals(2, desc.getColumns().size()); + + TableColumn id = desc.getColumns().get(0); + TableColumn value = desc.getColumns().get(1); + + Assert.assertEquals("id", id.getName()); + Assert.assertNull(id.getLiteralDefaultValue()); + Assert.assertNotNull(id.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Int32, id.getType()); + + Assert.assertEquals("value", value.getName()); + Assert.assertNull(value.getLiteralDefaultValue()); + Assert.assertNull(value.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Text.makeOptional(), value.getType()); + + SequenceDescription sequence = id.getSequenceDescription(); + Assert.assertNotNull(sequence); + Assert.assertEquals("_serial_column_id", sequence.getName()); + + DataQueryResult dataQueryResult = ctx.supplyResult(session -> session.executeDataQuery( + "INSERT INTO " + TABLE + " (value) VALUES ('1'), ('2'), ('3') RETURNING id;", + TxControl.serializableRw() + )).join().getValue(); + + Assert.assertEquals(1, dataQueryResult.getResultSetCount()); + ResultSetReader rs = dataQueryResult.getResultSet(0); + Assert.assertTrue(rs.next()); + Assert.assertEquals(1, rs.getColumn("id").getInt32()); + Assert.assertTrue(rs.next()); + Assert.assertEquals(2, rs.getColumn("id").getInt32()); + Assert.assertTrue(rs.next()); + Assert.assertEquals(3, rs.getColumn("id").getInt32()); + Assert.assertFalse(rs.next()); + } + + @Test + public void bigSerialYqlTest() { + ctx.supplyStatus(session -> session.executeSchemeQuery("" + + "CREATE TABLE " + TABLE + "(" + + " id BigSerial," + + " value Text," + + " PRIMARY KEY(id))" + )).join().expectSuccess("cannot create table " + TABLE); + + TableDescription desc = ctx.supplyResult(session -> session.describeTable(tablePath())).join().getValue(); + Assert.assertEquals(2, desc.getColumns().size()); + + TableColumn id = desc.getColumns().get(0); + TableColumn value = desc.getColumns().get(1); + + Assert.assertEquals("id", id.getName()); + Assert.assertNull(id.getLiteralDefaultValue()); + Assert.assertNotNull(id.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Int64, id.getType()); + + Assert.assertEquals("value", value.getName()); + Assert.assertNull(value.getLiteralDefaultValue()); + Assert.assertNull(value.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Text.makeOptional(), value.getType()); + + SequenceDescription sequence = id.getSequenceDescription(); + Assert.assertNotNull(sequence); + Assert.assertEquals("_serial_column_id", sequence.getName()); + + DataQueryResult dataQueryResult = ctx.supplyResult(session -> session.executeDataQuery( + "INSERT INTO " + TABLE + " (value) VALUES ('1'), ('2'), ('3') RETURNING id;", + TxControl.serializableRw() + )).join().getValue(); + + Assert.assertEquals(1, dataQueryResult.getResultSetCount()); + ResultSetReader rs = dataQueryResult.getResultSet(0); + Assert.assertTrue(rs.next()); + Assert.assertEquals(1, rs.getColumn("id").getInt64()); + Assert.assertTrue(rs.next()); + Assert.assertEquals(2, rs.getColumn("id").getInt64()); + Assert.assertTrue(rs.next()); + Assert.assertEquals(3, rs.getColumn("id").getInt64()); + Assert.assertFalse(rs.next()); + } + + @Test + public void addColumnWithDefaultValueTest() { + TableDescription createTable = TableDescription.newBuilder() + .addNonnullColumn("id", PrimitiveType.Int32) + .addNonnullColumn("v1", PrimitiveType.Text, PrimitiveValue.newText("non")) + .addNullableColumn("v2", PrimitiveType.Text, PrimitiveValue.newText("null")) + .setPrimaryKey("id") + .build(); + + ctx.supplyStatus(session -> session.createTable(tablePath(), createTable)).join() + .expectSuccess("cannot create table " + tablePath()); + + TableDescription desc = ctx.supplyResult(session -> session.describeTable(tablePath())).join().getValue(); + + Assert.assertEquals(3, desc.getColumns().size()); + + TableColumn id = desc.getColumns().get(0); + TableColumn v1 = desc.getColumns().get(1); + TableColumn v2 = desc.getColumns().get(2); + + Assert.assertEquals("id", id.getName()); + Assert.assertNull(id.getLiteralDefaultValue()); + Assert.assertNull(id.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Int32, id.getType()); + + Assert.assertEquals("v1", v1.getName()); + Assert.assertNotNull(v1.getLiteralDefaultValue()); + Assert.assertNull(v1.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Text, v1.getType()); + Assert.assertEquals(PrimitiveValue.newText("non"), v1.getLiteralDefaultValue()); + + Assert.assertEquals("v2", v2.getName()); + Assert.assertNotNull(v2.getLiteralDefaultValue()); + Assert.assertNull(v2.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Text.makeOptional(), v2.getType()); + Assert.assertEquals(PrimitiveValue.newText("null"), v2.getLiteralDefaultValue()); + + DataQueryResult dataQueryResult = ctx.supplyResult(session -> session.executeDataQuery("" + + "INSERT INTO " + TABLE + " (id) VALUES (1);" + + "INSERT INTO " + TABLE + " (id, v1) VALUES (2, 'v1');" + + "INSERT INTO " + TABLE + " (id, v2) VALUES (3, 'v2'), (4, NULL);" + + "SELECT id, v1, v2 FROM " + TABLE + " ORDER BY id", + TxControl.serializableRw() + )).join().getValue(); + + Assert.assertEquals(1, dataQueryResult.getResultSetCount()); + ResultSetReader rs = dataQueryResult.getResultSet(0); + + Assert.assertTrue(rs.next()); + Assert.assertEquals(1, rs.getColumn("id").getInt32()); + Assert.assertEquals("non", rs.getColumn("v1").getText()); + Assert.assertEquals("null", rs.getColumn("v2").getText()); + + Assert.assertTrue(rs.next()); + Assert.assertEquals(2, rs.getColumn("id").getInt32()); + Assert.assertEquals("v1", rs.getColumn("v1").getText()); + Assert.assertEquals("null", rs.getColumn("v2").getText()); + + Assert.assertTrue(rs.next()); + Assert.assertEquals(3, rs.getColumn("id").getInt32()); + Assert.assertEquals("non", rs.getColumn("v1").getText()); + Assert.assertEquals("v2", rs.getColumn("v2").getText()); + + Assert.assertTrue(rs.next()); + Assert.assertEquals(4, rs.getColumn("id").getInt32()); + Assert.assertEquals("non", rs.getColumn("v1").getText()); + Assert.assertFalse(rs.getColumn("v2").isOptionalItemPresent()); + + Assert.assertFalse(rs.next()); + } + + @Test + public void defaultValueYqlTest() { + ctx.supplyStatus(session -> session.executeSchemeQuery("" + + "CREATE TABLE " + TABLE + "(" + + " id Int32 NOT NULl," + + " v1 Text NOT NULL DEFAULT 'non'," + + " v2 Text DEFAULT 'null'," + + " PRIMARY KEY(id))" + )).join().expectSuccess("cannot create table " + TABLE); + + TableDescription desc = ctx.supplyResult(session -> session.describeTable(tablePath())).join().getValue(); + + Assert.assertEquals(3, desc.getColumns().size()); + + TableColumn id = desc.getColumns().get(0); + TableColumn v1 = desc.getColumns().get(1); + TableColumn v2 = desc.getColumns().get(2); + + Assert.assertEquals("id", id.getName()); + Assert.assertNull(id.getLiteralDefaultValue()); + Assert.assertNull(id.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Int32, id.getType()); + + Assert.assertEquals("v1", v1.getName()); + Assert.assertNotNull(v1.getLiteralDefaultValue()); + Assert.assertNull(v1.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Text, v1.getType()); + Assert.assertEquals(PrimitiveValue.newText("non"), v1.getLiteralDefaultValue()); + + Assert.assertEquals("v2", v2.getName()); + Assert.assertNotNull(v2.getLiteralDefaultValue()); + Assert.assertNull(v2.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Text.makeOptional(), v2.getType()); + Assert.assertEquals(PrimitiveValue.newText("null"), v2.getLiteralDefaultValue()); + + DataQueryResult dataQueryResult = ctx.supplyResult(session -> session.executeDataQuery("" + + "INSERT INTO " + TABLE + " (id) VALUES (1);" + + "INSERT INTO " + TABLE + " (id, v1) VALUES (2, 'v1');" + + "INSERT INTO " + TABLE + " (id, v2) VALUES (3, 'v2'), (4, NULL);" + + "SELECT id, v1, v2 FROM " + TABLE + " ORDER BY id", + TxControl.serializableRw() + )).join().getValue(); + + Assert.assertEquals(1, dataQueryResult.getResultSetCount()); + ResultSetReader rs = dataQueryResult.getResultSet(0); + + Assert.assertTrue(rs.next()); + Assert.assertEquals(1, rs.getColumn("id").getInt32()); + Assert.assertEquals("non", rs.getColumn("v1").getText()); + Assert.assertEquals("null", rs.getColumn("v2").getText()); + + Assert.assertTrue(rs.next()); + Assert.assertEquals(2, rs.getColumn("id").getInt32()); + Assert.assertEquals("v1", rs.getColumn("v1").getText()); + Assert.assertEquals("null", rs.getColumn("v2").getText()); + + Assert.assertTrue(rs.next()); + Assert.assertEquals(3, rs.getColumn("id").getInt32()); + Assert.assertEquals("non", rs.getColumn("v1").getText()); + Assert.assertEquals("v2", rs.getColumn("v2").getText()); + + Assert.assertTrue(rs.next()); + Assert.assertEquals(4, rs.getColumn("id").getInt32()); + Assert.assertEquals("non", rs.getColumn("v1").getText()); + Assert.assertFalse(rs.getColumn("v2").isOptionalItemPresent()); + + Assert.assertFalse(rs.next()); + } + + @Test + public void customSequenceDescriptionTest() { + SequenceDescription sequenceConfig = SequenceDescription.newBuilder() + .setCache(5L) + .setMaxValue(Long.MAX_VALUE) + .setMinValue(10L) + .setName("custom_sequence") + .setCycle(true) + .setIncrement(2L) + .setStartValue(12L) + .build(); + + TableDescription createTable = TableDescription.newBuilder() + .addColumn(new TableColumn("id", PrimitiveType.Int32, null, sequenceConfig)) + .addNullableColumn("value", PrimitiveType.Text) + .setPrimaryKey("id") + .build(); + + ctx.supplyStatus(session -> session.createTable(tablePath(), createTable)).join() + .expectSuccess("cannot create table " + tablePath()); + + TableDescription desc = ctx.supplyResult(session -> session.describeTable(tablePath())).join().getValue(); + Assert.assertEquals(2, desc.getColumns().size()); + + TableColumn id = desc.getColumns().get(0); + TableColumn value = desc.getColumns().get(1); + + Assert.assertEquals("id", id.getName()); + Assert.assertNull(id.getLiteralDefaultValue()); + Assert.assertNotNull(id.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Int32, id.getType()); + + Assert.assertEquals("value", value.getName()); + Assert.assertNull(value.getLiteralDefaultValue()); + Assert.assertNull(value.getSequenceDescription()); + Assert.assertEquals(PrimitiveType.Text.makeOptional(), value.getType()); + + SequenceDescription sequence = id.getSequenceDescription(); + Assert.assertNotNull(sequence); + Assert.assertEquals("custom_sequence", sequence.getName()); + Assert.assertEquals(Long.valueOf(Long.MAX_VALUE), sequence.getMaxValue()); + Assert.assertEquals(Long.valueOf(10L), sequence.getMinValue()); + Assert.assertEquals(Long.valueOf(5L), sequence.getCache()); + Assert.assertTrue(sequence.getCycle()); + Assert.assertEquals(Long.valueOf(2L), sequence.getIncrement()); + Assert.assertEquals(Long.valueOf(12L), sequence.getStartValue()); + + DataQueryResult dataQueryResult = ctx.supplyResult(session -> session.executeDataQuery( + "INSERT INTO " + TABLE + " (value) VALUES ('1'), ('2'), ('3') RETURNING id;", + TxControl.serializableRw() + )).join().getValue(); + + Assert.assertEquals(1, dataQueryResult.getResultSetCount()); + ResultSetReader rs = dataQueryResult.getResultSet(0); + Assert.assertTrue(rs.next()); + Assert.assertEquals(12, rs.getColumn("id").getInt32()); + Assert.assertTrue(rs.next()); + Assert.assertEquals(14, rs.getColumn("id").getInt32()); + Assert.assertTrue(rs.next()); + Assert.assertEquals(16, rs.getColumn("id").getInt32()); + Assert.assertFalse(rs.next()); + } + + @Test + public void copyTableWithSequenceAndDefaultValue() { + SequenceDescription sequenceConfig = SequenceDescription.newBuilder() + .setCache(5L) + .setMaxValue(Long.MAX_VALUE) + .setMinValue(12L) + .setName("custom_sequence") + .setCycle(true) + .setIncrement(5L) + .setStartValue(12L) + .build(); + + TableDescription createTable = TableDescription.newBuilder() + .addNonnullColumn("version", PrimitiveType.Int8) + .addColumn(new TableColumn("id", PrimitiveType.Int32, null, sequenceConfig)) + .addNullableColumn("value", PrimitiveType.Text, PrimitiveValue.newText("123")) + .setPrimaryKeys("version", "id") + .build(); + + ctx.supplyStatus(session -> session.createTable(tablePath(), createTable)).join() + .expectSuccess("cannot create table " + tablePath()); + + DataQueryResult dataQueryResult = ctx.supplyResult(session -> session.executeDataQuery( + "INSERT INTO " + TABLE + " (version) VALUES (1), (1), (1) RETURNING version, id, value;", + TxControl.serializableRw() + )).join().getValue(); + + Assert.assertEquals(1, dataQueryResult.getResultSetCount()); + ResultSetReader rs = dataQueryResult.getResultSet(0); + Assert.assertTrue(rs.next()); + Assert.assertEquals(1, rs.getColumn("version").getInt8()); + Assert.assertEquals(12, rs.getColumn("id").getInt32()); + Assert.assertEquals("123", rs.getColumn("value").getText()); + + Assert.assertTrue(rs.next()); + Assert.assertEquals(1, rs.getColumn("version").getInt8()); + Assert.assertEquals(17, rs.getColumn("id").getInt32()); + Assert.assertEquals("123", rs.getColumn("value").getText()); + + Assert.assertTrue(rs.next()); + Assert.assertEquals(1, rs.getColumn("version").getInt8()); + Assert.assertEquals(22, rs.getColumn("id").getInt32()); + Assert.assertEquals("123", rs.getColumn("value").getText()); + + Assert.assertFalse(rs.next()); + + TableDescription tableDesc = ctx.supplyResult(session -> session.describeTable(tablePath())).join().getValue(); + ctx.supplyStatus(session -> session.dropTable(tablePath())).join().expectSuccess("cannot drop table " + TABLE); + + ctx.supplyStatus(session -> session.createTable(tablePath(), tableDesc)).join() + .expectSuccess("cannot create table " + tablePath()); + + dataQueryResult = ctx.supplyResult(session -> session.executeDataQuery( + "INSERT INTO " + TABLE + " (version) VALUES (1), (1), (1) RETURNING version, id, value;", + TxControl.serializableRw() + )).join().getValue(); + + Assert.assertEquals(1, dataQueryResult.getResultSetCount()); + rs = dataQueryResult.getResultSet(0); + Assert.assertTrue(rs.next()); + Assert.assertEquals(1, rs.getColumn("version").getInt8()); + Assert.assertEquals(12, rs.getColumn("id").getInt32()); + Assert.assertEquals("123", rs.getColumn("value").getText()); + + Assert.assertTrue(rs.next()); + Assert.assertEquals(1, rs.getColumn("version").getInt8()); + Assert.assertEquals(17, rs.getColumn("id").getInt32()); + Assert.assertEquals("123", rs.getColumn("value").getText()); + + Assert.assertTrue(rs.next()); + Assert.assertEquals(1, rs.getColumn("version").getInt8()); + Assert.assertEquals(22, rs.getColumn("id").getInt32()); + Assert.assertEquals("123", rs.getColumn("value").getText()); + + Assert.assertFalse(rs.next()); + } +}