This is an automated email from the ASF dual-hosted git repository.

adelapena pushed a commit to branch cassandra-3.11
in repository https://gitbox.apache.org/repos/asf/cassandra.git

commit 0e1d068d9237de39b53992522eba4b40afb0e72b
Merge: 01ebd9936f ffc4c89c3d
Author: Andrés de la Peña <a.penya.gar...@gmail.com>
AuthorDate: Fri May 20 11:43:56 2022 +0100

    Merge branch 'cassandra-3.0' into cassandra-3.11

 CHANGES.txt                                        |   1 +
 src/java/org/apache/cassandra/cql3/Maps.java       |  11 +-
 src/java/org/apache/cassandra/cql3/Sets.java       |   2 +-
 test/unit/org/apache/cassandra/cql3/CQLTester.java |  29 +++-
 .../apache/cassandra/cql3/ColumnConditionTest.java |   2 +-
 .../cql3/validation/entities/CollectionsTest.java  |  74 +++++++++
 .../cassandra/io/sstable/CQLSSTableWriterTest.java | 171 +++++++++++++++++++++
 7 files changed, 282 insertions(+), 8 deletions(-)

diff --cc CHANGES.txt
index 689fbfd2ba,c49c33224f..d796eb9449
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,5 -1,5 +1,6 @@@
 -3.0.28
 +3.11.14
 +Merged from 3.0:
+  * Fix issue where frozen maps may not be serialized in the correct order 
(CASSANDRA-17623)
   * Suppress CVE-2022-24823 (CASSANDRA-17633)
   * fsync TOC and digest files (CASSANDRA-10709)
  
diff --cc test/unit/org/apache/cassandra/cql3/CQLTester.java
index 705fad8f1f,fe8ed5b9c3..996cfc8d5e
--- a/test/unit/org/apache/cassandra/cql3/CQLTester.java
+++ b/test/unit/org/apache/cassandra/cql3/CQLTester.java
@@@ -31,7 -31,10 +31,9 @@@ import java.util.concurrent.atomic.Atom
  import java.util.stream.Collectors;
  
  import com.google.common.base.Objects;
 -import com.google.common.collect.ImmutableList;
  import com.google.common.collect.ImmutableSet;
+ import com.google.common.collect.Iterables;
+ 
  import org.junit.*;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
@@@ -801,7 -797,11 +803,11 @@@ public abstract class CQLTeste
          return Schema.instance.getCFMetaData(KEYSPACE, currentTable());
      }
  
+     protected com.datastax.driver.core.ResultSet executeNet(String query, 
Object... values) throws Throwable
+     {
+         return sessionNet().execute(formatQuery(query), values);
+     }
 -    protected com.datastax.driver.core.ResultSet executeNet(int 
protocolVersion, String query, Object... values) throws Throwable
 +    protected com.datastax.driver.core.ResultSet executeNet(ProtocolVersion 
protocolVersion, String query, Object... values) throws Throwable
      {
          return sessionNet(protocolVersion).execute(formatQuery(query), 
values);
      }
@@@ -952,6 -942,18 +958,13 @@@
                                          rows.length>i ? "less" : "more", 
rows.length, i, protocolVersion), i == rows.length);
      }
  
 -    protected void assertRowsNet(ResultSet result, Object[]... rows)
 -    {
 -        assertRowsNet(PROTOCOL_VERSIONS.get(PROTOCOL_VERSIONS.size() - 1), 
result, rows);
 -    }
 -
+     protected void assertRowCountNet(ResultSet r1, int expectedCount)
+     {
+         Assert.assertFalse("Received a null resultset when expected count was 
> 0", expectedCount > 0 && r1 == null);
+         int actualRowCount = Iterables.size(r1);
+         Assert.assertEquals(String.format("expected %d rows but received %d", 
expectedCount, actualRowCount), expectedCount, actualRowCount);
+     }
+ 
      public static void assertRows(UntypedResultSet result, Object[]... rows)
      {
          if (result == null)
diff --cc test/unit/org/apache/cassandra/io/sstable/CQLSSTableWriterTest.java
index dbeefbb7da,f66b66f173..57910fbf6f
--- a/test/unit/org/apache/cassandra/io/sstable/CQLSSTableWriterTest.java
+++ b/test/unit/org/apache/cassandra/io/sstable/CQLSSTableWriterTest.java
@@@ -19,13 -19,17 +19,15 @@@ package org.apache.cassandra.io.sstable
  
  import java.io.File;
  import java.io.FilenameFilter;
 +import java.io.IOException;
  import java.nio.ByteBuffer;
 -import java.util.Arrays;
 -import java.util.Iterator;
 -import java.util.LinkedHashMap;
 -import java.util.LinkedHashSet;
 -import java.util.Map;
 -import java.util.UUID;
 +import java.util.*;
  import java.util.concurrent.ExecutionException;
 +import java.util.concurrent.atomic.AtomicInteger;
+ import java.util.stream.Collectors;
+ import java.util.stream.StreamSupport;
  
 +import com.google.common.collect.ImmutableList;
  import com.google.common.collect.ImmutableMap;
  import com.google.common.io.Files;
  
@@@ -35,21 -37,22 +37,23 @@@ import org.junit.Before
  import org.junit.BeforeClass;
  import org.junit.Test;
  
+ import com.datastax.driver.core.utils.UUIDs;
  import org.apache.cassandra.SchemaLoader;
  import org.apache.cassandra.Util;
 -import org.apache.cassandra.config.CFMetaData;
 -import org.apache.cassandra.config.Config;
 -import org.apache.cassandra.config.DatabaseDescriptor;
 -import org.apache.cassandra.config.Schema;
 -import org.apache.cassandra.cql3.QueryProcessor;
 -import org.apache.cassandra.cql3.UntypedResultSet;
 +import org.apache.cassandra.config.*;
 +import org.apache.cassandra.cql3.*;
 +import org.apache.cassandra.cql3.functions.UDHelper;
  import org.apache.cassandra.db.Keyspace;
+ import org.apache.cassandra.db.marshal.UTF8Type;
  import org.apache.cassandra.dht.*;
 +import org.apache.cassandra.exceptions.*;
  import org.apache.cassandra.service.StorageService;
 -import org.apache.cassandra.utils.ByteBufferUtil;
 -import org.apache.cassandra.utils.FBUtilities;
 -import org.apache.cassandra.utils.OutputHandler;
 +import org.apache.cassandra.utils.*;
 +import com.datastax.driver.core.DataType;
 +import com.datastax.driver.core.ProtocolVersion;
 +import com.datastax.driver.core.TypeCodec;
 +import com.datastax.driver.core.UDTValue;
 +import com.datastax.driver.core.UserType;
  
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertFalse;
@@@ -607,38 -330,266 +612,204 @@@ public class CQLSSTableWriterTes
          assertFalse(iter.hasNext());
      }
  
 -    private static final int NUMBER_WRITES_IN_RUNNABLE = 10;
 -    private class WriterThread extends Thread
 -    {
 -        private final File dataDir;
 -        private final int id;
 -        public volatile Exception exception;
 -
 -        public WriterThread(File dataDir, int id)
 -        {
 -            this.dataDir = dataDir;
 -            this.id = id;
 -        }
 -
 -        @Override
 -        public void run()
 -        {
 -            String schema = "CREATE TABLE cql_keyspace2.table2 ("
 -                    + "  k int,"
 -                    + "  v int,"
 -                    + "  PRIMARY KEY (k, v)"
 -                    + ")";
 -            String insert = "INSERT INTO cql_keyspace2.table2 (k, v) VALUES 
(?, ?)";
 -            CQLSSTableWriter writer = CQLSSTableWriter.builder()
 -                    .inDirectory(dataDir)
 -                    .forTable(schema)
 -                    .using(insert).build();
 -
 -            try
 -            {
 -                for (int i = 0; i < NUMBER_WRITES_IN_RUNNABLE; i++)
 -                {
 -                    writer.addRow(id, i);
 -                }
 -                writer.close();
 -            }
 -            catch (Exception e)
 -            {
 -                exception = e;
 -            }
 -        }
 -    }
 -
      @Test
 -    public void testConcurrentWriters() throws Exception
 +    public void testWriteWithNestedTupleUdt() throws Exception
      {
 -        final String KS = "cql_keyspace2";
 -        final String TABLE = "table2";
 -
 -        File tempdir = Files.createTempDir();
 -        File dataDir = new File(tempdir.getAbsolutePath() + File.separator + 
KS + File.separator + TABLE);
 -        assert dataDir.mkdirs();
 +        // Check the writer does not throw "InvalidRequestException: 
Non-frozen tuples are not allowed inside collections: list<tuple<int, int>>"
 +        // See CASSANDRA-15857
 +        final String schema = "CREATE TABLE " + qualifiedTable + " ("
 +                              + "  k int,"
 +                              + "  v1 frozen<nested_type>,"
 +                              + "  PRIMARY KEY (k)"
 +                              + ")";
  
 -        WriterThread[] threads = new WriterThread[5];
 -        for (int i = 0; i < threads.length; i++)
 -        {
 -            WriterThread thread = new WriterThread(dataDir, i);
 -            threads[i] = thread;
 -            thread.start();
 -        }
 +        CQLSSTableWriter writer = CQLSSTableWriter.builder()
 +                                                  .inDirectory(dataDir)
 +                                                  .withType("CREATE TYPE " + 
keyspace + ".nested_type (a list<tuple<int, int>>)")
 +                                                  .forTable(schema)
 +                                                  .using("INSERT INTO " + 
qualifiedTable + " (k, v1) " +
 +                                                         "VALUES (?, 
?)").build();
  
 -        for (WriterThread thread : threads)
 +        UserType nestedType = writer.getUDType("nested_type");
 +        for (int i = 0; i < 100; i++)
          {
 -            thread.join();
 -            assert !thread.isAlive() : "Thread should be dead by now";
 -            if (thread.exception != null)
 -            {
 -                throw thread.exception;
 -            }
 +            writer.addRow(i, nestedType.newValue()
 +                                       .setList("a", 
Collections.emptyList()));
          }
  
 -        loadSSTables(dataDir, KS);
 +        writer.close();
 +        loadSSTables(dataDir, keyspace);
  
 -        UntypedResultSet rs = QueryProcessor.executeInternal("SELECT * FROM 
cql_keyspace2.table2;");
 -        assertEquals(threads.length * NUMBER_WRITES_IN_RUNNABLE, rs.size());
 +        UntypedResultSet resultSet = QueryProcessor.executeInternal("SELECT * 
FROM " + qualifiedTable);
 +        assertEquals(100, resultSet.size());
      }
  
+     @Test
+     public void testFrozenMapType() throws Exception
+     {
 -        final String KS = "cql_keyspace3";
 -        final String TABLE = "table3";
 -        final String qualifiedTable = KS + "." + TABLE;
 -        File tempdir = Files.createTempDir();
 -        File dataDir = new File(tempdir.getAbsolutePath() + File.separator + 
KS + File.separator + TABLE);
 -        assert dataDir.mkdirs();
+         // Test to make sure we can write to `date` fields in both old and 
new formats
+         String schema = "CREATE TABLE " + qualifiedTable + " ("
+                         + "  k text,"
+                         + "  c frozen<map<text, text>>,"
+                         + "  PRIMARY KEY (k, c)"
+                         + ")";
+         String insert = "INSERT INTO " + qualifiedTable + " (k, c) VALUES (?, 
?)";
+         CQLSSTableWriter writer = CQLSSTableWriter.builder()
+                                                   .inDirectory(dataDir)
+                                                   .forTable(schema)
+                                                   .using(insert)
+                                                   .withBufferSizeInMB(1)
+                                                   .build();
+         for (int i = 0; i < 100; i++)
+         {
+             LinkedHashMap<String, String> map = new LinkedHashMap<>();
+             map.put("a_key", "av" + i);
+             map.put("b_key", "zv" + i);
+             writer.addRow(String.valueOf(i), map);
+         }
+         for (int i = 100; i < 200; i++)
+         {
+             LinkedHashMap<String, String> map = new LinkedHashMap<>();
+             map.put("b_key", "zv" + i);
+             map.put("a_key", "av" + i);
+             writer.addRow(String.valueOf(i), map);
+         }
+         writer.close();
 -        loadSSTables(dataDir, KS);
++        loadSSTables(dataDir, keyspace);
+ 
+         UntypedResultSet rs = QueryProcessor.executeInternal("SELECT * FROM " 
+ qualifiedTable + ";");
+         assertEquals(200, rs.size());
+         Map<String, Map<String, String>> map = 
StreamSupport.stream(rs.spliterator(), false)
+                                                             
.collect(Collectors.toMap(r -> r.getString("k"), r -> r.getFrozenMap("c", 
UTF8Type.instance, UTF8Type.instance)));
+         for (int i = 0; i < 200; i++)
+         {
+             final String expectedKey = String.valueOf(i);
+             assertTrue(map.containsKey(expectedKey));
+             Map<String, String> innerMap = map.get(expectedKey);
+             assertTrue(innerMap.containsKey("a_key"));
+             assertEquals(innerMap.get("a_key"), "av" + i);
+             assertTrue(innerMap.containsKey("b_key"));
+             assertEquals(innerMap.get("b_key"), "zv" + i);
+         }
+ 
+         // Make sure we can filter with map values regardless of which order 
we put the keys in
+         UntypedResultSet filtered;
+         filtered = QueryProcessor.executeInternal("SELECT * FROM " + 
qualifiedTable + " where k='0' and c={'a_key': 'av0', 'b_key': 'zv0'};");
+         assertEquals(1, filtered.size());
+         filtered = QueryProcessor.executeInternal("SELECT * FROM " + 
qualifiedTable + " where k='0' and c={'b_key': 'zv0', 'a_key': 'av0'};");
+         assertEquals(1, filtered.size());
+         filtered = QueryProcessor.executeInternal("SELECT * FROM " + 
qualifiedTable + " where k='100' and c={'b_key': 'zv100', 'a_key': 'av100'};");
+         assertEquals(1, filtered.size());
+         filtered = QueryProcessor.executeInternal("SELECT * FROM " + 
qualifiedTable + " where k='100' and c={'a_key': 'av100', 'b_key': 'zv100'};");
+         assertEquals(1, filtered.size());
+     }
+ 
+     @Test
+     public void testFrozenMapTypeCustomOrdered() throws Exception
+     {
 -        final String KS = "cql_keyspace4";
 -        final String TABLE = "table4";
 -        final String qualifiedTable = KS + "." + TABLE;
 -        File tempdir = Files.createTempDir();
 -        File dataDir = new File(tempdir.getAbsolutePath() + File.separator + 
KS + File.separator + TABLE);
 -        assert dataDir.mkdirs();
+         // Test to make sure we can write to `date` fields in both old and 
new formats
+         String schema = "CREATE TABLE " + qualifiedTable + " ("
+                         + "  k text,"
+                         + "  c frozen<map<timeuuid, int>>,"
+                         + "  PRIMARY KEY (k, c)"
+                         + ")";
+         String insert = "INSERT INTO " + qualifiedTable + " (k, c) VALUES (?, 
?)";
+         CQLSSTableWriter writer = CQLSSTableWriter.builder()
+                                                   .inDirectory(dataDir)
+                                                   .forTable(schema)
+                                                   .using(insert)
+                                                   .withBufferSizeInMB(1)
+                                                   .build();
+         UUID uuid1 = UUIDs.timeBased();
+         UUID uuid2 = UUIDs.timeBased();
+         UUID uuid3 = UUIDs.timeBased();
+         UUID uuid4 = UUIDs.timeBased();
+         Map<UUID, Integer> map = new LinkedHashMap<>();
+         // NOTE: if these two `put` calls are switched, the test passes
+         map.put(uuid2, 2);
+         map.put(uuid1, 1);
+         writer.addRow(String.valueOf(1), map);
+ 
+         Map<UUID, Integer> map2 = new LinkedHashMap<>();
+         map2.put(uuid3, 1);
+         map2.put(uuid4, 2);
+         writer.addRow(String.valueOf(2), map2);
+ 
+         writer.close();
 -        loadSSTables(dataDir, KS);
++        loadSSTables(dataDir, keyspace);
+ 
+         UntypedResultSet rs = QueryProcessor.executeInternal("SELECT * FROM " 
+ qualifiedTable + ";");
+         assertEquals(2, rs.size());
+ 
+         // Make sure we can filter with map values regardless of which order 
we put the keys in
+         UntypedResultSet filtered;
+         filtered = QueryProcessor.executeInternal("SELECT * FROM " + 
qualifiedTable + " where k='1' and c={" + uuid1 + ": 1, " + uuid2 + ": 2};");
+         assertEquals(1, filtered.size());
+         filtered = QueryProcessor.executeInternal("SELECT * FROM " + 
qualifiedTable + " where k='1' and c={" + uuid2 + ": 2, " + uuid1 + ": 1};");
+         assertEquals(1, filtered.size());
+         filtered = QueryProcessor.executeInternal("SELECT * FROM " + 
qualifiedTable + " where k='2' and c={" + uuid3 + ": 1, " + uuid4 + ": 2};");
+         assertEquals(1, filtered.size());
+         filtered = QueryProcessor.executeInternal("SELECT * FROM " + 
qualifiedTable + " where k='2' and c={" + uuid4 + ": 2, " + uuid3 + ": 1};");
+         assertEquals(1, filtered.size());
+         UUID other = UUIDs.startOf(1234L); // Just some other TimeUUID
+         filtered = QueryProcessor.executeInternal("SELECT * FROM " + 
qualifiedTable + " where k='2' and c={" + uuid3 + ": 1, " + other + ": 2};");
+         assertEquals(0, filtered.size());
+         filtered = QueryProcessor.executeInternal("SELECT * FROM " + 
qualifiedTable + " where k='2' and c={" + uuid4 + ": 2, " + other + ": 1};");
+         assertEquals(0, filtered.size());
+     }
+ 
+     @Test
+     public void testFrozenSetTypeCustomOrdered() throws Exception
+     {
 -        final String KS = "cql_keyspace5";
 -        final String TABLE = "table5";
 -        final String qualifiedTable = KS + "." + TABLE;
 -        File tempdir = Files.createTempDir();
 -        File dataDir = new File(tempdir.getAbsolutePath() + File.separator + 
KS + File.separator + TABLE);
 -        assert dataDir.mkdirs();
+         // Test to make sure we can write to `date` fields in both old and 
new formats
+         String schema = "CREATE TABLE " + qualifiedTable + " ("
+                         + "  k text,"
+                         + "  c frozen<set<timeuuid>>,"
+                         + "  PRIMARY KEY (k, c)"
+                         + ")";
+         String insert = "INSERT INTO " + qualifiedTable + " (k, c) VALUES (?, 
?)";
+         CQLSSTableWriter writer = CQLSSTableWriter.builder()
+                                                   .inDirectory(dataDir)
+                                                   .forTable(schema)
+                                                   .using(insert)
+                                                   .withBufferSizeInMB(1)
+                                                   .build();
+         UUID uuid1 = UUIDs.startOf(0L);
+         UUID uuid2 = UUIDs.startOf(10000000L);
+ 
+         LinkedHashSet<UUID> set = new LinkedHashSet<>();
+         set.add(uuid1);
+         set.add(uuid2);
+         writer.addRow(String.valueOf(1), set);
+ 
+         LinkedHashSet<UUID> set2 = new LinkedHashSet<>();
+         set2.add(uuid2);
+         set2.add(uuid1);
+         writer.addRow(String.valueOf(2), set2);
+ 
+         writer.close();
 -        loadSSTables(dataDir, KS);
++        loadSSTables(dataDir, keyspace);
+ 
+         UntypedResultSet rs = QueryProcessor.executeInternal("SELECT * FROM " 
+ qualifiedTable + ";");
+         assertEquals(2, rs.size());
+ 
+         // Make sure we can filter with map values regardless of which order 
we put the keys in
+         UntypedResultSet filtered;
+         filtered = QueryProcessor.executeInternal("SELECT * FROM " + 
qualifiedTable + " where k='1' and c={" + uuid1 + ", " + uuid2 + "};");
+         assertEquals(1, filtered.size());
+         filtered = QueryProcessor.executeInternal("SELECT * FROM " + 
qualifiedTable + " where k='1' and c={" + uuid2 + ", " + uuid1 + "};");
+         assertEquals(1, filtered.size());
+         filtered = QueryProcessor.executeInternal("SELECT * FROM " + 
qualifiedTable + " where k='2' and c={" + uuid1 + ", " + uuid2 + "};");
+         assertEquals(1, filtered.size());
+         filtered = QueryProcessor.executeInternal("SELECT * FROM " + 
qualifiedTable + " where k='2' and c={" + uuid2 + ", " + uuid1 + "};");
+         assertEquals(1, filtered.size());
+         UUID other = UUIDs.startOf(10000000L + 1L); // Pick one that's really 
close just to make sure clustering filters are working
+         filtered = QueryProcessor.executeInternal("SELECT * FROM " + 
qualifiedTable + " where k='2' and c={" + uuid1 + ", " + other + "};");
+         assertEquals(0, filtered.size());
+         filtered = QueryProcessor.executeInternal("SELECT * FROM " + 
qualifiedTable + " where k='2' and c={" + other + ", " + uuid1 + "};");
+         assertEquals(0, filtered.size());
+     }
+ 
      private static void loadSSTables(File dataDir, String ks) throws 
ExecutionException, InterruptedException
      {
          SSTableLoader loader = new SSTableLoader(dataDir, new 
SSTableLoader.Client()


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to