http://git-wip-us.apache.org/repos/asf/cassandra/blob/f797bfa4/test/unit/org/apache/cassandra/cql3/validation/entities/FrozenCollectionsTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/FrozenCollectionsTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/FrozenCollectionsTest.java new file mode 100644 index 0000000..beed560 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/FrozenCollectionsTest.java @@ -0,0 +1,1111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cassandra.cql3.validation.entities; + +import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.db.marshal.*; +import org.apache.cassandra.dht.ByteOrderedPartitioner; +import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.cassandra.exceptions.InvalidRequestException; +import org.apache.cassandra.exceptions.SyntaxException; +import org.apache.commons.lang3.StringUtils; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class FrozenCollectionsTest extends CQLTester +{ + @BeforeClass + public static void setUpClass() + { + DatabaseDescriptor.setPartitioner(new ByteOrderedPartitioner()); + } + + @Test + public void testPartitionKeyUsage() throws Throwable + { + createTable("CREATE TABLE %s (k frozen<set<int>> PRIMARY KEY, v int)"); + + execute("INSERT INTO %s (k, v) VALUES (?, ?)", set(), 1); + execute("INSERT INTO %s (k, v) VALUES (?, ?)", set(1, 2, 3), 1); + execute("INSERT INTO %s (k, v) VALUES (?, ?)", set(4, 5, 6), 0); + execute("INSERT INTO %s (k, v) VALUES (?, ?)", set(7, 8, 9), 0); + + // overwrite with an update + execute("UPDATE %s SET v=? WHERE k=?", 0, set()); + execute("UPDATE %s SET v=? WHERE k=?", 0, set(1, 2, 3)); + + assertRows(execute("SELECT * FROM %s"), + row(set(), 0), + row(set(1, 2, 3), 0), + row(set(4, 5, 6), 0), + row(set(7, 8, 9), 0) + ); + + assertRows(execute("SELECT k FROM %s"), + row(set()), + row(set(1, 2, 3)), + row(set(4, 5, 6)), + row(set(7, 8, 9)) + ); + + assertRows(execute("SELECT * FROM %s LIMIT 2"), + row(set(), 0), + row(set(1, 2, 3), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE k=?", set(4, 5, 6)), + row(set(4, 5, 6), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE k=?", set()), + row(set(), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE k IN ?", list(set(4, 5, 6), set())), + row(set(4, 5, 6), 0), + row(set(), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE token(k) >= token(?)", set(4, 5, 6)), + row(set(4, 5, 6), 0), + row(set(7, 8, 9), 0) + ); + + assertInvalid("INSERT INTO %s (k, v) VALUES (null, 0)"); + + execute("DELETE FROM %s WHERE k=?", set()); + execute("DELETE FROM %s WHERE k=?", set(4, 5, 6)); + assertRows(execute("SELECT * FROM %s"), + row(set(1, 2, 3), 0), + row(set(7, 8, 9), 0) + ); + } + + @Test + public void testNestedPartitionKeyUsage() throws Throwable + { + createTable("CREATE TABLE %s (k frozen<map<set<int>, list<int>>> PRIMARY KEY, v int)"); + + execute("INSERT INTO %s (k, v) VALUES (?, ?)", map(), 1); + execute("INSERT INTO %s (k, v) VALUES (?, ?)", map(set(), list(1, 2, 3)), 0); + execute("INSERT INTO %s (k, v) VALUES (?, ?)", map(set(1, 2, 3), list(1, 2, 3)), 1); + execute("INSERT INTO %s (k, v) VALUES (?, ?)", map(set(4, 5, 6), list(1, 2, 3)), 0); + execute("INSERT INTO %s (k, v) VALUES (?, ?)", map(set(7, 8, 9), list(1, 2, 3)), 0); + + // overwrite with an update + execute("UPDATE %s SET v=? WHERE k=?", 0, map()); + execute("UPDATE %s SET v=? WHERE k=?", 0, map(set(1, 2, 3), list(1, 2, 3))); + + assertRows(execute("SELECT * FROM %s"), + row(map(), 0), + row(map(set(), list(1, 2, 3)), 0), + row(map(set(1, 2, 3), list(1, 2, 3)), 0), + row(map(set(4, 5, 6), list(1, 2, 3)), 0), + row(map(set(7, 8, 9), list(1, 2, 3)), 0) + ); + + assertRows(execute("SELECT k FROM %s"), + row(map()), + row(map(set(), list(1, 2, 3))), + row(map(set(1, 2, 3), list(1, 2, 3))), + row(map(set(4, 5, 6), list(1, 2, 3))), + row(map(set(7, 8, 9), list(1, 2, 3))) + ); + + assertRows(execute("SELECT * FROM %s LIMIT 3"), + row(map(), 0), + row(map(set(), list(1, 2, 3)), 0), + row(map(set(1, 2, 3), list(1, 2, 3)), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE k=?", map(set(4, 5, 6), list(1, 2, 3))), + row(map(set(4, 5, 6), list(1, 2, 3)), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE k=?", map()), + row(map(), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE k=?", map(set(), list(1, 2, 3))), + row(map(set(), list(1, 2, 3)), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE k IN ?", list(map(set(4, 5, 6), list(1, 2, 3)), map(), map(set(), list(1, 2, 3)))), + row(map(set(4, 5, 6), list(1, 2, 3)), 0), + row(map(), 0), + row(map(set(), list(1, 2, 3)), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE token(k) >= token(?)", map(set(4, 5, 6), list(1, 2, 3))), + row(map(set(4, 5, 6), list(1, 2, 3)), 0), + row(map(set(7, 8, 9), list(1, 2, 3)), 0) + ); + + execute("DELETE FROM %s WHERE k=?", map()); + execute("DELETE FROM %s WHERE k=?", map(set(), list(1, 2, 3))); + execute("DELETE FROM %s WHERE k=?", map(set(4, 5, 6), list(1, 2, 3))); + assertRows(execute("SELECT * FROM %s"), + row(map(set(1, 2, 3), list(1, 2, 3)), 0), + row(map(set(7, 8, 9), list(1, 2, 3)), 0) + ); + + } + + @Test + public void testClusteringKeyUsage() throws Throwable + { + for (String option : Arrays.asList("", " WITH COMPACT STORAGE")) + { + createTable("CREATE TABLE %s (a int, b frozen<set<int>>, c int, PRIMARY KEY (a, b))" + option); + + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, set(), 1); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, set(1, 2, 3), 1); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, set(4, 5, 6), 0); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, set(7, 8, 9), 0); + + // overwrite with an update + execute("UPDATE %s SET c=? WHERE a=? AND b=?", 0, 0, set()); + execute("UPDATE %s SET c=? WHERE a=? AND b=?", 0, 0, set(1, 2, 3)); + + assertRows(execute("SELECT * FROM %s"), + row(0, set(), 0), + row(0, set(1, 2, 3), 0), + row(0, set(4, 5, 6), 0), + row(0, set(7, 8, 9), 0) + ); + + assertRows(execute("SELECT b FROM %s"), + row(set()), + row(set(1, 2, 3)), + row(set(4, 5, 6)), + row(set(7, 8, 9)) + ); + + assertRows(execute("SELECT * FROM %s LIMIT 2"), + row(0, set(), 0), + row(0, set(1, 2, 3), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, set(4, 5, 6)), + row(0, set(4, 5, 6), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, set()), + row(0, set(), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b IN ?", 0, list(set(4, 5, 6), set())), + row(0, set(), 0), + row(0, set(4, 5, 6), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b > ?", 0, set(4, 5, 6)), + row(0, set(7, 8, 9), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b >= ?", 0, set(4, 5, 6)), + row(0, set(4, 5, 6), 0), + row(0, set(7, 8, 9), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b < ?", 0, set(4, 5, 6)), + row(0, set(), 0), + row(0, set(1, 2, 3), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b <= ?", 0, set(4, 5, 6)), + row(0, set(), 0), + row(0, set(1, 2, 3), 0), + row(0, set(4, 5, 6), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b > ? AND b <= ?", 0, set(1, 2, 3), set(4, 5, 6)), + row(0, set(4, 5, 6), 0) + ); + + execute("DELETE FROM %s WHERE a=? AND b=?", 0, set()); + execute("DELETE FROM %s WHERE a=? AND b=?", 0, set(4, 5, 6)); + assertRows(execute("SELECT * FROM %s"), + row(0, set(1, 2, 3), 0), + row(0, set(7, 8, 9), 0) + ); + } + } + + @Test + public void testNestedClusteringKeyUsage() throws Throwable + { + for (String option : Arrays.asList("", " WITH COMPACT STORAGE")) + { + createTable("CREATE TABLE %s (a int, b frozen<map<set<int>, list<int>>>, c frozen<set<int>>, d int, PRIMARY KEY (a, b, c))" + option); + + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, map(), set(), 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, map(set(), list(1, 2, 3)), set(), 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0); + + assertRows(execute("SELECT * FROM %s"), + row(0, map(), set(), 0), + row(0, map(set(), list(1, 2, 3)), set(), 0), + row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0), + row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0), + row(0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0) + ); + + assertRows(execute("SELECT b FROM %s"), + row(map()), + row(map(set(), list(1, 2, 3))), + row(map(set(1, 2, 3), list(1, 2, 3))), + row(map(set(4, 5, 6), list(1, 2, 3))), + row(map(set(7, 8, 9), list(1, 2, 3))) + ); + + assertRows(execute("SELECT c FROM %s"), + row(set()), + row(set()), + row(set(1, 2, 3)), + row(set(1, 2, 3)), + row(set(1, 2, 3)) + ); + + assertRows(execute("SELECT * FROM %s LIMIT 3"), + row(0, map(), set(), 0), + row(0, map(set(), list(1, 2, 3)), set(), 0), + row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=0 ORDER BY b DESC LIMIT 4"), + row(0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0), + row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0), + row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0), + row(0, map(set(), list(1, 2, 3)), set(), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, map()), + row(0, map(), set(), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, map(set(), list(1, 2, 3))), + row(0, map(set(), list(1, 2, 3)), set(), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, map(set(1, 2, 3), list(1, 2, 3))), + row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, map(set(), list(1, 2, 3)), set()), + row(0, map(set(), list(1, 2, 3)), set(), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND (b, c) IN ?", 0, list(tuple(map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3)), + tuple(map(), set()))), + row(0, map(), set(), 0), + row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b > ?", 0, map(set(4, 5, 6), list(1, 2, 3))), + row(0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b >= ?", 0, map(set(4, 5, 6), list(1, 2, 3))), + row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0), + row(0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b < ?", 0, map(set(4, 5, 6), list(1, 2, 3))), + row(0, map(), set(), 0), + row(0, map(set(), list(1, 2, 3)), set(), 0), + row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b <= ?", 0, map(set(4, 5, 6), list(1, 2, 3))), + row(0, map(), set(), 0), + row(0, map(set(), list(1, 2, 3)), set(), 0), + row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0), + row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b > ? AND b <= ?", 0, map(set(1, 2, 3), list(1, 2, 3)), map(set(4, 5, 6), list(1, 2, 3))), + row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0) + ); + + execute("DELETE FROM %s WHERE a=? AND b=? AND c=?", 0, map(), set()); + assertEmpty(execute("SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, map(), set())); + + execute("DELETE FROM %s WHERE a=? AND b=? AND c=?", 0, map(set(), list(1, 2, 3)), set()); + assertEmpty(execute("SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, map(set(), list(1, 2, 3)), set())); + + execute("DELETE FROM %s WHERE a=? AND b=? AND c=?", 0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3)); + assertEmpty(execute("SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3))); + + assertRows(execute("SELECT * FROM %s"), + row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0), + row(0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0) + ); + } + } + + @Test + public void testNormalColumnUsage() throws Throwable + { + for (String option : Arrays.asList("", " WITH COMPACT STORAGE")) + { + createTable("CREATE TABLE %s (a int PRIMARY KEY, b frozen<map<set<int>, list<int>>>, c frozen<set<int>>)" + option); + + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, map(), set()); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 1, map(set(), list(99999, 999999, 99999)), set()); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 2, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3)); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 3, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3)); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 4, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3)); + + // overwrite with update + execute ("UPDATE %s SET b=? WHERE a=?", map(set(), list(1, 2, 3)), 1); + + assertRows(execute("SELECT * FROM %s"), + row(0, map(), set()), + row(1, map(set(), list(1, 2, 3)), set()), + row(2, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3)), + row(3, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3)), + row(4, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3)) + ); + + assertRows(execute("SELECT b FROM %s"), + row(map()), + row(map(set(), list(1, 2, 3))), + row(map(set(1, 2, 3), list(1, 2, 3))), + row(map(set(4, 5, 6), list(1, 2, 3))), + row(map(set(7, 8, 9), list(1, 2, 3))) + ); + + assertRows(execute("SELECT c FROM %s"), + row(set()), + row(set()), + row(set(1, 2, 3)), + row(set(1, 2, 3)), + row(set(1, 2, 3)) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=?", 3), + row(3, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3)) + ); + + execute("UPDATE %s SET b=? WHERE a=?", null, 1); + assertRows(execute("SELECT * FROM %s WHERE a=?", 1), + row(1, null, set()) + ); + + execute("UPDATE %s SET b=? WHERE a=?", map(), 1); + assertRows(execute("SELECT * FROM %s WHERE a=?", 1), + row(1, map(), set()) + ); + + execute("UPDATE %s SET c=? WHERE a=?", null, 2); + assertRows(execute("SELECT * FROM %s WHERE a=?", 2), + row(2, map(set(1, 2, 3), list(1, 2, 3)), null) + ); + + execute("UPDATE %s SET c=? WHERE a=?", set(), 2); + assertRows(execute("SELECT * FROM %s WHERE a=?", 2), + row(2, map(set(1, 2, 3), list(1, 2, 3)), set()) + ); + + execute("DELETE b FROM %s WHERE a=?", 3); + assertRows(execute("SELECT * FROM %s WHERE a=?", 3), + row(3, null, set(1, 2, 3)) + ); + + execute("DELETE c FROM %s WHERE a=?", 4); + assertRows(execute("SELECT * FROM %s WHERE a=?", 4), + row(4, map(set(7, 8, 9), list(1, 2, 3)), null) + ); + } + } + + @Test + public void testStaticColumnUsage() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c frozen<map<set<int>, list<int>>> static, d int, PRIMARY KEY (a, b))"); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, map(), 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, map(), 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 0, map(set(), list(1, 2, 3)), 0); + execute("INSERT INTO %s (a, b, d) VALUES (?, ?, ?)", 1, 1, 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 2, 0, map(set(1, 2, 3), list(1, 2, 3)), 0); + + assertRows(execute("SELECT * FROM %s"), + row(0, 0, map(), 0), + row(0, 1, map(), 0), + row(1, 0, map(set(), list(1, 2, 3)), 0), + row(1, 1, map(set(), list(1, 2, 3)), 0), + row(2, 0, map(set(1, 2, 3), list(1, 2, 3)), 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, 1), + row(0, 1, map(), 0) + ); + + execute("DELETE c FROM %s WHERE a=?", 0); + assertRows(execute("SELECT * FROM %s"), + row(0, 0, null, 0), + row(0, 1, null, 0), + row(1, 0, map(set(), list(1, 2, 3)), 0), + row(1, 1, map(set(), list(1, 2, 3)), 0), + row(2, 0, map(set(1, 2, 3), list(1, 2, 3)), 0) + ); + + execute("DELETE FROM %s WHERE a=?", 0); + assertRows(execute("SELECT * FROM %s"), + row(1, 0, map(set(), list(1, 2, 3)), 0), + row(1, 1, map(set(), list(1, 2, 3)), 0), + row(2, 0, map(set(1, 2, 3), list(1, 2, 3)), 0) + ); + + execute("UPDATE %s SET c=? WHERE a=?", map(set(1, 2, 3), list(1, 2, 3)), 1); + assertRows(execute("SELECT * FROM %s"), + row(1, 0, map(set(1, 2, 3), list(1, 2, 3)), 0), + row(1, 1, map(set(1, 2, 3), list(1, 2, 3)), 0), + row(2, 0, map(set(1, 2, 3), list(1, 2, 3)), 0) + ); + } + + private void assertInvalidCreateWithMessage(String createTableStatement, String errorMessage) throws Throwable + { + try + { + createTableMayThrow(createTableStatement); + Assert.fail("Expected CREATE TABLE statement to error: " + createTableStatement); + } + catch (InvalidRequestException | ConfigurationException | SyntaxException ex) + { + Assert.assertTrue("Expected error message to contain '" + errorMessage + "', but got '" + ex.getMessage() + "'", + ex.getMessage().contains(errorMessage)); + } + } + + private void assertInvalidAlterWithMessage(String createTableStatement, String errorMessage) throws Throwable + { + try + { + alterTableMayThrow(createTableStatement); + Assert.fail("Expected CREATE TABLE statement to error: " + createTableStatement); + } + catch (InvalidRequestException | ConfigurationException ex) + { + Assert.assertTrue("Expected error message to contain '" + errorMessage + "', but got '" + ex.getMessage() + "'", + ex.getMessage().contains(errorMessage)); + } + } + + @Test + public void testInvalidOperations() throws Throwable + { + // lists + createTable("CREATE TABLE %s (k int PRIMARY KEY, l frozen<list<int>>)"); + assertInvalid("UPDATE %s SET l[?]=? WHERE k=?", 0, 0, 0); + assertInvalid("UPDATE %s SET l = ? + l WHERE k=?", list(0), 0); + assertInvalid("UPDATE %s SET l = l + ? WHERE k=?", list(4), 0); + assertInvalid("UPDATE %s SET l = l - ? WHERE k=?", list(3), 0); + assertInvalid("DELETE l[?] FROM %s WHERE k=?", 0, 0); + + // sets + createTable("CREATE TABLE %s (k int PRIMARY KEY, s frozen<set<int>>)"); + assertInvalid("UPDATE %s SET s = s + ? WHERE k=?", set(0), 0); + assertInvalid("UPDATE %s SET s = s - ? WHERE k=?", set(3), 0); + + // maps + createTable("CREATE TABLE %s (k int PRIMARY KEY, m frozen<map<int, int>>)"); + assertInvalid("UPDATE %s SET m[?]=? WHERE k=?", 0, 0, 0); + assertInvalid("UPDATE %s SET m = m + ? WHERE k=?", map(4, 4), 0); + assertInvalid("DELETE m[?] FROM %s WHERE k=?", 0, 0); + + assertInvalidCreateWithMessage("CREATE TABLE %s (k int PRIMARY KEY, t set<set<int>>)", + "Non-frozen collections are not allowed inside collections"); + + assertInvalidCreateWithMessage("CREATE TABLE %s (k int PRIMARY KEY, t frozen<set<counter>>)", + "Counters are not allowed inside collections"); + + assertInvalidCreateWithMessage("CREATE TABLE %s (k int PRIMARY KEY, t frozen<text>)", + "frozen<> is only allowed on collections, tuples, and user-defined types"); + } + + @Test + public void testAltering() throws Throwable + { + createTable("CREATE TABLE %s (a int, b frozen<list<int>>, c frozen<list<int>>, PRIMARY KEY (a, b))"); + + alterTable("ALTER TABLE %s ALTER c TYPE frozen<list<blob>>"); + + assertInvalidAlterWithMessage("ALTER TABLE %s ALTER b TYPE frozen<list<blob>>", + "types are not order-compatible"); + + assertInvalidAlterWithMessage("ALTER TABLE %s ALTER b TYPE list<int>", + "types are not order-compatible"); + + assertInvalidAlterWithMessage("ALTER TABLE %s ALTER c TYPE list<blob>", + "types are incompatible"); + + alterTable("ALTER TABLE %s DROP c"); + alterTable("ALTER TABLE %s ADD c frozen<set<int>>"); + assertInvalidAlterWithMessage("ALTER TABLE %s ALTER c TYPE frozen<set<blob>>", + "types are incompatible"); + + alterTable("ALTER TABLE %s DROP c"); + alterTable("ALTER TABLE %s ADD c frozen<map<int, int>>"); + assertInvalidAlterWithMessage("ALTER TABLE %s ALTER c TYPE frozen<map<blob, int>>", + "types are incompatible"); + alterTable("ALTER TABLE %s ALTER c TYPE frozen<map<int, blob>>"); + } + + private void assertInvalidIndexCreationWithMessage(String statement, String errorMessage) throws Throwable + { + try + { + createIndexMayThrow(statement); + Assert.fail("Expected index creation to fail: " + statement); + } + catch (InvalidRequestException ex) + { + Assert.assertTrue("Expected error message to contain '" + errorMessage + "', but got '" + ex.getMessage() + "'", + ex.getMessage().contains(errorMessage)); + } + } + + @Test + public void testSecondaryIndex() throws Throwable + { + createTable("CREATE TABLE %s (a frozen<map<int, text>> PRIMARY KEY, b frozen<map<int, text>>)"); + + // for now, we don't support indexing values or keys of collections in the primary key + assertInvalidIndexCreationWithMessage("CREATE INDEX ON %s (full(a))", "Cannot create secondary index on partition key column"); + assertInvalidIndexCreationWithMessage("CREATE INDEX ON %s (keys(a))", "Cannot create index on keys of frozen<map> column"); + assertInvalidIndexCreationWithMessage("CREATE INDEX ON %s (keys(b))", "Cannot create index on keys of frozen<map> column"); + + createTable("CREATE TABLE %s (a int, b frozen<list<int>>, c frozen<set<int>>, d frozen<map<int, text>>, PRIMARY KEY (a, b))"); + + createIndex("CREATE INDEX ON %s (full(b))"); + createIndex("CREATE INDEX ON %s (full(c))"); + createIndex("CREATE INDEX ON %s (full(d))"); + + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, list(1, 2, 3), set(1, 2, 3), map(1, "a")); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, list(4, 5, 6), set(1, 2, 3), map(1, "a")); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, list(1, 2, 3), set(4, 5, 6), map(2, "b")); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, list(4, 5, 6), set(4, 5, 6), map(2, "b")); + + // CONTAINS KEY doesn't work on non-maps + assertInvalidMessage("Cannot use CONTAINS KEY on non-map column", + "SELECT * FROM %s WHERE b CONTAINS KEY ?", 1); + + assertInvalidMessage("Cannot use CONTAINS KEY on non-map column", + "SELECT * FROM %s WHERE b CONTAINS KEY ? ALLOW FILTERING", 1); + + assertInvalidMessage("Cannot use CONTAINS KEY on non-map column", + "SELECT * FROM %s WHERE c CONTAINS KEY ?", 1); + + // normal indexes on frozen collections don't support CONTAINS or CONTAINS KEY + assertInvalidMessage("Cannot restrict column \"b\" by a CONTAINS relation without a secondary index", + "SELECT * FROM %s WHERE b CONTAINS ?", 1); + + assertInvalidMessage("Cannot restrict column \"b\" by a CONTAINS relation without a secondary index", + "SELECT * FROM %s WHERE b CONTAINS ? ALLOW FILTERING", 1); + + assertInvalidMessage("No secondary indexes on the restricted columns support the provided operator", + "SELECT * FROM %s WHERE d CONTAINS KEY ?", 1); + + assertInvalidMessage("No secondary indexes on the restricted columns support the provided operator", + "SELECT * FROM %s WHERE d CONTAINS KEY ? ALLOW FILTERING", 1); + + assertInvalidMessage("Cannot restrict column \"b\" by a CONTAINS relation without a secondary index", + "SELECT * FROM %s WHERE b CONTAINS ? AND d CONTAINS KEY ? ALLOW FILTERING", 1, 1); + + // index lookup on b + assertRows(execute("SELECT * FROM %s WHERE b=?", list(1, 2, 3)), + row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")), + row(1, list(1, 2, 3), set(4, 5, 6), map(2, "b")) + ); + + assertEmpty(execute("SELECT * FROM %s WHERE b=?", list(-1))); + + assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE b=? AND c=?", list(1, 2, 3), set(4, 5, 6)); + assertRows(execute("SELECT * FROM %s WHERE b=? AND c=? ALLOW FILTERING", list(1, 2, 3), set(4, 5, 6)), + row(1, list(1, 2, 3), set(4, 5, 6), map(2, "b")) + ); + + assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE b=? AND c CONTAINS ?", list(1, 2, 3), 5); + assertRows(execute("SELECT * FROM %s WHERE b=? AND c CONTAINS ? ALLOW FILTERING", list(1, 2, 3), 5), + row(1, list(1, 2, 3), set(4, 5, 6), map(2, "b")) + ); + + assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE b=? AND d=?", list(1, 2, 3), map(1, "a")); + assertRows(execute("SELECT * FROM %s WHERE b=? AND d=? ALLOW FILTERING", list(1, 2, 3), map(1, "a")), + row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")) + ); + + assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE b=? AND d CONTAINS ?", list(1, 2, 3), "a"); + assertRows(execute("SELECT * FROM %s WHERE b=? AND d CONTAINS ? ALLOW FILTERING", list(1, 2, 3), "a"), + row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")) + ); + + assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE b=? AND d CONTAINS KEY ?", list(1, 2, 3), 1); + assertRows(execute("SELECT * FROM %s WHERE b=? AND d CONTAINS KEY ? ALLOW FILTERING", list(1, 2, 3), 1), + row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")) + ); + + // index lookup on c + assertRows(execute("SELECT * FROM %s WHERE c=?", set(1, 2, 3)), + row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")), + row(0, list(4, 5, 6), set(1, 2, 3), map(1, "a")) + ); + + // ordering of c should not matter + assertRows(execute("SELECT * FROM %s WHERE c=?", set(2, 1, 3)), + row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")), + row(0, list(4, 5, 6), set(1, 2, 3), map(1, "a")) + ); + + assertEmpty(execute("SELECT * FROM %s WHERE c=?", set(-1))); + + assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE c=? AND b=?", set(1, 2, 3), list(1, 2, 3)); + assertRows(execute("SELECT * FROM %s WHERE c=? AND b=? ALLOW FILTERING", set(1, 2, 3), list(1, 2, 3)), + row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")) + ); + + assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE c=? AND b CONTAINS ?", set(1, 2, 3), 1); + assertRows(execute("SELECT * FROM %s WHERE c=? AND b CONTAINS ? ALLOW FILTERING", set(1, 2, 3), 1), + row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")) + ); + + assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE c=? AND d = ?", set(1, 2, 3), map(1, "a")); + assertRows(execute("SELECT * FROM %s WHERE c=? AND d = ? ALLOW FILTERING", set(1, 2, 3), map(1, "a")), + row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")), + row(0, list(4, 5, 6), set(1, 2, 3), map(1, "a")) + ); + + assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE c=? AND d CONTAINS ?", set(1, 2, 3), "a"); + assertRows(execute("SELECT * FROM %s WHERE c=? AND d CONTAINS ? ALLOW FILTERING", set(1, 2, 3), "a"), + row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")), + row(0, list(4, 5, 6), set(1, 2, 3), map(1, "a")) + ); + + assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE c=? AND d CONTAINS KEY ?", set(1, 2, 3), 1); + assertRows(execute("SELECT * FROM %s WHERE c=? AND d CONTAINS KEY ? ALLOW FILTERING", set(1, 2, 3), 1), + row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")), + row(0, list(4, 5, 6), set(1, 2, 3), map(1, "a")) + ); + + // index lookup on d + assertRows(execute("SELECT * FROM %s WHERE d=?", map(1, "a")), + row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")), + row(0, list(4, 5, 6), set(1, 2, 3), map(1, "a")) + ); + + assertRows(execute("SELECT * FROM %s WHERE d=?", map(2, "b")), + row(1, list(1, 2, 3), set(4, 5, 6), map(2, "b")), + row(1, list(4, 5, 6), set(4, 5, 6), map(2, "b")) + ); + + assertEmpty(execute("SELECT * FROM %s WHERE d=?", map(3, "c"))); + + assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE d=? AND c=?", map(1, "a"), set(1, 2, 3)); + assertRows(execute("SELECT * FROM %s WHERE d=? AND b=? ALLOW FILTERING", map(1, "a"), list(1, 2, 3)), + row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")) + ); + + assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE d=? AND b CONTAINS ?", map(1, "a"), 3); + assertRows(execute("SELECT * FROM %s WHERE d=? AND b CONTAINS ? ALLOW FILTERING", map(1, "a"), 3), + row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")) + ); + + assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE d=? AND b=? AND c=?", map(1, "a"), list(1, 2, 3), set(1, 2, 3)); + assertRows(execute("SELECT * FROM %s WHERE d=? AND b=? AND c=? ALLOW FILTERING", map(1, "a"), list(1, 2, 3), set(1, 2, 3)), + row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")) + ); + + assertRows(execute("SELECT * FROM %s WHERE d=? AND b CONTAINS ? AND c CONTAINS ? ALLOW FILTERING", map(1, "a"), 2, 2), + row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")) + ); + + execute("DELETE d FROM %s WHERE a=? AND b=?", 0, list(1, 2, 3)); + assertRows(execute("SELECT * FROM %s WHERE d=?", map(1, "a")), + row(0, list(4, 5, 6), set(1, 2, 3), map(1, "a")) + ); + } + + /** Test for CASSANDRA-8302 */ + @Test + public void testClusteringColumnFiltering() throws Throwable + { + createTable("CREATE TABLE %s (a int, b frozen<map<int, int>>, c int, d int, PRIMARY KEY (a, b, c))"); + createIndex("CREATE INDEX c_index ON %s (c)"); + createIndex("CREATE INDEX d_index ON %s (d)"); + + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, map(0, 0, 1, 1), 0, 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, map(1, 1, 2, 2), 0, 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, map(0, 0, 1, 1), 0, 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, map(1, 1, 2, 2), 0, 0); + + assertRows(execute("SELECT * FROM %s WHERE d=? AND b CONTAINS ? ALLOW FILTERING", 0, 0), + row(0, map(0, 0, 1, 1), 0, 0), + row(1, map(0, 0, 1, 1), 0, 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE d=? AND b CONTAINS KEY ? ALLOW FILTERING", 0, 0), + row(0, map(0, 0, 1, 1), 0, 0), + row(1, map(0, 0, 1, 1), 0, 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND d=? AND b CONTAINS ? ALLOW FILTERING", 0, 0, 0), + row(0, map(0, 0, 1, 1), 0, 0) + ); + assertRows(execute("SELECT * FROM %s WHERE a=? AND d=? AND b CONTAINS KEY ? ALLOW FILTERING", 0, 0, 0), + row(0, map(0, 0, 1, 1), 0, 0) + ); + + dropIndex("DROP INDEX %s.d_index"); + + assertRows(execute("SELECT * FROM %s WHERE c=? AND b CONTAINS ? ALLOW FILTERING", 0, 0), + row(0, map(0, 0, 1, 1), 0, 0), + row(1, map(0, 0, 1, 1), 0, 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE c=? AND b CONTAINS KEY ? ALLOW FILTERING", 0, 0), + row(0, map(0, 0, 1, 1), 0, 0), + row(1, map(0, 0, 1, 1), 0, 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND c=? AND b CONTAINS ? ALLOW FILTERING", 0, 0, 0), + row(0, map(0, 0, 1, 1), 0, 0) + ); + assertRows(execute("SELECT * FROM %s WHERE a=? AND c=? AND b CONTAINS KEY ? ALLOW FILTERING", 0, 0, 0), + row(0, map(0, 0, 1, 1), 0, 0) + ); + } + + @Test + public void testFrozenListInMap() throws Throwable + { + createTable("CREATE TABLE %s (k int primary key, m map<frozen<list<int>>, int>)"); + + execute("INSERT INTO %s (k, m) VALUES (1, {[1, 2, 3] : 1})"); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, map(list(1, 2, 3), 1))); + + execute("UPDATE %s SET m[[1, 2, 3]]=2 WHERE k=1"); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, map(list(1, 2, 3), 2))); + + execute("UPDATE %s SET m = m + ? WHERE k=1", map(list(4, 5, 6), 3)); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, + map(list(1, 2, 3), 2, + list(4, 5, 6), 3))); + + execute("DELETE m[[1, 2, 3]] FROM %s WHERE k = 1"); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, map(list(4, 5, 6), 3))); + } + + @Test + public void testFrozenListInSet() throws Throwable + { + createTable("CREATE TABLE %s (k int primary key, s set<frozen<list<int>>>)"); + + execute("INSERT INTO %s (k, s) VALUES (1, {[1, 2, 3]})"); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, set(list(1, 2, 3))) + ); + + execute("UPDATE %s SET s = s + ? WHERE k=1", set(list(4, 5, 6))); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, set(list(1, 2, 3), list(4, 5, 6))) + ); + + execute("UPDATE %s SET s = s - ? WHERE k=1", set(list(4, 5, 6))); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, set(list(1, 2, 3))) + ); + + execute("DELETE s[[1, 2, 3]] FROM %s WHERE k = 1"); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, null) + ); + } + + @Test + public void testFrozenListInList() throws Throwable + { + createTable("CREATE TABLE %s (k int primary key, l list<frozen<list<int>>>)"); + + execute("INSERT INTO %s (k, l) VALUES (1, [[1, 2, 3]])"); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(list(1, 2, 3))) + ); + + execute("UPDATE %s SET l[?]=? WHERE k=1", 0, list(4, 5, 6)); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(list(4, 5, 6))) + ); + + execute("UPDATE %s SET l = ? + l WHERE k=1", list(list(1, 2, 3))); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(list(1, 2, 3), list(4, 5, 6))) + ); + + execute("UPDATE %s SET l = l + ? WHERE k=1", list(list(7, 8, 9))); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(list(1, 2, 3), list(4, 5, 6), list(7, 8, 9))) + ); + + execute("UPDATE %s SET l = l - ? WHERE k=1", list(list(4, 5, 6))); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(list(1, 2, 3), list(7, 8, 9))) + ); + + execute("DELETE l[0] FROM %s WHERE k = 1"); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(list(7, 8, 9))) + ); + } + + @Test + public void testFrozenMapInMap() throws Throwable + { + createTable("CREATE TABLE %s (k int primary key, m map<frozen<map<int, int>>, int>)"); + + execute("INSERT INTO %s (k, m) VALUES (1, {{1 : 1, 2 : 2} : 1})"); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, map(map(1, 1, 2, 2), 1))); + + execute("UPDATE %s SET m[?]=2 WHERE k=1", map(1, 1, 2, 2)); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, map(map(1, 1, 2, 2), 2))); + + execute("UPDATE %s SET m = m + ? WHERE k=1", map(map(3, 3, 4, 4), 3)); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, + map(map(1, 1, 2, 2), 2, + map(3, 3, 4, 4), 3))); + + execute("DELETE m[?] FROM %s WHERE k = 1", map(1, 1, 2, 2)); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, map(map(3, 3, 4, 4), 3))); + } + + @Test + public void testFrozenMapInSet() throws Throwable + { + createTable("CREATE TABLE %s (k int primary key, s set<frozen<map<int, int>>>)"); + + execute("INSERT INTO %s (k, s) VALUES (1, {{1 : 1, 2 : 2}})"); + + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, set(map(1, 1, 2, 2))) + ); + + execute("UPDATE %s SET s = s + ? WHERE k=1", set(map(3, 3, 4, 4))); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, set(map(1, 1, 2, 2), map(3, 3, 4, 4))) + ); + + execute("UPDATE %s SET s = s - ? WHERE k=1", set(map(3, 3, 4, 4))); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, set(map(1, 1, 2, 2))) + ); + + execute("DELETE s[?] FROM %s WHERE k = 1", map(1, 1, 2, 2)); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, null) + ); + } + + @Test + public void testFrozenMapInList() throws Throwable + { + createTable("CREATE TABLE %s (k int primary key, l list<frozen<map<int, int>>>)"); + + execute("INSERT INTO %s (k, l) VALUES (1, [{1 : 1, 2 : 2}])"); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(map(1, 1, 2, 2))) + ); + + execute("UPDATE %s SET l[?]=? WHERE k=1", 0, map(3, 3, 4, 4)); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(map(3, 3, 4, 4))) + ); + + execute("UPDATE %s SET l = ? + l WHERE k=1", list(map(1, 1, 2, 2))); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(map(1, 1, 2, 2), map(3, 3, 4, 4))) + ); + + execute("UPDATE %s SET l = l + ? WHERE k=1", list(map(5, 5, 6, 6))); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(map(1, 1, 2, 2), map(3, 3, 4, 4), map(5, 5, 6, 6))) + ); + + execute("UPDATE %s SET l = l - ? WHERE k=1", list(map(3, 3, 4, 4))); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(map(1, 1, 2, 2), map(5, 5, 6, 6))) + ); + + execute("DELETE l[0] FROM %s WHERE k = 1"); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(map(5, 5, 6, 6))) + ); + } + + @Test + public void testFrozenSetInMap() throws Throwable + { + createTable("CREATE TABLE %s (k int primary key, m map<frozen<set<int>>, int>)"); + + execute("INSERT INTO %s (k, m) VALUES (1, {{1, 2, 3} : 1})"); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, map(set(1, 2, 3), 1))); + + execute("UPDATE %s SET m[?]=2 WHERE k=1", set(1, 2, 3)); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, map(set(1, 2, 3), 2))); + + execute("UPDATE %s SET m = m + ? WHERE k=1", map(set(4, 5, 6), 3)); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, + map(set(1, 2, 3), 2, + set(4, 5, 6), 3))); + + execute("DELETE m[?] FROM %s WHERE k = 1", set(1, 2, 3)); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, map(set(4, 5, 6), 3))); + } + + @Test + public void testFrozenSetInSet() throws Throwable + { + createTable("CREATE TABLE %s (k int primary key, s set<frozen<set<int>>>)"); + + execute("INSERT INTO %s (k, s) VALUES (1, {{1, 2, 3}})"); + + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, set(set(1, 2, 3))) + ); + + execute("UPDATE %s SET s = s + ? WHERE k=1", set(set(4, 5, 6))); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, set(set(1, 2, 3), set(4, 5, 6))) + ); + + execute("UPDATE %s SET s = s - ? WHERE k=1", set(set(4, 5, 6))); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, set(set(1, 2, 3))) + ); + + execute("DELETE s[?] FROM %s WHERE k = 1", set(1, 2, 3)); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, null) + ); + } + + @Test + public void testFrozenSetInList() throws Throwable + { + createTable("CREATE TABLE %s (k int primary key, l list<frozen<set<int>>>)"); + + execute("INSERT INTO %s (k, l) VALUES (1, [{1, 2, 3}])"); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(set(1, 2, 3))) + ); + + execute("UPDATE %s SET l[?]=? WHERE k=1", 0, set(4, 5, 6)); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(set(4, 5, 6))) + ); + + execute("UPDATE %s SET l = ? + l WHERE k=1", list(set(1, 2, 3))); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(set(1, 2, 3), set(4, 5, 6))) + ); + + execute("UPDATE %s SET l = l + ? WHERE k=1", list(set(7, 8, 9))); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(set(1, 2, 3), set(4, 5, 6), set(7, 8, 9))) + ); + + execute("UPDATE %s SET l = l - ? WHERE k=1", list(set(4, 5, 6))); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(set(1, 2, 3), set(7, 8, 9))) + ); + + execute("DELETE l[0] FROM %s WHERE k = 1"); + assertRows(execute("SELECT * FROM %s WHERE k = 1"), + row(1, list(set(7, 8, 9))) + ); + } + + @Test + public void testUserDefinedTypes() throws Throwable + { + String myType = createType("CREATE TYPE %s (a set<int>, b tuple<list<int>>)"); + createTable("CREATE TABLE %s (k int PRIMARY KEY, v frozen<" + myType + ">)"); + execute("INSERT INTO %s (k, v) VALUES (?, {a: ?, b: ?})", 0, set(1, 2, 3), tuple(list(1, 2, 3))); + assertRows(execute("SELECT v.a, v.b FROM %s WHERE k=?", 0), + row(set(1, 2, 3), tuple(list(1, 2, 3))) + ); + } + + private static String clean(String classname) + { + return StringUtils.remove(classname, "org.apache.cassandra.db.marshal."); + } + + @Test + public void testToString() + { + // set<frozen<list<int>>> + SetType t = SetType.getInstance(ListType.getInstance(Int32Type.instance, false), true); + assertEquals("SetType(FrozenType(ListType(Int32Type)))", clean(t.toString())); + assertEquals("SetType(ListType(Int32Type))", clean(t.toString(true))); + + // frozen<set<list<int>>> + t = SetType.getInstance(ListType.getInstance(Int32Type.instance, false), false); + assertEquals("FrozenType(SetType(ListType(Int32Type)))", clean(t.toString())); + assertEquals("SetType(ListType(Int32Type))", clean(t.toString(true))); + + // map<frozen<list<int>>, int> + MapType m = MapType.getInstance(ListType.getInstance(Int32Type.instance, false), Int32Type.instance, true); + assertEquals("MapType(FrozenType(ListType(Int32Type)),Int32Type)", clean(m.toString())); + assertEquals("MapType(ListType(Int32Type),Int32Type)", clean(m.toString(true))); + + // frozen<map<list<int>, int>> + m = MapType.getInstance(ListType.getInstance(Int32Type.instance, false), Int32Type.instance, false); + assertEquals("FrozenType(MapType(ListType(Int32Type),Int32Type))", clean(m.toString())); + assertEquals("MapType(ListType(Int32Type),Int32Type)", clean(m.toString(true))); + + // tuple<set<int>> + List<AbstractType<?>> types = new ArrayList<>(); + types.add(SetType.getInstance(Int32Type.instance, true)); + TupleType tuple = new TupleType(types); + assertEquals("TupleType(SetType(Int32Type))", clean(tuple.toString())); + } +}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/f797bfa4/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java new file mode 100644 index 0000000..a433d06 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java @@ -0,0 +1,644 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cassandra.cql3.validation.entities; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.lang.StringUtils; + +import org.junit.Test; + +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.cassandra.exceptions.SyntaxException; +import org.apache.cassandra.utils.FBUtilities; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class SecondaryIndexTest extends CQLTester +{ + private static final int TOO_BIG = 1024 * 65; + + @Test + public void testCreateAndDropIndex() throws Throwable + { + testCreateAndDropIndex("test", false); + testCreateAndDropIndex("test2", true); + } + + @Test + public void testCreateAndDropIndexWithQuotedIdentifier() throws Throwable + { + testCreateAndDropIndex("\"quoted_ident\"", false); + testCreateAndDropIndex("\"quoted_ident2\"", true); + } + + @Test + public void testCreateAndDropIndexWithCamelCaseIdentifier() throws Throwable + { + testCreateAndDropIndex("CamelCase", false); + testCreateAndDropIndex("CamelCase2", true); + } + + /** + * Test creating and dropping an index with the specified name. + * + * @param indexName the index name + * @param addKeyspaceOnDrop add the keyspace name in the drop statement + * @throws Throwable if an error occurs + */ + private void testCreateAndDropIndex(String indexName, boolean addKeyspaceOnDrop) throws Throwable + { + execute("USE system"); + assertInvalidMessage("Index '" + removeQuotes(indexName.toLowerCase(Locale.US)) + "' could not be found", "DROP INDEX " + indexName + ";"); + + createTable("CREATE TABLE %s (a int primary key, b int);"); + createIndex("CREATE INDEX " + indexName + " ON %s(b);"); + createIndex("CREATE INDEX IF NOT EXISTS " + indexName + " ON %s(b);"); + + assertInvalidMessage("Index already exists", "CREATE INDEX " + indexName + " ON %s(b)"); + + execute("INSERT INTO %s (a, b) values (?, ?);", 0, 0); + execute("INSERT INTO %s (a, b) values (?, ?);", 1, 1); + execute("INSERT INTO %s (a, b) values (?, ?);", 2, 2); + execute("INSERT INTO %s (a, b) values (?, ?);", 3, 1); + + assertRows(execute("SELECT * FROM %s where b = ?", 1), row(1, 1), row(3, 1)); + assertInvalidMessage("Index '" + removeQuotes(indexName.toLowerCase(Locale.US)) + "' could not be found in any of the tables of keyspace 'system'", "DROP INDEX " + indexName); + + if (addKeyspaceOnDrop) + { + dropIndex("DROP INDEX " + KEYSPACE + "." + indexName); + } + else + { + execute("USE " + KEYSPACE); + dropIndex("DROP INDEX " + indexName); + } + + assertInvalidMessage("No secondary indexes on the restricted columns support the provided operators", + "SELECT * FROM %s where b = ?", 1); + dropIndex("DROP INDEX IF EXISTS " + indexName); + assertInvalidMessage("Index '" + removeQuotes(indexName.toLowerCase(Locale.US)) + "' could not be found", "DROP INDEX " + indexName); + } + + /** + * Removes the quotes from the specified index name. + * + * @param indexName the index name from which the quotes must be removed. + * @return the unquoted index name. + */ + private static String removeQuotes(String indexName) + { + return StringUtils.remove(indexName, '\"'); + } + + /** + * Check that you can query for an indexed column even with a key EQ clause, + * migrated from cql_tests.py:TestCQL.static_cf_test() + */ + @Test + public void testSelectWithEQ() throws Throwable + { + createTable("CREATE TABLE %s (userid uuid PRIMARY KEY, firstname text, lastname text, age int)"); + createIndex("CREATE INDEX byAge ON %s(age)"); + + UUID id1 = UUID.fromString("550e8400-e29b-41d4-a716-446655440000"); + UUID id2 = UUID.fromString("f47ac10b-58cc-4372-a567-0e02b2c3d479"); + + execute("INSERT INTO %s (userid, firstname, lastname, age) VALUES (?, 'Frodo', 'Baggins', 32)", id1); + execute("UPDATE %s SET firstname = 'Samwise', lastname = 'Gamgee', age = 33 WHERE userid = ?", id2); + + assertEmpty(execute("SELECT firstname FROM %s WHERE userid = ? AND age = 33", id1)); + + assertRows(execute("SELECT firstname FROM %s WHERE userid = ? AND age = 33", id2), + row("Samwise")); + } + + /** + * Check CREATE INDEX without name and validate the index can be dropped, + * migrated from cql_tests.py:TestCQL.nameless_index_test() + */ + @Test + public void testNamelessIndex() throws Throwable + { + createTable(" CREATE TABLE %s (id text PRIMARY KEY, birth_year int)"); + + createIndex("CREATE INDEX on %s (birth_year)"); + + execute("INSERT INTO %s (id, birth_year) VALUES ('Tom', 42)"); + execute("INSERT INTO %s (id, birth_year) VALUES ('Paul', 24)"); + execute("INSERT INTO %s (id, birth_year) VALUES ('Bob', 42)"); + + assertRows(execute("SELECT id FROM %s WHERE birth_year = 42"), + row("Tom"), + row("Bob")); + + execute("DROP INDEX %s_birth_year_idx"); + + assertInvalid("SELECT id FROM users WHERE birth_year = 42"); + } + + /** + * Test range queries with 2ndary indexes (#4257), + * migrated from cql_tests.py:TestCQL.range_query_2ndary_test() + */ + @Test + public void testRangeQuery() throws Throwable + { + createTable("CREATE TABLE %s (id int primary key, row int, setid int)"); + createIndex("CREATE INDEX indextest_setid_idx ON %s (setid)"); + + execute("INSERT INTO %s (id, row, setid) VALUES (?, ?, ?)", 0, 0, 0); + execute("INSERT INTO %s (id, row, setid) VALUES (?, ?, ?)", 1, 1, 0); + execute("INSERT INTO %s (id, row, setid) VALUES (?, ?, ?)", 2, 2, 0); + execute("INSERT INTO %s (id, row, setid) VALUES (?, ?, ?)", 3, 3, 0); + + assertInvalid("SELECT * FROM %s WHERE setid = 0 AND row < 1"); + + assertRows(execute("SELECT * FROM %s WHERE setid = 0 AND row < 1 ALLOW FILTERING"), + row(0, 0, 0)); + } + + /** + * Check for unknown compression parameters options (#4266), + * migrated from cql_tests.py:TestCQL.compression_option_validation_test() + */ + @Test + public void testUnknownCompressionOptions() throws Throwable + { + String tableName = createTableName(); + assertInvalidThrow(SyntaxException.class, String.format( + "CREATE TABLE %s (key varchar PRIMARY KEY, password varchar, gender varchar) WITH compression_parameters:sstable_compressor = 'DeflateCompressor'", tableName)); + + + assertInvalidThrow(ConfigurationException.class, String.format( + "CREATE TABLE %s (key varchar PRIMARY KEY, password varchar, gender varchar) WITH compression = { 'sstable_compressor': 'DeflateCompressor' }", tableName)); + } + + /** + * Check one can use arbitrary name for datacenter when creating keyspace (#4278), + * migrated from cql_tests.py:TestCQL.keyspace_creation_options_test() + */ + @Test + public void testDataCenterName() throws Throwable + { + execute("CREATE KEYSPACE Foo WITH replication = { 'class' : 'NetworkTopologyStrategy', 'us-east' : 1, 'us-west' : 1 };"); + } + + /** + * Migrated from cql_tests.py:TestCQL.indexes_composite_test() + */ + @Test + public void testIndexOnComposite() throws Throwable + { + String tableName = createTable("CREATE TABLE %s (blog_id int, timestamp int, author text, content text, PRIMARY KEY (blog_id, timestamp))"); + + execute("INSERT INTO %s (blog_id, timestamp, author, content) VALUES (?, ?, ?, ?)", 0, 0, "bob", "1st post"); + execute("INSERT INTO %s (blog_id, timestamp, author, content) VALUES (?, ?, ?, ?)", 0, 1, "tom", "2nd post"); + execute("INSERT INTO %s (blog_id, timestamp, author, content) VALUES (?, ?, ?, ?)", 0, 2, "bob", "3rd post"); + execute("INSERT INTO %s (blog_id, timestamp, author, content) VALUES (?, ?, ?, ?)", 0, 3, "tom", "4th post"); + execute("INSERT INTO %s (blog_id, timestamp, author, content) VALUES (?, ?, ?, ?)", 1, 0, "bob", "5th post"); + + createIndex("CREATE INDEX authoridx ON %s (author)"); + + assertTrue(waitForIndex(keyspace(), tableName, "authoridx")); + + assertRows(execute("SELECT blog_id, timestamp FROM %s WHERE author = 'bob'"), + row(1, 0), + row(0, 0), + row(0, 2)); + + execute("INSERT INTO %s (blog_id, timestamp, author, content) VALUES (?, ?, ?, ?)", 1, 1, "tom", "6th post"); + execute("INSERT INTO %s (blog_id, timestamp, author, content) VALUES (?, ?, ?, ?)", 1, 2, "tom", "7th post"); + execute("INSERT INTO %s (blog_id, timestamp, author, content) VALUES (?, ?, ?, ?)", 1, 3, "bob", "8th post"); + + assertRows(execute("SELECT blog_id, timestamp FROM %s WHERE author = 'bob'"), + row(1, 0), + row(1, 3), + row(0, 0), + row(0, 2)); + + execute("DELETE FROM %s WHERE blog_id = 0 AND timestamp = 2"); + + assertRows(execute("SELECT blog_id, timestamp FROM %s WHERE author = 'bob'"), + row(1, 0), + row(1, 3), + row(0, 0)); + } + + /** + * Test for the validation bug of #4709, + * migrated from cql_tests.py:TestCQL.refuse_in_with_indexes_test() + */ + @Test + public void testInvalidIndexSelect() throws Throwable + { + createTable("create table %s (pk varchar primary key, col1 varchar, col2 varchar)"); + createIndex("create index on %s (col1)"); + createIndex("create index on %s (col2)"); + + execute("insert into %s (pk, col1, col2) values ('pk1','foo1','bar1')"); + execute("insert into %s (pk, col1, col2) values ('pk1a','foo1','bar1')"); + execute("insert into %s (pk, col1, col2) values ('pk1b','foo1','bar1')"); + execute("insert into %s (pk, col1, col2) values ('pk1c','foo1','bar1')"); + execute("insert into %s (pk, col1, col2) values ('pk2','foo2','bar2')"); + execute("insert into %s (pk, col1, col2) values ('pk3','foo3','bar3')"); + assertInvalid("select * from %s where col2 in ('bar1', 'bar2')"); + + //Migrated from cql_tests.py:TestCQL.bug_6050_test() + createTable("CREATE TABLE %s (k int PRIMARY KEY, a int, b int)"); + + createIndex("CREATE INDEX ON %s (a)"); + assertInvalid("SELECT * FROM %s WHERE a = 3 AND b IN (1, 3)"); + + } + + /** + * Migrated from cql_tests.py:TestCQL.edge_2i_on_complex_pk_test() + */ + @Test + public void testIndexesOnComplexPrimaryKey() throws Throwable + { + createTable("CREATE TABLE %s (pk0 int, pk1 int, ck0 int, ck1 int, ck2 int, value int, PRIMARY KEY ((pk0, pk1), ck0, ck1, ck2))"); + + execute("CREATE INDEX ON %s (pk0)"); + execute("CREATE INDEX ON %s (ck0)"); + execute("CREATE INDEX ON %s (ck1)"); + execute("CREATE INDEX ON %s (ck2)"); + + execute("INSERT INTO %s (pk0, pk1, ck0, ck1, ck2, value) VALUES (0, 1, 2, 3, 4, 5)"); + execute("INSERT INTO %s (pk0, pk1, ck0, ck1, ck2, value) VALUES (1, 2, 3, 4, 5, 0)"); + execute("INSERT INTO %s (pk0, pk1, ck0, ck1, ck2, value) VALUES (2, 3, 4, 5, 0, 1)"); + execute("INSERT INTO %s (pk0, pk1, ck0, ck1, ck2, value) VALUES (3, 4, 5, 0, 1, 2)"); + execute("INSERT INTO %s (pk0, pk1, ck0, ck1, ck2, value) VALUES (4, 5, 0, 1, 2, 3)"); + execute("INSERT INTO %s (pk0, pk1, ck0, ck1, ck2, value) VALUES (5, 0, 1, 2, 3, 4)"); + + assertRows(execute("SELECT value FROM %s WHERE pk0 = 2"), + row(1)); + + assertRows(execute("SELECT value FROM %s WHERE ck0 = 0"), + row(3)); + + assertRows(execute("SELECT value FROM %s WHERE pk0 = 3 AND pk1 = 4 AND ck1 = 0"), + row(2)); + + assertRows(execute("SELECT value FROM %s WHERE pk0 = 5 AND pk1 = 0 AND ck0 = 1 AND ck2 = 3 ALLOW FILTERING"), + row(4)); + } + + /** + * Test for CASSANDRA-5240, + * migrated from cql_tests.py:TestCQL.bug_5240_test() + */ + @Test + public void testIndexOnCompoundRowKey() throws Throwable + { + createTable("CREATE TABLE %s (interval text, seq int, id int, severity int, PRIMARY KEY ((interval, seq), id) ) WITH CLUSTERING ORDER BY (id DESC)"); + + execute("CREATE INDEX ON %s (severity)"); + + execute("insert into %s (interval, seq, id , severity) values('t',1, 1, 1)"); + execute("insert into %s (interval, seq, id , severity) values('t',1, 2, 1)"); + execute("insert into %s (interval, seq, id , severity) values('t',1, 3, 2)"); + execute("insert into %s (interval, seq, id , severity) values('t',1, 4, 3)"); + execute("insert into %s (interval, seq, id , severity) values('t',2, 1, 3)"); + execute("insert into %s (interval, seq, id , severity) values('t',2, 2, 3)"); + execute("insert into %s (interval, seq, id , severity) values('t',2, 3, 1)"); + execute("insert into %s (interval, seq, id , severity) values('t',2, 4, 2)"); + + assertRows(execute("select * from %s where severity = 3 and interval = 't' and seq =1"), + row("t", 1, 4, 3)); + } + + /** + * Migrated from cql_tests.py:TestCQL.secondary_index_counters() + */ + @Test + public void testIndexOnCountersInvalid() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, c counter)"); + assertInvalid("CREATE INDEX ON test(c)"); + } + + /** + * Migrated from cql_tests.py:TestCQL.collection_indexing_test() + */ + @Test + public void testIndexOnCollections() throws Throwable + { + createTable(" CREATE TABLE %s ( k int, v int, l list<int>, s set<text>, m map<text, int>, PRIMARY KEY (k, v))"); + + createIndex("CREATE INDEX ON %s (l)"); + createIndex("CREATE INDEX ON %s (s)"); + createIndex("CREATE INDEX ON %s (m)"); + + execute("INSERT INTO %s (k, v, l, s, m) VALUES (0, 0, [1, 2], {'a'}, {'a' : 1})"); + execute("INSERT INTO %s (k, v, l, s, m) VALUES (0, 1, [3, 4], {'b', 'c'}, {'a' : 1, 'b' : 2})"); + execute("INSERT INTO %s (k, v, l, s, m) VALUES (0, 2, [1], {'a', 'c'}, {'c' : 3})"); + execute("INSERT INTO %s (k, v, l, s, m) VALUES (1, 0, [1, 2, 4], {}, {'b' : 1})"); + execute("INSERT INTO %s (k, v, l, s, m) VALUES (1, 1, [4, 5], {'d'}, {'a' : 1, 'b' : 3})"); + + // lists + assertRows(execute("SELECT k, v FROM %s WHERE l CONTAINS 1"), row(1, 0), row(0, 0), row(0, 2)); + assertRows(execute("SELECT k, v FROM %s WHERE k = 0 AND l CONTAINS 1"), row(0, 0), row(0, 2)); + assertRows(execute("SELECT k, v FROM %s WHERE l CONTAINS 2"), row(1, 0), row(0, 0)); + assertEmpty(execute("SELECT k, v FROM %s WHERE l CONTAINS 6")); + + // sets + assertRows(execute("SELECT k, v FROM %s WHERE s CONTAINS 'a'"), row(0, 0), row(0, 2)); + assertRows(execute("SELECT k, v FROM %s WHERE k = 0 AND s CONTAINS 'a'"), row(0, 0), row(0, 2)); + assertRows(execute("SELECT k, v FROM %s WHERE s CONTAINS 'd'"), row(1, 1)); + assertEmpty(execute("SELECT k, v FROM %s WHERE s CONTAINS 'e'")); + + // maps + assertRows(execute("SELECT k, v FROM %s WHERE m CONTAINS 1"), row(1, 0), row(1, 1), row(0, 0), row(0, 1)); + assertRows(execute("SELECT k, v FROM %s WHERE k = 0 AND m CONTAINS 1"), row(0, 0), row(0, 1)); + assertRows(execute("SELECT k, v FROM %s WHERE m CONTAINS 2"), row(0, 1)); + assertEmpty(execute("SELECT k, v FROM %s WHERE m CONTAINS 4")); + } + + /** + * Migrated from cql_tests.py:TestCQL.map_keys_indexing() + */ + @Test + public void testIndexOnMapKeys() throws Throwable + { + createTable("CREATE TABLE %s (k int, v int, m map<text, int>, PRIMARY KEY (k, v))"); + + createIndex("CREATE INDEX ON %s(keys(m))"); + + execute("INSERT INTO %s (k, v, m) VALUES (0, 0, {'a' : 1})"); + execute("INSERT INTO %s (k, v, m) VALUES (0, 1, {'a' : 1, 'b' : 2})"); + execute("INSERT INTO %s (k, v, m) VALUES (0, 2, {'c' : 3})"); + execute("INSERT INTO %s (k, v, m) VALUES (1, 0, {'b' : 1})"); + execute("INSERT INTO %s (k, v, m) VALUES (1, 1, {'a' : 1, 'b' : 3})"); + + // maps + assertRows(execute("SELECT k, v FROM %s WHERE m CONTAINS KEY 'a'"), row(1, 1), row(0, 0), row(0, 1)); + assertRows(execute("SELECT k, v FROM %s WHERE k = 0 AND m CONTAINS KEY 'a'"), row(0, 0), row(0, 1)); + assertRows(execute("SELECT k, v FROM %s WHERE m CONTAINS KEY 'c'"), row(0, 2)); + assertEmpty(execute("SELECT k, v FROM %s WHERE m CONTAINS KEY 'd'")); + + // we're not allowed to create a value index if we already have a key one + assertInvalid("CREATE INDEX ON %s(m)"); + } + + /** + * Test for #6950 bug, + * migrated from cql_tests.py:TestCQL.key_index_with_reverse_clustering() + */ + @Test + public void testIndexOnKeyWithReverseClustering() throws Throwable + { + createTable(" CREATE TABLE %s (k1 int, k2 int, v int, PRIMARY KEY ((k1, k2), v) ) WITH CLUSTERING ORDER BY (v DESC)"); + + createIndex("CREATE INDEX ON %s (k2)"); + + execute("INSERT INTO %s (k1, k2, v) VALUES (0, 0, 1)"); + execute("INSERT INTO %s (k1, k2, v) VALUES (0, 1, 2)"); + execute("INSERT INTO %s (k1, k2, v) VALUES (0, 0, 3)"); + execute("INSERT INTO %s (k1, k2, v) VALUES (1, 0, 4)"); + execute("INSERT INTO %s (k1, k2, v) VALUES (1, 1, 5)"); + execute("INSERT INTO %s (k1, k2, v) VALUES (2, 0, 7)"); + execute("INSERT INTO %s (k1, k2, v) VALUES (2, 1, 8)"); + execute("INSERT INTO %s (k1, k2, v) VALUES (3, 0, 1)"); + + assertRows(execute("SELECT * FROM %s WHERE k2 = 0 AND v >= 2 ALLOW FILTERING"), + row(2, 0, 7), + row(0, 0, 3), + row(1, 0, 4)); + } + + /** + * Test for CASSANDRA-6612, + * migrated from cql_tests.py:TestCQL.bug_6612_test() + */ + @Test + public void testSelectCountOnIndexedColumn() throws Throwable + { + createTable("CREATE TABLE %s (username text, session_id text, app_name text, account text, last_access timestamp, created_on timestamp, PRIMARY KEY (username, session_id, app_name, account))"); + + createIndex("create index ON %s (app_name)"); + createIndex("create index ON %s (last_access)"); + + assertRows(execute("select count(*) from %s where app_name='foo' and account='bar' and last_access > 4 allow filtering"), row(0L)); + + execute("insert into %s (username, session_id, app_name, account, last_access, created_on) values ('toto', 'foo', 'foo', 'bar', 12, 13)"); + + assertRows(execute("select count(*) from %s where app_name='foo' and account='bar' and last_access > 4 allow filtering"), row(1L)); + } + + /** + * Test for CASSANDRA-5732, Can not query secondary index + * migrated from cql_tests.py:TestCQL.bug_5732_test(), + * which was executing with a row cache size of 100 MB + * and restarting the node, here we just cleanup the cache. + */ + @Test + public void testCanQuerySecondaryIndex() throws Throwable + { + String tableName = createTable("CREATE TABLE %s (k int PRIMARY KEY, v int,)"); + + execute("ALTER TABLE %s WITH CACHING='ALL'"); + execute("INSERT INTO %s (k,v) VALUES (0,0)"); + execute("INSERT INTO %s (k,v) VALUES (1,1)"); + + createIndex("CREATE INDEX testindex on %s (v)"); + assertTrue(waitForIndex(keyspace(), tableName, "testindex")); + + assertRows(execute("SELECT k FROM %s WHERE v = 0"), row(0)); + cleanupCache(); + assertRows(execute("SELECT k FROM %s WHERE v = 0"), row(0)); + } + + // CASSANDRA-8280/8081 + // reject updates with indexed values where value > 64k + @Test + public void testIndexOnCompositeValueOver64k() throws Throwable + { + createTable("CREATE TABLE %s(a int, b int, c blob, PRIMARY KEY (a))"); + createIndex("CREATE INDEX ON %s(c)"); + failInsert("INSERT INTO %s (a, b, c) VALUES (0, 0, ?)", ByteBuffer.allocate(TOO_BIG)); + } + + @Test + public void testIndexOnClusteringColumnInsertPartitionKeyAndClusteringsOver64k() throws Throwable + { + createTable("CREATE TABLE %s(a blob, b blob, c blob, d int, PRIMARY KEY (a, b, c))"); + createIndex("CREATE INDEX ON %s(b)"); + + // CompositeIndexOnClusteringKey creates index entries composed of the + // PK plus all of the non-indexed clustering columns from the primary row + // so we should reject where len(a) + len(c) > 65560 as this will form the + // total clustering in the index table + ByteBuffer a = ByteBuffer.allocate(100); + ByteBuffer b = ByteBuffer.allocate(10); + ByteBuffer c = ByteBuffer.allocate(FBUtilities.MAX_UNSIGNED_SHORT - 99); + + failInsert("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, 0)", a, b, c); + } + + @Test + public void testCompactTableWithValueOver64k() throws Throwable + { + createTable("CREATE TABLE %s(a int, b blob, PRIMARY KEY (a)) WITH COMPACT STORAGE"); + createIndex("CREATE INDEX ON %s(b)"); + failInsert("INSERT INTO %s (a, b) VALUES (0, ?)", ByteBuffer.allocate(TOO_BIG)); + } + + @Test + public void testIndexOnCollectionValueInsertPartitionKeyAndCollectionKeyOver64k() throws Throwable + { + createTable("CREATE TABLE %s(a blob , b map<blob, int>, PRIMARY KEY (a))"); + createIndex("CREATE INDEX ON %s(b)"); + + // A collection key > 64k by itself will be rejected from + // the primary table. + // To test index validation we need to ensure that + // len(b) < 64k, but len(a) + len(b) > 64k as that will + // form the clustering in the index table + ByteBuffer a = ByteBuffer.allocate(100); + ByteBuffer b = ByteBuffer.allocate(FBUtilities.MAX_UNSIGNED_SHORT - 100); + + failInsert("UPDATE %s SET b[?] = 0 WHERE a = ?", b, a); + } + + @Test + public void testIndexOnCollectionKeyInsertPartitionKeyAndClusteringOver64k() throws Throwable + { + createTable("CREATE TABLE %s(a blob, b blob, c map<blob, int>, PRIMARY KEY (a, b))"); + createIndex("CREATE INDEX ON %s(KEYS(c))"); + + // Basically the same as the case with non-collection clustering + // CompositeIndexOnCollectionKeyy creates index entries composed of the + // PK plus all of the clustering columns from the primary row, except the + // collection element - which becomes the partition key in the index table + ByteBuffer a = ByteBuffer.allocate(100); + ByteBuffer b = ByteBuffer.allocate(FBUtilities.MAX_UNSIGNED_SHORT - 100); + ByteBuffer c = ByteBuffer.allocate(10); + + failInsert("UPDATE %s SET c[?] = 0 WHERE a = ? and b = ?", c, a, b); + } + + @Test + public void testIndexOnPartitionKeyInsertValueOver64k() throws Throwable + { + createTable("CREATE TABLE %s(a int, b int, c blob, PRIMARY KEY ((a, b)))"); + createIndex("CREATE INDEX ON %s(a)"); + succeedInsert("INSERT INTO %s (a, b, c) VALUES (0, 0, ?)", ByteBuffer.allocate(TOO_BIG)); + } + + @Test + public void testIndexOnClusteringColumnInsertValueOver64k() throws Throwable + { + createTable("CREATE TABLE %s(a int, b int, c blob, PRIMARY KEY (a, b))"); + createIndex("CREATE INDEX ON %s(b)"); + succeedInsert("INSERT INTO %s (a, b, c) VALUES (0, 0, ?)", ByteBuffer.allocate(TOO_BIG)); + } + + @Test + public void testIndexOnFullCollectionEntryInsertCollectionValueOver64k() throws Throwable + { + createTable("CREATE TABLE %s(a int, b frozen<map<int, blob>>, PRIMARY KEY (a))"); + createIndex("CREATE INDEX ON %s(full(b))"); + Map<Integer, ByteBuffer> map = new HashMap(); + map.put(0, ByteBuffer.allocate(1024 * 65)); + failInsert("INSERT INTO %s (a, b) VALUES (0, ?)", map); + } + + public void failInsert(String insertCQL, Object...args) throws Throwable + { + try + { + execute(insertCQL, args); + fail("Expected statement to fail validation"); + } + catch (Exception e) + { + // as expected + } + } + + public void succeedInsert(String insertCQL, Object...args) throws Throwable + { + execute(insertCQL, args); + flush(); + } + + /** + * Migrated from cql_tests.py:TestCQL.clustering_indexing_test() + */ + @Test + public void testIndexesOnClustering() throws Throwable + { + createTable("CREATE TABLE %s ( id1 int, id2 int, author text, time bigint, v1 text, v2 text, PRIMARY KEY ((id1, id2), author, time))"); + + createIndex("CREATE INDEX ON %s (time)"); + execute("CREATE INDEX ON %s (id2)"); + + execute("INSERT INTO %s (id1, id2, author, time, v1, v2) VALUES(0, 0, 'bob', 0, 'A', 'A')"); + execute("INSERT INTO %s (id1, id2, author, time, v1, v2) VALUES(0, 0, 'bob', 1, 'B', 'B')"); + execute("INSERT INTO %s (id1, id2, author, time, v1, v2) VALUES(0, 1, 'bob', 2, 'C', 'C')"); + execute("INSERT INTO %s (id1, id2, author, time, v1, v2) VALUES(0, 0, 'tom', 0, 'D', 'D')"); + execute("INSERT INTO %s (id1, id2, author, time, v1, v2) VALUES(0, 1, 'tom', 1, 'E', 'E')"); + + assertRows(execute("SELECT v1 FROM %s WHERE time = 1"), + row("B"), row("E")); + + assertRows(execute("SELECT v1 FROM %s WHERE id2 = 1"), + row("C"), row("E")); + + assertRows(execute("SELECT v1 FROM %s WHERE id1 = 0 AND id2 = 0 AND author = 'bob' AND time = 0"), + row("A")); + + // Test for CASSANDRA-8206 + execute("UPDATE %s SET v2 = null WHERE id1 = 0 AND id2 = 0 AND author = 'bob' AND time = 1"); + + assertRows(execute("SELECT v1 FROM %s WHERE id2 = 0"), + row("A"), row("B"), row("D")); + + assertRows(execute("SELECT v1 FROM %s WHERE time = 1"), + row("B"), row("E")); + } + + /** + * Migrated from cql_tests.py:TestCQL.invalid_clustering_indexing_test() + */ + @Test + public void testIndexesOnClusteringInvalid() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY ((a, b))) WITH COMPACT STORAGE"); + assertInvalid("CREATE INDEX ON %s (a)"); + assertInvalid("CREATE INDEX ON %s (b)"); + + createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY (a, b)) WITH COMPACT STORAGE"); + assertInvalid("CREATE INDEX ON %s (a)"); + assertInvalid("CREATE INDEX ON %s (b)"); + assertInvalid("CREATE INDEX ON %s (c)"); + + createTable("CREATE TABLE %s (a int, b int, c int static , PRIMARY KEY (a, b))"); + assertInvalid("CREATE INDEX ON %s (c)"); + } + +}