mirror of https://github.com/apache/cassandra
Forbid SELECT restrictions and CREATE INDEX over non-frozen UDT columns
patch by Andrés de la Peña; reviewed by Benjamin Lerer for CASSANDRA-13247
This commit is contained in:
parent
a85eeefe88
commit
82d3cdcd6c
|
|
@ -1,4 +1,5 @@
|
|||
3.11.0
|
||||
* Forbid SELECT restrictions and CREATE INDEX over non-frozen UDT columns (CASSANDRA-13247)
|
||||
* Default logging we ship will incorrectly print "?:?" for "%F:%L" pattern (CASSANDRA-13317)
|
||||
* Possible AssertionError in UnfilteredRowIteratorWithLowerBound (CASSANDRA-13366)
|
||||
* Support unaligned memory access for AArch64 (CASSANDRA-13326)
|
||||
|
|
|
|||
|
|
@ -273,6 +273,12 @@ public final class SingleColumnRelation extends Relation
|
|||
checkTrue(isEQ(), "Only EQ relations are supported on map entries");
|
||||
}
|
||||
|
||||
// Non-frozen UDTs don't support any operator
|
||||
checkFalse(receiver.type.isUDT() && receiver.type.isMultiCell(),
|
||||
"Non-frozen UDT column '%s' (%s) cannot be restricted by any relation",
|
||||
receiver.name,
|
||||
receiver.type.asCQL3Type());
|
||||
|
||||
if (receiver.type.isCollection())
|
||||
{
|
||||
// We don't support relations against entire collections (unless they're frozen), like "numbers = {1, 2, 3}"
|
||||
|
|
|
|||
|
|
@ -134,6 +134,8 @@ public class CreateIndexStatement extends SchemaAlteringStatement
|
|||
validateIsSimpleIndexIfTargetColumnNotCollection(cd, target);
|
||||
validateTargetColumnIsMapIfIndexInvolvesKeys(isMap, target);
|
||||
}
|
||||
|
||||
checkFalse(cd.type.isUDT() && cd.type.isMultiCell(), "Secondary indexes are not supported on non-frozen UDTs");
|
||||
}
|
||||
|
||||
if (!Strings.isNullOrEmpty(indexName))
|
||||
|
|
|
|||
|
|
@ -1409,6 +1409,109 @@ public class SecondaryIndexTest extends CQLTester
|
|||
"CREATE INDEX ON %s (t)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexOnFrozenUDT() throws Throwable
|
||||
{
|
||||
String type = createType("CREATE TYPE %s (a int)");
|
||||
String tableName = createTable("CREATE TABLE %s (k int PRIMARY KEY, v frozen<" + type + ">)");
|
||||
|
||||
Object udt1 = userType("a", 1);
|
||||
Object udt2 = userType("a", 2);
|
||||
|
||||
execute("INSERT INTO %s (k, v) VALUES (?, ?)", 0, udt1);
|
||||
execute("CREATE INDEX idx ON %s (v)");
|
||||
execute("INSERT INTO %s (k, v) VALUES (?, ?)", 1, udt2);
|
||||
execute("INSERT INTO %s (k, v) VALUES (?, ?)", 1, udt1);
|
||||
assertTrue(waitForIndex(keyspace(), tableName, "idx"));
|
||||
|
||||
assertRows(execute("SELECT * FROM %s WHERE v = ?", udt1), row(1, udt1), row(0, udt1));
|
||||
assertEmpty(execute("SELECT * FROM %s WHERE v = ?", udt2));
|
||||
|
||||
execute("DELETE FROM %s WHERE k = 0");
|
||||
assertRows(execute("SELECT * FROM %s WHERE v = ?", udt1), row(1, udt1));
|
||||
|
||||
dropIndex("DROP INDEX %s.idx");
|
||||
assertInvalidMessage("Index 'idx' could not be found", "DROP INDEX " + KEYSPACE + ".idx");
|
||||
assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
|
||||
"SELECT * FROM %s WHERE v = ?", udt1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexOnFrozenCollectionOfUDT() throws Throwable
|
||||
{
|
||||
String type = createType("CREATE TYPE %s (a int)");
|
||||
String tableName = createTable("CREATE TABLE %s (k int PRIMARY KEY, v frozen<set<frozen<" + type + ">>>)");
|
||||
|
||||
Object udt1 = userType("a", 1);
|
||||
Object udt2 = userType("a", 2);
|
||||
|
||||
execute("INSERT INTO %s (k, v) VALUES (?, ?)", 1, set(udt1, udt2));
|
||||
assertInvalidMessage("Frozen collections only support full()", "CREATE INDEX idx ON %s (keys(v))");
|
||||
assertInvalidMessage("Frozen collections only support full()", "CREATE INDEX idx ON %s (values(v))");
|
||||
execute("CREATE INDEX idx ON %s (full(v))");
|
||||
|
||||
execute("INSERT INTO %s (k, v) VALUES (?, ?)", 2, set(udt2));
|
||||
assertTrue(waitForIndex(keyspace(), tableName, "idx"));
|
||||
|
||||
assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
|
||||
"SELECT * FROM %s WHERE v CONTAINS ?", udt1);
|
||||
|
||||
assertRows(execute("SELECT * FROM %s WHERE v = ?", set(udt1, udt2)), row(1, set(udt1, udt2)));
|
||||
assertRows(execute("SELECT * FROM %s WHERE v = ?", set(udt2)), row(2, set(udt2)));
|
||||
|
||||
execute("DELETE FROM %s WHERE k = 2");
|
||||
assertEmpty(execute("SELECT * FROM %s WHERE v = ?", set(udt2)));
|
||||
|
||||
dropIndex("DROP INDEX %s.idx");
|
||||
assertInvalidMessage("Index 'idx' could not be found", "DROP INDEX " + KEYSPACE + ".idx");
|
||||
assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
|
||||
"SELECT * FROM %s WHERE v CONTAINS ?", udt1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexOnNonFrozenCollectionOfFrozenUDT() throws Throwable
|
||||
{
|
||||
String type = createType("CREATE TYPE %s (a int)");
|
||||
String tableName = createTable("CREATE TABLE %s (k int PRIMARY KEY, v set<frozen<" + type + ">>)");
|
||||
|
||||
Object udt1 = userType("a", 1);
|
||||
Object udt2 = userType("a", 2);
|
||||
|
||||
execute("INSERT INTO %s (k, v) VALUES (?, ?)", 1, set(udt1));
|
||||
assertInvalidMessage("Cannot create index on keys of column v with non-map type",
|
||||
"CREATE INDEX idx ON %s (keys(v))");
|
||||
assertInvalidMessage("full() indexes can only be created on frozen collections",
|
||||
"CREATE INDEX idx ON %s (full(v))");
|
||||
execute("CREATE INDEX idx ON %s (values(v))");
|
||||
|
||||
execute("INSERT INTO %s (k, v) VALUES (?, ?)", 2, set(udt2));
|
||||
execute("UPDATE %s SET v = v + ? WHERE k = ?", set(udt2), 1);
|
||||
assertTrue(waitForIndex(keyspace(), tableName, "idx"));
|
||||
|
||||
assertRows(execute("SELECT * FROM %s WHERE v CONTAINS ?", udt1), row(1, set(udt1, udt2)));
|
||||
assertRows(execute("SELECT * FROM %s WHERE v CONTAINS ?", udt2), row(1, set(udt1, udt2)), row(2, set(udt2)));
|
||||
|
||||
execute("DELETE FROM %s WHERE k = 1");
|
||||
assertEmpty(execute("SELECT * FROM %s WHERE v CONTAINS ?", udt1));
|
||||
assertRows(execute("SELECT * FROM %s WHERE v CONTAINS ?", udt2), row(2, set(udt2)));
|
||||
|
||||
dropIndex("DROP INDEX %s.idx");
|
||||
assertInvalidMessage("Index 'idx' could not be found", "DROP INDEX " + KEYSPACE + ".idx");
|
||||
assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
|
||||
"SELECT * FROM %s WHERE v CONTAINS ?", udt1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexOnNonFrozenUDT() throws Throwable
|
||||
{
|
||||
String type = createType("CREATE TYPE %s (a int)");
|
||||
createTable("CREATE TABLE %s (k int PRIMARY KEY, v " + type + ")");
|
||||
assertInvalidMessage("Secondary indexes are not supported on non-frozen UDTs", "CREATE INDEX ON %s (v)");
|
||||
assertInvalidMessage("Non-collection columns support only simple indexes", "CREATE INDEX ON %s (keys(v))");
|
||||
assertInvalidMessage("Non-collection columns support only simple indexes", "CREATE INDEX ON %s (values(v))");
|
||||
assertInvalidMessage("full() indexes can only be created on frozen collections", "CREATE INDEX ON %s (full(v))");
|
||||
}
|
||||
|
||||
private ResultMessage.Prepared prepareStatement(String cql, boolean forThrift)
|
||||
{
|
||||
return QueryProcessor.prepare(String.format(cql, KEYSPACE, currentTable()),
|
||||
|
|
|
|||
|
|
@ -638,4 +638,28 @@ public class SelectSingleColumnRelationTest extends CQLTester
|
|||
assertInvalidMessage("Undefined column name d", "SELECT c AS d FROM %s WHERE d CONTAINS KEY 0");
|
||||
assertInvalidMessage("Undefined column name d", "SELECT d FROM %s WHERE a = 0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidNonFrozenUDTRelation() throws Throwable
|
||||
{
|
||||
String type = createType("CREATE TYPE %s (a int)");
|
||||
createTable("CREATE TABLE %s (a int PRIMARY KEY, b " + type + ")");
|
||||
Object udt = userType("a", 1);
|
||||
|
||||
// All operators
|
||||
String msg = "Non-frozen UDT column 'b' (" + type + ") cannot be restricted by any relation";
|
||||
assertInvalidMessage(msg, "SELECT * FROM %s WHERE b = ?", udt);
|
||||
assertInvalidMessage(msg, "SELECT * FROM %s WHERE b > ?", udt);
|
||||
assertInvalidMessage(msg, "SELECT * FROM %s WHERE b < ?", udt);
|
||||
assertInvalidMessage(msg, "SELECT * FROM %s WHERE b >= ?", udt);
|
||||
assertInvalidMessage(msg, "SELECT * FROM %s WHERE b <= ?", udt);
|
||||
assertInvalidMessage(msg, "SELECT * FROM %s WHERE b IN (?)", udt);
|
||||
assertInvalidMessage(msg, "SELECT * FROM %s WHERE b LIKE ?", udt);
|
||||
assertInvalidMessage("Unsupported \"!=\" relation: b != {a: 0}",
|
||||
"SELECT * FROM %s WHERE b != {a: 0}", udt);
|
||||
assertInvalidMessage("Unsupported restriction: b IS NOT NULL",
|
||||
"SELECT * FROM %s WHERE b IS NOT NULL", udt);
|
||||
assertInvalidMessage("Cannot use CONTAINS on non-collection column b",
|
||||
"SELECT * FROM %s WHERE b CONTAINS ?", udt);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue