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