Skip to content

Commit 9cb1867

Browse files
authored
Change DATE type encoding to integer (#2491)
1 parent a6d627e commit 9cb1867

10 files changed

+63
-28
lines changed

core/src/main/java/com/scalar/db/storage/cosmos/ResultInterpreter.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,7 @@ private Column<?> convert(@Nullable Object recordValue, String name, DataType da
9898
return recordValue == null
9999
? DateColumn.ofNull(name)
100100
: DateColumn.of(
101-
name,
102-
TimeRelatedColumnEncodingUtils.decodeDate(((Number) recordValue).longValue()));
101+
name, TimeRelatedColumnEncodingUtils.decodeDate(((Number) recordValue).intValue()));
103102
case TIME:
104103
return recordValue == null
105104
? TimeColumn.ofNull(name)

core/src/main/java/com/scalar/db/storage/dynamo/ResultInterpreter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ private Column<?> convert(@Nullable AttributeValue itemValue, String name, DataT
8181
return isNull
8282
? DateColumn.ofNull(name)
8383
: DateColumn.of(
84-
name, TimeRelatedColumnEncodingUtils.decodeDate(Long.parseLong(itemValue.n())));
84+
name, TimeRelatedColumnEncodingUtils.decodeDate(Integer.parseInt(itemValue.n())));
8585
case TIME:
8686
return isNull
8787
? TimeColumn.ofNull(name)

core/src/main/java/com/scalar/db/storage/dynamo/bytes/BytesUtils.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ public static byte[] toBytes(ByteBuffer src) {
112112
}
113113

114114
static void encodeLong(long value, Order order, ByteBuffer dst) {
115-
dst.put(
116-
mask((byte) ((value >> 56) ^ 0x80), order)); // Flip a sign bit to make it binary comparable
115+
// Flip a sign bit to make it binary comparable
116+
dst.put(mask((byte) ((value >> 56) ^ 0x80), order));
117117
dst.put(mask((byte) (value >> 48), order));
118118
dst.put(mask((byte) (value >> 40), order));
119119
dst.put(mask((byte) (value >> 32), order));
@@ -122,4 +122,12 @@ static void encodeLong(long value, Order order, ByteBuffer dst) {
122122
dst.put(mask((byte) (value >> 8), order));
123123
dst.put(mask((byte) value, order));
124124
}
125+
126+
static void encodeInt(int value, Order order, ByteBuffer dst) {
127+
// Flip a sign bit to make it binary comparable
128+
dst.put(mask((byte) ((value >> 24) ^ 0x80), order));
129+
dst.put(mask((byte) (value >> 16), order));
130+
dst.put(mask((byte) (value >> 8), order));
131+
dst.put(mask((byte) value, order));
132+
}
125133
}

core/src/main/java/com/scalar/db/storage/dynamo/bytes/DateBytesEncoder.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.scalar.db.storage.dynamo.bytes;
22

3-
import static com.scalar.db.storage.dynamo.bytes.BytesUtils.encodeLong;
3+
import static com.scalar.db.storage.dynamo.bytes.BytesUtils.encodeInt;
44

55
import com.scalar.db.api.Scan.Ordering.Order;
66
import com.scalar.db.io.DateColumn;
@@ -17,14 +17,14 @@ public class DateBytesEncoder implements BytesEncoder<DateColumn> {
1717
public int encodedLength(DateColumn column, Order order) {
1818
assert column.getValue().isPresent();
1919

20-
return 8;
20+
return 4;
2121
}
2222

2323
@Override
2424
public void encode(DateColumn column, Order order, ByteBuffer dst) {
2525
assert column.getValue().isPresent();
2626

27-
long value = TimeRelatedColumnEncodingUtils.encode(column);
28-
encodeLong(value, order, dst);
27+
int value = TimeRelatedColumnEncodingUtils.encode(column);
28+
encodeInt(value, order, dst);
2929
}
3030
}

core/src/main/java/com/scalar/db/storage/dynamo/bytes/IntBytesEncoder.java

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.scalar.db.storage.dynamo.bytes;
22

3-
import static com.scalar.db.storage.dynamo.bytes.BytesUtils.mask;
3+
import static com.scalar.db.storage.dynamo.bytes.BytesUtils.encodeInt;
44

55
import com.scalar.db.api.Scan.Ordering.Order;
66
import com.scalar.db.io.IntColumn;
@@ -22,9 +22,6 @@ public void encode(IntColumn column, Order order, ByteBuffer dst) {
2222
assert !column.hasNullValue();
2323

2424
int v = column.getIntValue();
25-
dst.put(mask((byte) ((v >> 24) ^ 0x80), order)); // Flip a sign bit to make it binary comparable
26-
dst.put(mask((byte) (v >> 16), order));
27-
dst.put(mask((byte) (v >> 8), order));
28-
dst.put(mask((byte) v, order));
25+
encodeInt(v, order, dst);
2926
}
3027
}

core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineSqlite.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,9 @@ public String getDataTypeForEngine(DataType scalarDbDataType) {
9595
case BOOLEAN:
9696
return "BOOLEAN";
9797
case INT:
98+
case DATE:
9899
return "INT";
99100
case BIGINT:
100-
case DATE:
101101
case TIME:
102102
case TIMESTAMP:
103103
case TIMESTAMPTZ:
@@ -126,8 +126,8 @@ public int getSqlTypes(DataType dataType) {
126126
case BOOLEAN:
127127
return Types.BOOLEAN;
128128
case INT:
129-
return Types.INTEGER;
130129
case DATE:
130+
return Types.INTEGER;
131131
case TIME:
132132
case TIMESTAMP:
133133
case TIMESTAMPTZ:
@@ -307,7 +307,7 @@ public String tryAddIfNotExistsToCreateIndexSql(String createIndexSql) {
307307
@Override
308308
public DateColumn parseDateColumn(ResultSet resultSet, String columnName) throws SQLException {
309309
return DateColumn.of(
310-
columnName, TimeRelatedColumnEncodingUtils.decodeDate(resultSet.getLong(columnName)));
310+
columnName, TimeRelatedColumnEncodingUtils.decodeDate(resultSet.getInt(columnName)));
311311
}
312312

313313
@Override
@@ -332,7 +332,7 @@ public TimestampTZColumn parseTimestampTZColumn(ResultSet resultSet, String colu
332332
}
333333

334334
@Override
335-
public RdbEngineTimeTypeStrategy<Long, Long, Long, Long> getTimeTypeStrategy() {
335+
public RdbEngineTimeTypeStrategy<Integer, Long, Long, Long> getTimeTypeStrategy() {
336336
return timeTypeEngine;
337337
}
338338
}

core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineTimeTypeSqlite.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
import java.time.LocalTime;
77
import java.time.OffsetDateTime;
88

9-
public class RdbEngineTimeTypeSqlite implements RdbEngineTimeTypeStrategy<Long, Long, Long, Long> {
9+
public class RdbEngineTimeTypeSqlite
10+
implements RdbEngineTimeTypeStrategy<Integer, Long, Long, Long> {
1011

1112
@Override
12-
public Long convert(LocalDate date) {
13+
public Integer convert(LocalDate date) {
1314
return TimeRelatedColumnEncodingUtils.encode(date);
1415
}
1516

core/src/main/java/com/scalar/db/util/TimeRelatedColumnEncodingUtils.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@
1717
public final class TimeRelatedColumnEncodingUtils {
1818
private TimeRelatedColumnEncodingUtils() {}
1919

20-
public static long encode(DateColumn column) {
20+
public static int encode(DateColumn column) {
2121
assert column.getDateValue() != null;
2222
return encode(column.getDateValue());
2323
}
2424

25-
public static long encode(LocalDate date) {
26-
return date.toEpochDay();
25+
public static int encode(LocalDate date) {
26+
return Math.toIntExact(date.toEpochDay());
2727
}
2828

29-
public static LocalDate decodeDate(long epochDay) {
29+
public static LocalDate decodeDate(int epochDay) {
3030
return LocalDate.ofEpochDay(epochDay);
3131
}
3232

core/src/test/java/com/scalar/db/storage/TimeRelatedColumnEncodingUtilsTest.java

+32-2
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,27 @@ public void encodeDate_ShouldWorkProperly() {
2626
DateColumn column = DateColumn.of("date", LocalDate.of(2023, 10, 1));
2727

2828
// Act
29-
long encoded = TimeRelatedColumnEncodingUtils.encode(column);
29+
int encoded = TimeRelatedColumnEncodingUtils.encode(column);
3030

3131
// Assert
3232
assertThat(encoded).isEqualTo(LocalDate.of(2023, 10, 1).toEpochDay());
3333
}
3434

35+
@Test
36+
public void encodeThenDecodeDate_ShouldPreserveDataIntegrity() {
37+
// Arrange
38+
DateColumn min = DateColumn.of("date", DateColumn.MIN_VALUE);
39+
DateColumn max = DateColumn.of("date", DateColumn.MAX_VALUE);
40+
41+
// Act Assert
42+
assertThat(
43+
TimeRelatedColumnEncodingUtils.decodeDate(TimeRelatedColumnEncodingUtils.encode(min)))
44+
.isEqualTo(min.getDateValue());
45+
assertThat(
46+
TimeRelatedColumnEncodingUtils.decodeDate(TimeRelatedColumnEncodingUtils.encode(max)))
47+
.isEqualTo(max.getDateValue());
48+
}
49+
3550
@Test
3651
public void encodeTime_ShouldWorkProperly() {
3752
// Arrange
@@ -44,6 +59,21 @@ public void encodeTime_ShouldWorkProperly() {
4459
assertThat(encoded).isEqualTo(LocalTime.of(12, 34, 56, 123_456_000).toNanoOfDay());
4560
}
4661

62+
@Test
63+
public void encodeThenDecodeTime_ShouldPreserveDataIntegrity() {
64+
// Arrange
65+
TimeColumn min = TimeColumn.of("time", TimeColumn.MIN_VALUE);
66+
TimeColumn max = TimeColumn.of("time", TimeColumn.MAX_VALUE);
67+
68+
// Act Assert
69+
assertThat(
70+
TimeRelatedColumnEncodingUtils.decodeTime(TimeRelatedColumnEncodingUtils.encode(min)))
71+
.isEqualTo(min.getTimeValue());
72+
assertThat(
73+
TimeRelatedColumnEncodingUtils.decodeTime(TimeRelatedColumnEncodingUtils.encode(max)))
74+
.isEqualTo(max.getTimeValue());
75+
}
76+
4777
@Test
4878
public void encodeTimestamp_ShouldWorkProperly() {
4979
// Arrange
@@ -124,7 +154,7 @@ public void encodeTimestampTZ_ShouldWorkProperly() {
124154
public void decodeDate_ShouldWorkProperly() {
125155
// Arrange Act
126156
LocalDate date =
127-
TimeRelatedColumnEncodingUtils.decodeDate(LocalDate.of(2023, 10, 1).toEpochDay());
157+
TimeRelatedColumnEncodingUtils.decodeDate((int) LocalDate.of(2023, 10, 1).toEpochDay());
128158

129159
// Assert
130160
assertThat(date).isEqualTo(LocalDate.of(2023, 10, 1));

core/src/test/java/com/scalar/db/storage/jdbc/JdbcAdminTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ public void createTableInternal_ForOracle_ShouldCreateTableAndIndexes() throws S
550550
public void createTableInternal_ForSqlite_ShouldCreateTableAndIndexes() throws SQLException {
551551
createTableInternal_ForX_CreateTableAndIndexes(
552552
RdbEngine.SQLITE,
553-
"CREATE TABLE \"my_ns$foo_table\"(\"c3\" BOOLEAN,\"c1\" TEXT,\"c4\" BLOB,\"c2\" BIGINT,\"c5\" INT,\"c6\" DOUBLE,\"c7\" FLOAT,\"c8\" BIGINT,\"c9\" BIGINT,\"c10\" BIGINT,\"c11\" BIGINT, PRIMARY KEY (\"c3\",\"c1\",\"c4\"))",
553+
"CREATE TABLE \"my_ns$foo_table\"(\"c3\" BOOLEAN,\"c1\" TEXT,\"c4\" BLOB,\"c2\" BIGINT,\"c5\" INT,\"c6\" DOUBLE,\"c7\" FLOAT,\"c8\" INT,\"c9\" BIGINT,\"c10\" BIGINT,\"c11\" BIGINT, PRIMARY KEY (\"c3\",\"c1\",\"c4\"))",
554554
"CREATE INDEX \"index_my_ns_foo_table_c4\" ON \"my_ns$foo_table\" (\"c4\")",
555555
"CREATE INDEX \"index_my_ns_foo_table_c1\" ON \"my_ns$foo_table\" (\"c1\")");
556556
}
@@ -655,7 +655,7 @@ public void createTableInternal_IfNotExistsForSqlite_ShouldCreateTableAndIndexes
655655
throws SQLException {
656656
createTableInternal_IfNotExistsForX_createTableAndIndexesIfNotExists(
657657
RdbEngine.SQLITE,
658-
"CREATE TABLE IF NOT EXISTS \"my_ns$foo_table\"(\"c3\" BOOLEAN,\"c1\" TEXT,\"c4\" BLOB,\"c2\" BIGINT,\"c5\" INT,\"c6\" DOUBLE,\"c7\" FLOAT,\"c8\" BIGINT,\"c9\" BIGINT,\"c10\" BIGINT,\"c11\" BIGINT, PRIMARY KEY (\"c3\",\"c1\",\"c4\"))",
658+
"CREATE TABLE IF NOT EXISTS \"my_ns$foo_table\"(\"c3\" BOOLEAN,\"c1\" TEXT,\"c4\" BLOB,\"c2\" BIGINT,\"c5\" INT,\"c6\" DOUBLE,\"c7\" FLOAT,\"c8\" INT,\"c9\" BIGINT,\"c10\" BIGINT,\"c11\" BIGINT, PRIMARY KEY (\"c3\",\"c1\",\"c4\"))",
659659
"CREATE INDEX IF NOT EXISTS \"index_my_ns_foo_table_c4\" ON \"my_ns$foo_table\" (\"c4\")",
660660
"CREATE INDEX IF NOT EXISTS \"index_my_ns_foo_table_c1\" ON \"my_ns$foo_table\" (\"c1\")");
661661
}

0 commit comments

Comments
 (0)