diff --git a/table/src/main/java/tech/ydb/table/values/PrimitiveValue.java b/table/src/main/java/tech/ydb/table/values/PrimitiveValue.java index 9465d48ac..c92882b35 100644 --- a/table/src/main/java/tech/ydb/table/values/PrimitiveValue.java +++ b/table/src/main/java/tech/ydb/table/values/PrimitiveValue.java @@ -19,7 +19,6 @@ import com.google.protobuf.UnsafeByteOperations; import tech.ydb.proto.ValueProtos; -import tech.ydb.table.utils.LittleEndian; import tech.ydb.table.values.proto.ProtoValue; @@ -123,10 +122,12 @@ public String getUuidString() { throw new IllegalStateException("expected Uuid, but was " + getClass().getSimpleName()); } + @Deprecated public long getUuidHigh() { throw new IllegalStateException("expected Uuid, but was " + getClass().getSimpleName()); } + @Deprecated public long getUuidLow() { throw new IllegalStateException("expected Uuid, but was " + getClass().getSimpleName()); } @@ -245,16 +246,17 @@ public static PrimitiveValue newJsonDocument(String value) { return value.isEmpty() ? Text.EMPTY_JSON_DOCUMENT : new Text(PrimitiveType.JsonDocument, value); } + @Deprecated public static PrimitiveValue newUuid(long high, long low) { - return new Uuid(high, low); + return ProtoValue.newUuid(high, low); } public static PrimitiveValue newUuid(UUID uuid) { - return new Uuid(uuid); + return ProtoValue.newUuid(uuid); } public static PrimitiveValue newUuid(String uuid) { - return new Uuid(uuid); + return ProtoValue.newUuid(uuid); } public static PrimitiveValue newDate(long daysSinceEpoch) { @@ -1091,112 +1093,6 @@ public ValueProtos.Value toPb() { } } - private static final class Uuid extends PrimitiveValue { - private final long high; - private final long low; - - Uuid(long high, long low) { - this.high = high; - this.low = low; - } - - Uuid(String value) { - String[] components = value.split("-"); - if (components.length != 5) { - throw new IllegalArgumentException("invalid UUID string: " + value); - } - - long timeLow = Long.parseLong(components[0], 16); - long timeMid = Long.parseLong(components[1], 16) << 32; - long timeHighAndVersion = Long.parseLong(components[2], 16) << 48; - this.low = timeLow | timeMid | timeHighAndVersion; - - long lsb = Long.parseLong(components[3], 16) << 48; - lsb |= Long.parseLong(components[4], 16); - this.high = LittleEndian.bswap(lsb); - } - - Uuid(UUID uuid) { - long msb = uuid.getMostSignificantBits(); - long timeLow = (msb & 0xffffffff00000000L) >>> 32; - long timeMid = (msb & 0x00000000ffff0000L) << 16; - long timeHighAndVersion = (msb & 0x000000000000ffffL) << 48; - - this.low = timeLow | timeMid | timeHighAndVersion; - this.high = LittleEndian.bswap(uuid.getLeastSignificantBits()); - } - - @Override - public PrimitiveType getType() { - return PrimitiveType.Uuid; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (o == null || getClass() != o.getClass()) { - return false; - } - - Uuid uuid = (Uuid) o; - return high == uuid.high && low == uuid.low; - } - - @Override - public int hashCode() { - int result = (int) (high ^ (high >>> 32)); - result = 31 * result + (int) (low ^ (low >>> 32)); - return result; - } - - @Override - public String toString() { - return '\"' + getUuidString() + '\"'; - } - - @Override - public String getUuidString() { - long hiBe = LittleEndian.bswap(high); - return - digits(low, 8) + "-" + digits(low >>> 32, 4) + "-" + digits(low >>> 48, 4) + "-" + - digits(hiBe >> 48, 4) + "-" + digits(hiBe, 12); - } - - @Override - public long getUuidHigh() { - return high; - } - - @Override - public long getUuidLow() { - return low; - } - - @Override - public UUID getUuidJdk() { - long timeLow = (low & 0x00000000ffffffffL) << 32; - long timeMid = (low & 0x0000ffff00000000L) >>> 16; - long timeHighAndVersion = (low & 0xffff000000000000L) >>> 48; - - long hiBe = LittleEndian.bswap(high); - return new UUID(timeLow | timeMid | timeHighAndVersion, hiBe); - } - - @Override - public ValueProtos.Value toPb() { - return ProtoValue.fromUuid(high, low); - } - - /** Returns val represented by the specified number of hex digits. */ - private static String digits(long val, int digits) { - long high = 1L << (digits * 4); - return Long.toHexString(high | (val & (high - 1))).substring(1); - } - } - private static final class InstantValue extends PrimitiveValue { private final PrimitiveType type; private final long microsSinceEpoch; diff --git a/table/src/main/java/tech/ydb/table/values/proto/ProtoValue.java b/table/src/main/java/tech/ydb/table/values/proto/ProtoValue.java index a66e9cc3c..b74aa7b64 100644 --- a/table/src/main/java/tech/ydb/table/values/proto/ProtoValue.java +++ b/table/src/main/java/tech/ydb/table/values/proto/ProtoValue.java @@ -36,8 +36,6 @@ import tech.ydb.table.values.VariantType; import tech.ydb.table.values.VoidValue; -import static tech.ydb.table.values.Type.Kind.VOID; - /** * @author Sergey Polovko @@ -787,7 +785,7 @@ private static PrimitiveValue primitiveFromPb(PrimitiveType primitiveType, Value case Yson: return PrimitiveValue.newYson(value.getBytesValue()); case Json: return PrimitiveValue.newJson(value.getTextValue()); case JsonDocument: return PrimitiveValue.newJsonDocument(value.getTextValue()); - case Uuid: return PrimitiveValue.newUuid(value.getHigh128(), value.getLow128()); + case Uuid: return newUuid(value.getHigh128(), value.getLow128()); case Date: return PrimitiveValue.newDate(Integer.toUnsignedLong(value.getUint32Value())); case Datetime: return PrimitiveValue.newDatetime(Integer.toUnsignedLong(value.getUint32Value())); case Timestamp: return PrimitiveValue.newTimestamp(value.getUint64Value()); @@ -806,4 +804,124 @@ public static ValueProtos.TypedValue toTypedValue(Value p) { .setValue(p.toPb()) .build(); } + + public static PrimitiveValue newUuid(long high, long low) { + return new Uuid(high, low); + } + + public static PrimitiveValue newUuid(UUID uuid) { + return new Uuid(uuid); + } + + public static PrimitiveValue newUuid(String uuid) { + return new Uuid(uuid); + } + + private static final class Uuid extends PrimitiveValue { + private final long high; + private final long low; + + Uuid(long high, long low) { + this.high = high; + this.low = low; + } + + Uuid(String value) { + String[] components = value.split("-"); + if (components.length != 5) { + throw new IllegalArgumentException("invalid UUID string: " + value); + } + + long timeLow = Long.parseLong(components[0], 16); + long timeMid = Long.parseLong(components[1], 16) << 32; + long timeHighAndVersion = Long.parseLong(components[2], 16) << 48; + this.low = timeLow | timeMid | timeHighAndVersion; + + long lsb = Long.parseLong(components[3], 16) << 48; + lsb |= Long.parseLong(components[4], 16); + this.high = LittleEndian.bswap(lsb); + } + + Uuid(UUID uuid) { + long msb = uuid.getMostSignificantBits(); + long timeLow = (msb & 0xffffffff00000000L) >>> 32; + long timeMid = (msb & 0x00000000ffff0000L) << 16; + long timeHighAndVersion = (msb & 0x000000000000ffffL) << 48; + + this.low = timeLow | timeMid | timeHighAndVersion; + this.high = LittleEndian.bswap(uuid.getLeastSignificantBits()); + } + + @Override + public PrimitiveType getType() { + return PrimitiveType.Uuid; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + + Uuid uuid = (Uuid) o; + return high == uuid.high && low == uuid.low; + } + + @Override + public int hashCode() { + int result = (int) (high ^ (high >>> 32)); + result = 31 * result + (int) (low ^ (low >>> 32)); + return result; + } + + @Override + public String toString() { + return '\"' + getUuidString() + '\"'; + } + + @Override + public String getUuidString() { + long hiBe = LittleEndian.bswap(high); + return + digits(low, 8) + "-" + digits(low >>> 32, 4) + "-" + digits(low >>> 48, 4) + "-" + + digits(hiBe >> 48, 4) + "-" + digits(hiBe, 12); + } + + @Override + @SuppressWarnings("deprecation") + public long getUuidHigh() { + return high; + } + + @Override + @SuppressWarnings("deprecation") + public long getUuidLow() { + return low; + } + + @Override + public UUID getUuidJdk() { + long timeLow = (low & 0x00000000ffffffffL) << 32; + long timeMid = (low & 0x0000ffff00000000L) >>> 16; + long timeHighAndVersion = (low & 0xffff000000000000L) >>> 48; + + long hiBe = LittleEndian.bswap(high); + return new UUID(timeLow | timeMid | timeHighAndVersion, hiBe); + } + + @Override + public ValueProtos.Value toPb() { + return ProtoValue.fromUuid(high, low); + } + + /** Returns val represented by the specified number of hex digits. */ + private static String digits(long val, int digits) { + long high = 1L << (digits * 4); + return Long.toHexString(high | (val & (high - 1))).substring(1); + } + } } diff --git a/table/src/test/java/tech/ydb/table/integration/NullReadTest.java b/table/src/test/java/tech/ydb/table/integration/NullReadTest.java deleted file mode 100644 index 74e8aaef8..000000000 --- a/table/src/test/java/tech/ydb/table/integration/NullReadTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package tech.ydb.table.integration; - -import org.junit.Assert; -import org.junit.ClassRule; -import org.junit.Test; - -import tech.ydb.table.SessionRetryContext; -import tech.ydb.table.impl.SimpleTableClient; -import tech.ydb.table.query.DataQueryResult; -import tech.ydb.table.result.ResultSetReader; -import tech.ydb.table.result.ValueReader; -import tech.ydb.table.rpc.grpc.GrpcTableRpc; -import tech.ydb.table.transaction.TxControl; -import tech.ydb.table.values.NullType; -import tech.ydb.table.values.NullValue; -import tech.ydb.table.values.PrimitiveType; -import tech.ydb.test.junit4.GrpcTransportRule; - -/** - * - * @author Aleksandr Gorshenin - */ -public class NullReadTest { - @ClassRule - public static final GrpcTransportRule YDB_TRANSPORT = new GrpcTransportRule(); - private static final SessionRetryContext CTX = SessionRetryContext.create(SimpleTableClient.newClient( - GrpcTableRpc.useTransport(YDB_TRANSPORT) - ).build()).build(); - - @Test - public void nullReadTest() { - DataQueryResult result = CTX.supplyResult( - s -> s.executeDataQuery("SELECT '1' AS p1, 123 AS p2, NULL AS p3", TxControl.serializableRw()) - ).join().getValue(); - - Assert.assertEquals(1, result.getResultSetCount()); - - ResultSetReader rs = result.getResultSet(0); - Assert.assertTrue(rs.next()); - - ValueReader p1 = rs.getColumn("p1"); - ValueReader p2 = rs.getColumn("p2"); - ValueReader p3 = rs.getColumn("p3"); - - Assert.assertNotNull(p1); - Assert.assertNotNull(p2); - Assert.assertNotNull(p3); - - Assert.assertSame(PrimitiveType.Bytes, p1.getType()); - Assert.assertSame(PrimitiveType.Int32, p2.getType()); - Assert.assertSame(NullType.of(), p3.getType()); - - Assert.assertArrayEquals(new byte[] { '1' }, p1.getBytes()); - Assert.assertEquals(123, p2.getInt32()); - Assert.assertSame(NullValue.of(), p3.getValue()); - } -} diff --git a/table/src/test/java/tech/ydb/table/integration/ValuesReadTest.java b/table/src/test/java/tech/ydb/table/integration/ValuesReadTest.java new file mode 100644 index 000000000..08a13ccf7 --- /dev/null +++ b/table/src/test/java/tech/ydb/table/integration/ValuesReadTest.java @@ -0,0 +1,104 @@ +package tech.ydb.table.integration; + +import java.util.UUID; + +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; + +import tech.ydb.table.SessionRetryContext; +import tech.ydb.table.impl.SimpleTableClient; +import tech.ydb.table.query.DataQueryResult; +import tech.ydb.table.result.ResultSetReader; +import tech.ydb.table.result.ValueReader; +import tech.ydb.table.rpc.grpc.GrpcTableRpc; +import tech.ydb.table.transaction.TxControl; +import tech.ydb.table.values.NullType; +import tech.ydb.table.values.NullValue; +import tech.ydb.table.values.PrimitiveType; +import tech.ydb.table.values.PrimitiveValue; +import tech.ydb.table.values.Type; +import tech.ydb.test.junit4.GrpcTransportRule; + +/** + * + * @author Aleksandr Gorshenin + */ +public class ValuesReadTest { + @ClassRule + public static final GrpcTransportRule YDB_TRANSPORT = new GrpcTransportRule(); + private static final SessionRetryContext CTX = SessionRetryContext.create(SimpleTableClient.newClient( + GrpcTableRpc.useTransport(YDB_TRANSPORT) + ).build()).build(); + + @Test + public void nullReadTest() { + DataQueryResult result = CTX.supplyResult( + s -> s.executeDataQuery("SELECT '1' AS p1, 123 AS p2, NULL AS p3", TxControl.serializableRw()) + ).join().getValue(); + + Assert.assertEquals(1, result.getResultSetCount()); + + ResultSetReader rs = result.getResultSet(0); + Assert.assertTrue(rs.next()); + + ValueReader p1 = rs.getColumn("p1"); + ValueReader p2 = rs.getColumn("p2"); + ValueReader p3 = rs.getColumn("p3"); + + Assert.assertNotNull(p1); + Assert.assertNotNull(p2); + Assert.assertNotNull(p3); + + Assert.assertSame(PrimitiveType.Bytes, p1.getType()); + Assert.assertSame(PrimitiveType.Int32, p2.getType()); + Assert.assertSame(NullType.of(), p3.getType()); + + Assert.assertArrayEquals(new byte[] { '1' }, p1.getBytes()); + Assert.assertEquals(123, p2.getInt32()); + Assert.assertSame(NullValue.of(), p3.getValue()); + } + + @Test + @SuppressWarnings("deprecation") + public void uuidReadTest() { + DataQueryResult result = CTX.supplyResult( + s -> s.executeDataQuery("SELECT " + + "CAST('123e4567-e89b-12d3-a456-426614174000' AS UUID) AS p1," + + "CAST('2d9e498b-b746-9cfb-084d-de4e1cb4736e' AS UUID) AS p2;", + TxControl.serializableRw() + ) + ).join().getValue(); + + Assert.assertEquals(1, result.getResultSetCount()); + + ResultSetReader rs = result.getResultSet(0); + Assert.assertTrue(rs.next()); + + ValueReader p1 = rs.getColumn("p1"); + Assert.assertNotNull(p1); + + Assert.assertSame(Type.Kind.OPTIONAL, p1.getType().getKind()); + Assert.assertSame(PrimitiveType.Uuid, p1.getType().unwrapOptional()); + + Assert.assertEquals(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"), p1.getUuid()); + + PrimitiveValue v1 = p1.getValue().asOptional().get().asData(); + Assert.assertEquals("123e4567-e89b-12d3-a456-426614174000", v1.getUuidString()); + Assert.assertEquals(0x12d3e89b123e4567L, v1.getUuidLow()); + Assert.assertEquals(0x00401714664256a4L, v1.getUuidHigh()); + + ValueReader p2 = rs.getColumn("p2"); + Assert.assertNotNull(p2); + + Assert.assertSame(Type.Kind.OPTIONAL, p2.getType().getKind()); + Assert.assertSame(PrimitiveType.Uuid, p2.getType().unwrapOptional()); + + Assert.assertEquals(UUID.fromString("2d9e498b-b746-9cfb-084d-de4e1cb4736e"), p2.getUuid()); + + PrimitiveValue v2 = p2.getValue().asOptional().get().asData(); + Assert.assertEquals("2d9e498b-b746-9cfb-084d-de4e1cb4736e", v2.getUuidString()); + Assert.assertEquals(0x9cfbb7462d9e498bL, v2.getUuidLow()); + Assert.assertEquals(0x6e73b41c4ede4d08L, v2.getUuidHigh()); + } +} diff --git a/table/src/test/java/tech/ydb/table/values/PrimitiveValueTest.java b/table/src/test/java/tech/ydb/table/values/PrimitiveValueTest.java index e0c3732e6..d435f0e95 100644 --- a/table/src/test/java/tech/ydb/table/values/PrimitiveValueTest.java +++ b/table/src/test/java/tech/ydb/table/values/PrimitiveValueTest.java @@ -443,13 +443,10 @@ public void uuid() { Consumer doTest = (v) -> { Assert.assertEquals(PrimitiveValue.newUuid(uuid), v); Assert.assertEquals(PrimitiveValue.newUuid(uuidStr), v); - Assert.assertEquals(PrimitiveValue.newUuid(high, low), v); Assert.assertNotEquals(PrimitiveValue.newUuid(UUID.randomUUID()), v); Assert.assertEquals("\"00112233-4455-6677-8899-aabbccddeeff\"", v.toString()); Assert.assertEquals("00112233-4455-6677-8899-aabbccddeeff", v.getUuidString()); - Assert.assertEquals(v.getUuidHigh(), high); - Assert.assertEquals(v.getUuidLow(), low); Assert.assertEquals(v.getUuidJdk(), uuid); ValueProtos.Value vPb = v.toPb(); @@ -460,7 +457,6 @@ public void uuid() { doTest.accept(PrimitiveValue.newUuid(uuid)); doTest.accept(PrimitiveValue.newUuid(uuidStr)); - doTest.accept(PrimitiveValue.newUuid(high, low)); } @Test diff --git a/table/src/test/java/tech/ydb/table/values/proto/ProtoValueTest.java b/table/src/test/java/tech/ydb/table/values/proto/ProtoValueTest.java index caae33dbf..ae60bc6b9 100644 --- a/table/src/test/java/tech/ydb/table/values/proto/ProtoValueTest.java +++ b/table/src/test/java/tech/ydb/table/values/proto/ProtoValueTest.java @@ -3,11 +3,14 @@ import java.time.Month; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.util.UUID; import java.util.concurrent.TimeUnit; import org.junit.Assert; import org.junit.Test; +import tech.ydb.table.values.PrimitiveValue; + /** @@ -59,4 +62,23 @@ public void tzTimestamp() { Assert.assertEquals(ZoneId.of("America/Chicago"), dateTime.getZone()); Assert.assertEquals("2018-10-22T01:23:45.678901-05:00[America/Chicago]", dateTime.toString()); } + + @Test + @SuppressWarnings("deprecation") + public void uuid() { + String uuid = "123e4567-e89b-12d3-a456-426614174000"; + long low = 0x12d3e89b123e4567L, high = 0x00401714664256a4L; + + PrimitiveValue u1 = ProtoValue.newUuid(uuid); + PrimitiveValue u2 = ProtoValue.newUuid(UUID.fromString(uuid)); + PrimitiveValue u3 = ProtoValue.newUuid(high, low); + + Assert.assertEquals(u1, u2); + Assert.assertEquals(u1, u3); + + Assert.assertEquals(uuid, u1.getUuidString()); + Assert.assertEquals(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"), u1.getUuidJdk()); + Assert.assertEquals(low, u1.getUuidLow()); + Assert.assertEquals(high, u1.getUuidHigh()); + } }