You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by sa...@apache.org on 2021/11/05 08:26:05 UTC
[cassandra] branch cassandra-4.0 updated: Backward compatibility
for CQLSSTableWriter Date fields
This is an automated email from the ASF dual-hosted git repository.
samt pushed a commit to branch cassandra-4.0
in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/cassandra-4.0 by this push:
new c961310 Backward compatibility for CQLSSTableWriter Date fields
c961310 is described below
commit c96131035b309dcc8d716fb0a57ff9d46a8c5042
Author: Doug Rohrer <dr...@apple.com>
AuthorDate: Wed Nov 3 15:50:54 2021 -0500
Backward compatibility for CQLSSTableWriter Date fields
Patch by Doug Rohrer; reviewed by Brandon Williams and Sam Tunnicliffe
for CASSANDRA-17117
---
CHANGES.txt | 1 +
.../apache/cassandra/cql3/UntypedResultSet.java | 4 ++
.../cassandra/cql3/functions/types/LocalDate.java | 6 +--
.../cassandra/io/sstable/CQLSSTableWriter.java | 20 +++++++---
.../cassandra/io/sstable/CQLSSTableWriterTest.java | 43 ++++++++++++++++++++++
5 files changed, 66 insertions(+), 8 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index 2093f0c..3f6bacd 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
4.0.2
+ * Add backward compatibility for CQLSSTableWriter Date fields (CASSANDRA-17117)
* Push initial client connection messages to trace (CASSANDRA-17038)
* Correct the internode message timestamp if sending node has wrapped (CASSANDRA-16997)
* Avoid race causing us to return null in RangesAtEndpoint (CASSANDRA-16965)
diff --git a/src/java/org/apache/cassandra/cql3/UntypedResultSet.java b/src/java/org/apache/cassandra/cql3/UntypedResultSet.java
index f4ac99f..169ec8d 100644
--- a/src/java/org/apache/cassandra/cql3/UntypedResultSet.java
+++ b/src/java/org/apache/cassandra/cql3/UntypedResultSet.java
@@ -24,6 +24,8 @@ import java.util.*;
import com.google.common.annotations.VisibleForTesting;
+import com.datastax.driver.core.CodecUtils;
+import org.apache.cassandra.cql3.functions.types.LocalDate;
import org.apache.cassandra.schema.ColumnMetadata;
import org.apache.cassandra.cql3.statements.SelectStatement;
import org.apache.cassandra.db.*;
@@ -394,6 +396,8 @@ public abstract class UntypedResultSet implements Iterable<UntypedResultSet.Row>
return TimestampType.instance.compose(data.get(column));
}
+ public LocalDate getDate(String column) { return LocalDate.fromDaysSinceEpoch(CodecUtils.fromUnsignedToSignedInt(data.get(column).getInt()));}
+
public long getLong(String column)
{
return LongType.instance.compose(data.get(column));
diff --git a/src/java/org/apache/cassandra/cql3/functions/types/LocalDate.java b/src/java/org/apache/cassandra/cql3/functions/types/LocalDate.java
index dead6ec..a8b4236 100644
--- a/src/java/org/apache/cassandra/cql3/functions/types/LocalDate.java
+++ b/src/java/org/apache/cassandra/cql3/functions/types/LocalDate.java
@@ -62,7 +62,7 @@ public final class LocalDate
* @param daysSinceEpoch the number of days.
* @return the new instance.
*/
- static LocalDate fromDaysSinceEpoch(int daysSinceEpoch)
+ public static LocalDate fromDaysSinceEpoch(int daysSinceEpoch)
{
return new LocalDate(daysSinceEpoch);
}
@@ -76,7 +76,7 @@ public final class LocalDate
* @throws IllegalArgumentException if the date is not in the range [-5877641-06-23;
* 5881580-07-11].
*/
- static LocalDate fromMillisSinceEpoch(long millisSinceEpoch)
+ public static LocalDate fromMillisSinceEpoch(long millisSinceEpoch)
throws IllegalArgumentException
{
long daysSinceEpoch = TimeUnit.MILLISECONDS.toDays(millisSinceEpoch);
@@ -92,7 +92,7 @@ public final class LocalDate
*
* @return the number of days.
*/
- int getDaysSinceEpoch()
+ public int getDaysSinceEpoch()
{
return daysSinceEpoch;
}
diff --git a/src/java/org/apache/cassandra/io/sstable/CQLSSTableWriter.java b/src/java/org/apache/cassandra/io/sstable/CQLSSTableWriter.java
index 8ac0fdf..0b8dbae 100644
--- a/src/java/org/apache/cassandra/io/sstable/CQLSSTableWriter.java
+++ b/src/java/org/apache/cassandra/io/sstable/CQLSSTableWriter.java
@@ -44,6 +44,7 @@ import org.apache.cassandra.cql3.statements.ModificationStatement;
import org.apache.cassandra.cql3.statements.UpdateStatement;
import org.apache.cassandra.db.Clustering;
import org.apache.cassandra.db.SystemKeyspace;
+import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.dht.IPartitioner;
import org.apache.cassandra.dht.Murmur3Partitioner;
import org.apache.cassandra.exceptions.InvalidRequestException;
@@ -167,7 +168,7 @@ public class CQLSSTableWriter implements Closeable
for (int i = 0; i < size; i++)
{
Object value = values.get(i);
- rawValues.add(serialize(value, typeCodecs.get(i)));
+ rawValues.add(serialize(value, typeCodecs.get(i), boundNames.get(i)));
}
return rawAddRow(rawValues);
@@ -202,7 +203,7 @@ public class CQLSSTableWriter implements Closeable
{
ColumnSpecification spec = boundNames.get(i);
Object value = values.get(spec.name.toString());
- rawValues.add(serialize(value, typeCodecs.get(i)));
+ rawValues.add(serialize(value, typeCodecs.get(i), boundNames.get(i)));
}
return rawAddRow(rawValues);
}
@@ -287,7 +288,7 @@ public class CQLSSTableWriter implements Closeable
{
int size = Math.min(values.size(), boundNames.size());
List<ByteBuffer> rawValues = new ArrayList<>(size);
- for (int i = 0; i < size; i++)
+ for (int i = 0; i < size; i++)
{
ColumnSpecification spec = boundNames.get(i);
rawValues.add(values.get(spec.name.toString()));
@@ -320,12 +321,21 @@ public class CQLSSTableWriter implements Closeable
writer.close();
}
- private ByteBuffer serialize(Object value, TypeCodec codec)
+ private ByteBuffer serialize(Object value, TypeCodec codec, ColumnSpecification columnSpecification)
{
if (value == null || value == UNSET_VALUE)
return (ByteBuffer) value;
- return codec.serialize(value, ProtocolVersion.CURRENT);
+ try
+ {
+ return codec.serialize(value, ProtocolVersion.CURRENT);
+ }
+ catch (ClassCastException cce)
+ {
+ // For backwards-compatibility with consumers that may be passing
+ // an Integer for a Date field, for example.
+ return ((AbstractType)columnSpecification.type).decompose(value);
+ }
}
/**
* A Builder for a CQLSSTableWriter object.
diff --git a/test/unit/org/apache/cassandra/io/sstable/CQLSSTableWriterTest.java b/test/unit/org/apache/cassandra/io/sstable/CQLSSTableWriterTest.java
index 31c588b..dd7085a 100644
--- a/test/unit/org/apache/cassandra/io/sstable/CQLSSTableWriterTest.java
+++ b/test/unit/org/apache/cassandra/io/sstable/CQLSSTableWriterTest.java
@@ -24,6 +24,9 @@ import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -43,10 +46,12 @@ import org.apache.cassandra.cql3.functions.UDHelper;
import org.apache.cassandra.cql3.functions.types.*;
import org.apache.cassandra.db.Keyspace;
import org.apache.cassandra.db.commitlog.CommitLog;
+import org.apache.cassandra.db.rows.Row;
import org.apache.cassandra.dht.*;
import org.apache.cassandra.exceptions.*;
import org.apache.cassandra.schema.Schema;
import org.apache.cassandra.schema.TableMetadataRef;
+import org.apache.cassandra.serializers.SimpleDateSerializer;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.utils.*;
@@ -634,6 +639,44 @@ public class CQLSSTableWriterTest
assertEquals(100, resultSet.size());
}
+ @Test
+ public void testDateType() throws Exception
+ {
+ // Test to make sure we can write to `date` fields in both old and new formats
+ String schema = "CREATE TABLE " + qualifiedTable + " ("
+ + " k int,"
+ + " c date,"
+ + " PRIMARY KEY (k)"
+ + ")";
+ String insert = "INSERT INTO " + qualifiedTable + " (k, c) VALUES (?, ?)";
+ CQLSSTableWriter writer = CQLSSTableWriter.builder()
+ .inDirectory(dataDir)
+ .forTable(schema)
+ .using(insert)
+ .withBufferSizeInMB(1)
+ .build();
+
+ final int ID_OFFSET = 1000;
+ for (int i = 0; i < 100 ; i++) {
+ // Use old-style integer as date to test backwards-compatibility
+ writer.addRow(i, i - Integer.MIN_VALUE); // old-style raw integer needs to be offset
+ // Use new-style `LocalDate` for date value.
+ writer.addRow(i + ID_OFFSET, LocalDate.fromDaysSinceEpoch(i));
+ }
+ writer.close();
+ loadSSTables(dataDir, keyspace);
+
+ UntypedResultSet rs = QueryProcessor.executeInternal("SELECT * FROM " + qualifiedTable + ";");
+ assertEquals(200, rs.size());
+ Map<Integer, LocalDate> map = StreamSupport.stream(rs.spliterator(), false)
+ .collect(Collectors.toMap( r -> r.getInt("k"), r -> r.getDate("c")));
+ for (int i = 0; i < 100; i++) {
+ final LocalDate expected = LocalDate.fromDaysSinceEpoch(i);
+ assertEquals(expected, map.get(i + ID_OFFSET));
+ assertEquals(expected, map.get(i));
+ }
+ }
+
private static void loadSSTables(File dataDir, String ks) throws ExecutionException, InterruptedException
{
SSTableLoader loader = new SSTableLoader(dataDir, new SSTableLoader.Client()
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org