Repository: cassandra Updated Branches: refs/heads/trunk a604b14bf -> 65a7088e7
http://git-wip-us.apache.org/repos/asf/cassandra/blob/65a7088e/src/java/org/apache/cassandra/cql3/statements/SingleColumnRestriction.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/statements/SingleColumnRestriction.java b/src/java/org/apache/cassandra/cql3/statements/SingleColumnRestriction.java deleted file mode 100644 index b6ca640..0000000 --- a/src/java/org/apache/cassandra/cql3/statements/SingleColumnRestriction.java +++ /dev/null @@ -1,486 +0,0 @@ -/* - * 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.statements; - -import org.apache.cassandra.cql3.*; -import org.apache.cassandra.exceptions.InvalidRequestException; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public abstract class SingleColumnRestriction implements Restriction -{ - public boolean isMultiColumn() - { - return false; - } - - public static class EQ extends SingleColumnRestriction implements Restriction.EQ - { - protected final Term value; - private final boolean onToken; - - public EQ(Term value, boolean onToken) - { - this.value = value; - this.onToken = onToken; - } - - public boolean usesFunction(String ksName, String functionName) - { - return value != null && value.usesFunction(ksName, functionName); - } - - public List<ByteBuffer> values(QueryOptions options) throws InvalidRequestException - { - return Collections.singletonList(value.bindAndGet(options)); - } - - public boolean isSlice() - { - return false; - } - - public boolean isEQ() - { - return true; - } - - public boolean isIN() - { - return false; - } - - public boolean isContains() - { - return false; - } - - public boolean isOnToken() - { - return onToken; - } - - public boolean canEvaluateWithSlices() - { - return true; - } - - @Override - public String toString() - { - return String.format("EQ(%s)%s", value, onToken ? "*" : ""); - } - } - - public static class InWithValues extends SingleColumnRestriction implements Restriction.IN - { - protected final List<Term> values; - - public InWithValues(List<Term> values) - { - this.values = values; - } - - public boolean usesFunction(String ksName, String functionName) - { - if (values != null) - for (Term value : values) - if (value != null && value.usesFunction(ksName, functionName)) - return true; - return false; - } - - public List<ByteBuffer> values(QueryOptions options) throws InvalidRequestException - { - List<ByteBuffer> buffers = new ArrayList<>(values.size()); - for (Term value : values) - buffers.add(value.bindAndGet(options)); - return buffers; - } - - public boolean canHaveOnlyOneValue() - { - return values.size() == 1; - } - - public boolean isSlice() - { - return false; - } - - public boolean isEQ() - { - return false; - } - - public boolean isIN() - { - return true; - } - - public boolean isContains() - { - return false; - } - - public boolean isOnToken() - { - return false; - } - - public boolean canEvaluateWithSlices() - { - return true; - } - - @Override - public String toString() - { - return String.format("IN(%s)", values); - } - } - - public static class InWithMarker extends SingleColumnRestriction implements Restriction.IN - { - protected final AbstractMarker marker; - - public InWithMarker(AbstractMarker marker) - { - this.marker = marker; - } - - public boolean usesFunction(String ksName, String functionName) - { - return false; - } - - public List<ByteBuffer> values(QueryOptions options) throws InvalidRequestException - { - Term.MultiItemTerminal lval = (Term.MultiItemTerminal)marker.bind(options); - if (lval == null) - throw new InvalidRequestException("Invalid null value for IN restriction"); - return lval.getElements(); - } - - public boolean canHaveOnlyOneValue() - { - return false; - } - - public boolean isSlice() - { - return false; - } - - public boolean isEQ() - { - return false; - } - - public boolean isIN() - { - return true; - } - - public boolean isContains() - { - return false; - } - - public boolean isOnToken() - { - return false; - } - - public boolean canEvaluateWithSlices() - { - return true; - } - - @Override - public String toString() - { - return "IN ?"; - } - } - - public static class Slice extends SingleColumnRestriction implements Restriction.Slice - { - protected final Term[] bounds; - protected final boolean[] boundInclusive; - protected final boolean onToken; - - public Slice(boolean onToken) - { - this.bounds = new Term[2]; - this.boundInclusive = new boolean[2]; - this.onToken = onToken; - } - - public boolean usesFunction(String ksName, String functionName) - { - for (Term value : bounds) - if (value != null && value.usesFunction(ksName, functionName)) - return true; - return false; - } - - public boolean isSlice() - { - return true; - } - - public boolean isEQ() - { - return false; - } - - public boolean isIN() - { - return false; - } - - public boolean isContains() - { - return false; - } - - public List<ByteBuffer> values(QueryOptions options) throws InvalidRequestException - { - throw new UnsupportedOperationException(); - } - - public boolean isOnToken() - { - return onToken; - } - - public boolean canEvaluateWithSlices() - { - return true; - } - - /** Returns true if the start or end bound (depending on the argument) is set, false otherwise */ - public boolean hasBound(Bound b) - { - return bounds[b.idx] != null; - } - - public ByteBuffer bound(Bound b, QueryOptions options) throws InvalidRequestException - { - return bounds[b.idx].bindAndGet(options); - } - - /** Returns true if the start or end bound (depending on the argument) is inclusive, false otherwise */ - public boolean isInclusive(Bound b) - { - return bounds[b.idx] == null || boundInclusive[b.idx]; - } - - public Operator getRelation(Bound eocBound, Bound inclusiveBound) - { - switch (eocBound) - { - case START: - return boundInclusive[inclusiveBound.idx] ? Operator.GTE : Operator.GT; - case END: - return boundInclusive[inclusiveBound.idx] ? Operator.LTE : Operator.LT; - } - throw new AssertionError(); - } - - public Operator getIndexOperator(Bound b) - { - switch (b) - { - case START: - return boundInclusive[b.idx] ? Operator.GTE : Operator.GT; - case END: - return boundInclusive[b.idx] ? Operator.LTE : Operator.LT; - } - throw new AssertionError(); - } - - public void setBound(ColumnIdentifier name, Operator operator, Term t) throws InvalidRequestException - { - Bound b; - boolean inclusive; - switch (operator) - { - case GT: - b = Bound.START; - inclusive = false; - break; - case GTE: - b = Bound.START; - inclusive = true; - break; - case LT: - b = Bound.END; - inclusive = false; - break; - case LTE: - b = Bound.END; - inclusive = true; - break; - default: - throw new AssertionError(); - } - - if (bounds[b.idx] != null) - throw new InvalidRequestException(String.format( - "More than one restriction was found for the %s bound on %s", b.name().toLowerCase(), name)); - - bounds[b.idx] = t; - boundInclusive[b.idx] = inclusive; - } - - @Override - public String toString() - { - return String.format("SLICE(%s %s, %s %s)%s", boundInclusive[0] ? ">=" : ">", - bounds[0], - boundInclusive[1] ? "<=" : "<", - bounds[1], - onToken ? "*" : ""); - } - } - - // This holds both CONTAINS and CONTAINS_KEY restriction because we might want to have both of them. - public static class Contains extends SingleColumnRestriction - { - private List<Term> values; // for CONTAINS - private List<Term> keys; // for CONTAINS_KEY - - public boolean usesFunction(String ksName, String functionName) - { - if (values != null) - for (Term value : values) - if (value != null && value.usesFunction(ksName, functionName)) - return true; - if (keys != null) - for (Term key : keys) - if (key != null && key.usesFunction(ksName, functionName)) - return true; - return false; - } - - public boolean hasContains() - { - return values != null; - } - - public boolean hasContainsKey() - { - return keys != null; - } - - public int numberOfValues() - { - return values == null ? 0 : values.size(); - } - - public int numberOfKeys() - { - return keys == null ? 0 : keys.size(); - } - - public void add(Term t, boolean isKey) - { - if (isKey) - addKey(t); - else - addValue(t); - } - - public void addValue(Term t) - { - if (values == null) - values = new ArrayList<>(); - values.add(t); - } - - public void addKey(Term t) - { - if (keys == null) - keys = new ArrayList<>(); - keys.add(t); - } - - public List<ByteBuffer> values(QueryOptions options) throws InvalidRequestException - { - if (values == null) - return Collections.emptyList(); - - List<ByteBuffer> buffers = new ArrayList<ByteBuffer>(values.size()); - for (Term value : values) - buffers.add(value.bindAndGet(options)); - return buffers; - } - - public List<ByteBuffer> keys(QueryOptions options) throws InvalidRequestException - { - if (keys == null) - return Collections.emptyList(); - - List<ByteBuffer> buffers = new ArrayList<ByteBuffer>(keys.size()); - for (Term value : keys) - buffers.add(value.bindAndGet(options)); - return buffers; - } - - public boolean isSlice() - { - return false; - } - - public boolean isEQ() - { - return false; - } - - public boolean isIN() - { - return false; - } - - public boolean isContains() - { - return true; - } - - public boolean isOnToken() - { - return false; - } - - public boolean canEvaluateWithSlices() - { - return false; - } - - @Override - public String toString() - { - return String.format("CONTAINS(values=%s, keys=%s)", values, keys); - } - } -} http://git-wip-us.apache.org/repos/asf/cassandra/blob/65a7088e/src/java/org/apache/cassandra/db/composites/Composites.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/composites/Composites.java b/src/java/org/apache/cassandra/db/composites/Composites.java index f6626e0..fa0df48 100644 --- a/src/java/org/apache/cassandra/db/composites/Composites.java +++ b/src/java/org/apache/cassandra/db/composites/Composites.java @@ -22,8 +22,11 @@ import java.util.List; import org.apache.cassandra.config.CFMetaData; import org.apache.cassandra.db.filter.ColumnSlice; -import org.apache.cassandra.utils.memory.AbstractAllocator; import org.apache.cassandra.utils.ByteBufferUtil; +import org.apache.cassandra.utils.memory.AbstractAllocator; + +import com.google.common.base.Function; +import com.google.common.collect.Lists; public abstract class Composites { @@ -31,6 +34,23 @@ public abstract class Composites public static final Composite EMPTY = new EmptyComposite(); + /** + * Converts the specified <code>Composites</code> into <code>ByteBuffer</code>s. + * + * @param composites the composites to convert. + * @return the <code>ByteBuffer</code>s corresponding to the specified <code>Composites</code>. + */ + public static List<ByteBuffer> toByteBuffers(List<Composite> composites) + { + return Lists.transform(composites, new Function<Composite, ByteBuffer>() + { + public ByteBuffer apply(Composite composite) + { + return composite.toByteBuffer(); + } + }); + } + static final CBuilder EMPTY_BUILDER = new CBuilder() { public int remainingCount() { return 0; } http://git-wip-us.apache.org/repos/asf/cassandra/blob/65a7088e/src/java/org/apache/cassandra/db/composites/CompositesBuilder.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/composites/CompositesBuilder.java b/src/java/org/apache/cassandra/db/composites/CompositesBuilder.java index 4542ac5..9a32dcc 100644 --- a/src/java/org/apache/cassandra/db/composites/CompositesBuilder.java +++ b/src/java/org/apache/cassandra/db/composites/CompositesBuilder.java @@ -20,6 +20,7 @@ package org.apache.cassandra.db.composites; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Comparator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; @@ -240,8 +241,8 @@ public final class CompositesBuilder if (elementsList.isEmpty()) return singletonList(builder.build().withEOC(eoc)); - // Use a TreeSet to sort and eliminate duplicates - Set<Composite> set = new TreeSet<Composite>(comparator); + // Use a Set to sort if needed and eliminate duplicates + Set<Composite> set = newSet(); for (int i = 0, m = elementsList.size(); i < m; i++) { @@ -252,6 +253,16 @@ public final class CompositesBuilder return new ArrayList<>(set); } + /** + * Returns a new <code>Set</code> instance that will be used to eliminate duplicates and sort the results. + * + * @return a new <code>Set</code> instance. + */ + private Set<Composite> newSet() + { + return comparator == null ? new LinkedHashSet<Composite>() : new TreeSet<Composite>(comparator); + } + private void checkUpdateable() { if (!hasRemaining() || built) http://git-wip-us.apache.org/repos/asf/cassandra/blob/65a7088e/src/java/org/apache/cassandra/db/marshal/CollectionType.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/marshal/CollectionType.java b/src/java/org/apache/cassandra/db/marshal/CollectionType.java index 24ad533..3121899 100644 --- a/src/java/org/apache/cassandra/db/marshal/CollectionType.java +++ b/src/java/org/apache/cassandra/db/marshal/CollectionType.java @@ -26,6 +26,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.cassandra.cql3.CQL3Type; +import org.apache.cassandra.cql3.ColumnSpecification; +import org.apache.cassandra.cql3.Lists; +import org.apache.cassandra.cql3.Maps; +import org.apache.cassandra.cql3.Sets; + import org.apache.cassandra.serializers.CollectionSerializer; import org.apache.cassandra.serializers.MarshalException; import org.apache.cassandra.utils.ByteBufferUtil; @@ -43,7 +48,29 @@ public abstract class CollectionType<T> extends AbstractType<T> public enum Kind { - MAP, SET, LIST + MAP + { + public ColumnSpecification makeCollectionReceiver(ColumnSpecification collection, boolean isKey) + { + return isKey ? Maps.keySpecOf(collection) : Maps.valueSpecOf(collection); + } + }, + SET + { + public ColumnSpecification makeCollectionReceiver(ColumnSpecification collection, boolean isKey) + { + return Sets.valueSpecOf(collection); + } + }, + LIST + { + public ColumnSpecification makeCollectionReceiver(ColumnSpecification collection, boolean isKey) + { + return Lists.valueSpecOf(collection); + } + }; + + public abstract ColumnSpecification makeCollectionReceiver(ColumnSpecification collection, boolean isKey); } public final Kind kind; @@ -59,6 +86,11 @@ public abstract class CollectionType<T> extends AbstractType<T> @Override public abstract CollectionSerializer<T> getSerializer(); + public ColumnSpecification makeCollectionReceiver(ColumnSpecification collection, boolean isKey) + { + return kind.makeCollectionReceiver(collection, isKey); + } + public String getString(ByteBuffer bytes) { return BytesType.instance.getString(bytes); http://git-wip-us.apache.org/repos/asf/cassandra/blob/65a7088e/src/java/org/apache/cassandra/exceptions/UnrecognizedEntityException.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/exceptions/UnrecognizedEntityException.java b/src/java/org/apache/cassandra/exceptions/UnrecognizedEntityException.java new file mode 100644 index 0000000..e8392e9 --- /dev/null +++ b/src/java/org/apache/cassandra/exceptions/UnrecognizedEntityException.java @@ -0,0 +1,49 @@ +/* + * 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.exceptions; + +import org.apache.cassandra.cql3.ColumnIdentifier; +import org.apache.cassandra.cql3.Relation; + +/** + * Exception thrown when an entity is not recognized within a relation. + */ +public final class UnrecognizedEntityException extends InvalidRequestException +{ + /** + * The unrecognized entity. + */ + public final ColumnIdentifier entity; + + /** + * The entity relation. + */ + public final Relation relation; + + /** + * Creates a new <code>UnrecognizedEntityException</code>. + * @param entity the unrecognized entity + * @param relation the entity relation + */ + public UnrecognizedEntityException(ColumnIdentifier entity, Relation relation) + { + super(String.format("Undefined name %s in where clause ('%s')", entity, relation)); + this.entity = entity; + this.relation = relation; + } +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/65a7088e/test/unit/org/apache/cassandra/cql3/AliasTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/AliasTest.java b/test/unit/org/apache/cassandra/cql3/AliasTest.java new file mode 100644 index 0000000..132aa04 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/AliasTest.java @@ -0,0 +1,40 @@ +/* + * 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; + +import org.junit.Test; + +public class AliasTest extends CQLTester +{ + @Test + public void testAlias() throws Throwable + { + createTable("CREATE TABLE %s (id int PRIMARY KEY, name text)"); + + for (int i = 0; i < 5; i++) + execute("INSERT INTO %s (id, name) VALUES (?, ?) USING TTL 10 AND TIMESTAMP 0", i, Integer.toString(i)); + + assertInvalidMessage("Aliases aren't allowed in the where clause" , + "SELECT id AS user_id, name AS user_name FROM %s WHERE user_id = 0"); + + // test that select throws a meaningful exception for aliases in order by clause + assertInvalidMessage("Aliases are not allowed in order by clause", + "SELECT id AS user_id, name AS user_name FROM %s WHERE id IN (0) ORDER BY user_name"); + + } +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/65a7088e/test/unit/org/apache/cassandra/cql3/ContainsRelationTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/ContainsRelationTest.java b/test/unit/org/apache/cassandra/cql3/ContainsRelationTest.java index 12d65fa..8f78553 100644 --- a/test/unit/org/apache/cassandra/cql3/ContainsRelationTest.java +++ b/test/unit/org/apache/cassandra/cql3/ContainsRelationTest.java @@ -26,7 +26,11 @@ public class ContainsRelationTest extends CQLTester row("test", 5, set("lmn")) ); - assertInvalid("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ? AND categories CONTAINS ?", "xyz", "lmn", "notPresent"); + assertInvalidMessage("Unsupported null value for indexed column categories", + "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, null); + + assertInvalidMessage("Cannot execute this query as it might involve data filtering and thus may have unpredictable performance. If you want to execute this query despite the performance unpredictability, use ALLOW FILTERING", + "SELECT * FROM %s WHERE account = ? AND categories CONTAINS ? AND categories CONTAINS ?", "xyz", "lmn", "notPresent"); assertEmpty(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ? AND categories CONTAINS ? ALLOW FILTERING", "xyz", "lmn", "notPresent")); } @@ -52,8 +56,12 @@ public class ContainsRelationTest extends CQLTester row("test", 5, list("lmn")) ); - assertInvalid("SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ? AND categories CONTAINS ?", - "test", 5, "lmn", "notPresent"); + assertInvalidMessage("Unsupported null value for indexed column categories", + "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, null); + + assertInvalidMessage("Cannot execute this query as it might involve data filtering and thus may have unpredictable performance. If you want to execute this query despite the performance unpredictability, use ALLOW FILTERING", + "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ? AND categories CONTAINS ?", + "test", 5, "lmn", "notPresent"); assertEmpty(execute("SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ? AND categories CONTAINS ? ALLOW FILTERING", "test", 5, "lmn", "notPresent")); } @@ -79,13 +87,18 @@ public class ContainsRelationTest extends CQLTester row("test", 5, map("lmn", "foo")) ); - assertInvalid("SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS KEY ? AND categories CONTAINS KEY ?", - "test", 5, "lmn", "notPresent"); + assertInvalidMessage("Unsupported null value for indexed column categories", + "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS KEY ?", "test", 5, null); + + assertInvalidMessage("Cannot execute this query as it might involve data filtering and thus may have unpredictable performance. If you want to execute this query despite the performance unpredictability, use ALLOW FILTERING", + "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS KEY ? AND categories CONTAINS KEY ?", + "test", 5, "lmn", "notPresent"); assertEmpty(execute("SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS KEY ? AND categories CONTAINS KEY ? ALLOW FILTERING", "test", 5, "lmn", "notPresent")); - assertInvalid("SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS KEY ? AND categories CONTAINS ?", - "test", 5, "lmn", "foo"); + assertInvalidMessage("Cannot execute this query as it might involve data filtering and thus may have unpredictable performance. If you want to execute this query despite the performance unpredictability, use ALLOW FILTERING", + "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS KEY ? AND categories CONTAINS ?", + "test", 5, "lmn", "foo"); } @Test @@ -110,7 +123,11 @@ public class ContainsRelationTest extends CQLTester row("test", 5, map("lmn", "foo")) ); - assertInvalid("SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ? AND categories CONTAINS ?" + assertInvalidMessage("Unsupported null value for indexed column categories", + "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, null); + + assertInvalidMessage("Cannot execute this query as it might involve data filtering and thus may have unpredictable performance. If you want to execute this query despite the performance unpredictability, use ALLOW FILTERING", + "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ? AND categories CONTAINS ?" , "test", 5, "foo", "notPresent"); assertEmpty(execute("SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ? AND categories CONTAINS ? ALLOW FILTERING" @@ -197,7 +214,8 @@ public class ContainsRelationTest extends CQLTester execute("INSERT INTO %s (account, id , categories) VALUES (?, ?, ?)", "test", 5, map("lmn", "foo")); execute("INSERT INTO %s (account, id , categories) VALUES (?, ?, ?)", "test", 6, map("lmn", "foo2")); - assertInvalid("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ?", "test", "foo"); + assertInvalidMessage("No secondary indexes on the restricted columns support the provided operators: 'categories CONTAINS <value>'", + "SELECT * FROM %s WHERE account = ? AND categories CONTAINS ?", "test", "foo"); assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS KEY ?", "test", "lmn"), row("test", 5, map("lmn", "foo")), @@ -219,7 +237,8 @@ public class ContainsRelationTest extends CQLTester execute("INSERT INTO %s (account, id , categories) VALUES (?, ?, ?)", "test", 5, map("lmn", "foo")); execute("INSERT INTO %s (account, id , categories) VALUES (?, ?, ?)", "test", 6, map("lmn2", "foo")); - assertInvalid("SELECT * FROM %s WHERE account = ? AND categories CONTAINS KEY ?", "test", "lmn"); + assertInvalidMessage("No secondary indexes on the restricted columns support the provided operators: 'categories CONTAINS KEY <value>'", + "SELECT * FROM %s WHERE account = ? AND categories CONTAINS KEY ?", "test", "lmn"); assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ?", "test", "foo"), row("test", 5, map("lmn", "foo")), http://git-wip-us.apache.org/repos/asf/cassandra/blob/65a7088e/test/unit/org/apache/cassandra/cql3/FrozenCollectionsTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/FrozenCollectionsTest.java b/test/unit/org/apache/cassandra/cql3/FrozenCollectionsTest.java index bf7ccfd..896bc5f 100644 --- a/test/unit/org/apache/cassandra/cql3/FrozenCollectionsTest.java +++ b/test/unit/org/apache/cassandra/cql3/FrozenCollectionsTest.java @@ -75,8 +75,8 @@ public class FrozenCollectionsTest extends CQLTester ); assertRows(execute("SELECT * FROM %s WHERE k IN ?", list(set(4, 5, 6), set())), - row(set(4, 5, 6), 0), - row(set(), 0) + row(set(), 0), + row(set(4, 5, 6), 0) ); assertRows(execute("SELECT * FROM %s WHERE token(k) >= token(?)", set(4, 5, 6)), @@ -144,9 +144,9 @@ public class FrozenCollectionsTest extends CQLTester ); 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) + row(map(), 0), + row(map(set(), list(1, 2, 3)), 0), + row(map(set(4, 5, 6), list(1, 2, 3)), 0) ); assertRows(execute("SELECT * FROM %s WHERE token(k) >= token(?)", map(set(4, 5, 6), list(1, 2, 3))), @@ -615,10 +615,10 @@ public class FrozenCollectionsTest extends CQLTester "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", + assertInvalidMessage("Cannot restrict clustering columns 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", + assertInvalidMessage("Cannot restrict clustering columns 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", @@ -627,7 +627,7 @@ public class FrozenCollectionsTest extends CQLTester 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", + assertInvalidMessage("Cannot restrict clustering columns 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 http://git-wip-us.apache.org/repos/asf/cassandra/blob/65a7088e/test/unit/org/apache/cassandra/cql3/MultiColumnRelationTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/MultiColumnRelationTest.java b/test/unit/org/apache/cassandra/cql3/MultiColumnRelationTest.java index 4c3ba2a..291afd8 100644 --- a/test/unit/org/apache/cassandra/cql3/MultiColumnRelationTest.java +++ b/test/unit/org/apache/cassandra/cql3/MultiColumnRelationTest.java @@ -24,56 +24,77 @@ public class MultiColumnRelationTest extends CQLTester @Test public void testSingleClusteringInvalidQueries() throws Throwable { - for (String compactOption : new String[]{"", " WITH COMPACT STORAGE"}) + for (String compactOption : new String[] { "", " WITH COMPACT STORAGE" }) { createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY (a, b))" + compactOption); assertInvalidSyntax("SELECT * FROM %s WHERE () = (?, ?)", 1, 2); - assertInvalid("SELECT * FROM %s WHERE a = 0 AND (b) = (?) AND (b) > (?)", 0, 0); - assertInvalid("SELECT * FROM %s WHERE a = 0 AND (b) > (?) AND (b) > (?)", 0, 1); - assertInvalid("SELECT * FROM %s WHERE (a, b) = (?, ?)", 0, 0); + assertInvalidMessage("b cannot be restricted by more than one relation if it includes an Equal", + "SELECT * FROM %s WHERE a = 0 AND (b) = (?) AND (b) > (?)", 0, 0); + assertInvalidMessage("More than one restriction was found for the start bound on b", + "SELECT * FROM %s WHERE a = 0 AND (b) > (?) AND (b) > (?)", 0, 1); + assertInvalidMessage("Multi-column relations can only be applied to clustering columns but was applied to: a", + "SELECT * FROM %s WHERE (a, b) = (?, ?)", 0, 0); } } @Test public void testMultiClusteringInvalidQueries() throws Throwable { - for (String compactOption : new String[]{"", " WITH COMPACT STORAGE"}) + for (String compactOption : new String[] { "", " WITH COMPACT STORAGE" }) { createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY (a, b, c, d))" + compactOption); assertInvalidSyntax("SELECT * FROM %s WHERE a = 0 AND (b, c) > ()"); - assertInvalid("SELECT * FROM %s WHERE a = 0 AND (b, c) > (?, ?, ?)", 1, 2, 3); - assertInvalid("SELECT * FROM %s WHERE a = 0 AND (b, c) > (?, ?)", 1, null); + assertInvalidMessage("Expected 2 elements in value tuple, but got 3: (?, ?, ?)", + "SELECT * FROM %s WHERE a = 0 AND (b, c) > (?, ?, ?)", 1, 2, 3); + assertInvalidMessage("Invalid null value in condition for column c", + "SELECT * FROM %s WHERE a = 0 AND (b, c) > (?, ?)", 1, null); // Wrong order of columns - assertInvalid("SELECT * FROM %s WHERE a = 0 AND (d, c, b) = (?, ?, ?)", 0, 0, 0); - assertInvalid("SELECT * FROM %s WHERE a = 0 AND (d, c, b) > (?, ?, ?)", 0, 0, 0); + assertInvalidMessage("Clustering columns may not be skipped in multi-column relations. They should appear in the PRIMARY KEY order. Got (d, c, b) = (?, ?, ?)", + "SELECT * FROM %s WHERE a = 0 AND (d, c, b) = (?, ?, ?)", 0, 0, 0); + assertInvalidMessage("Clustering columns may not be skipped in multi-column relations. They should appear in the PRIMARY KEY order. Got (d, c, b) > (?, ?, ?)", + "SELECT * FROM %s WHERE a = 0 AND (d, c, b) > (?, ?, ?)", 0, 0, 0); // Wrong number of values - assertInvalid("SELECT * FROM %s WHERE a=0 AND (b, c, d) IN ((?, ?))", 0, 1); - assertInvalid("SELECT * FROM %s WHERE a=0 AND (b, c, d) IN ((?, ?, ?, ?, ?))", 0, 1, 2, 3, 4); + assertInvalidMessage("Expected 3 elements in value tuple, but got 2: (?, ?)", + "SELECT * FROM %s WHERE a=0 AND (b, c, d) IN ((?, ?))", 0, 1); + assertInvalidMessage("Expected 3 elements in value tuple, but got 5: (?, ?, ?, ?, ?)", + "SELECT * FROM %s WHERE a=0 AND (b, c, d) IN ((?, ?, ?, ?, ?))", 0, 1, 2, 3, 4); // Missing first clustering column - assertInvalid("SELECT * FROM %s WHERE a = 0 AND (c, d) = (?, ?)", 0, 0); - assertInvalid("SELECT * FROM %s WHERE a = 0 AND (c, d) > (?, ?)", 0, 0); + assertInvalidMessage("Clustering columns may not be skipped in multi-column relations. They should appear in the PRIMARY KEY order. Got (c, d) = (?, ?)", + "SELECT * FROM %s WHERE a = 0 AND (c, d) = (?, ?)", 0, 0); + assertInvalidMessage("Clustering columns may not be skipped in multi-column relations. They should appear in the PRIMARY KEY order. Got (c, d) > (?, ?)", + "SELECT * FROM %s WHERE a = 0 AND (c, d) > (?, ?)", 0, 0); // Nulls - assertInvalid("SELECT * FROM %s WHERE a = 0 AND (b, c, d) IN ((?, ?, ?))", 1, 2, null); + assertInvalidMessage("Invalid null value in condition for column d", + "SELECT * FROM %s WHERE a = 0 AND (b, c, d) IN ((?, ?, ?))", 1, 2, null); // Wrong type for 'd' assertInvalid("SELECT * FROM %s WHERE a = 0 AND (b, c, d) = (?, ?, ?)", 1, 2, "foobar"); - assertInvalid("SELECT * FROM %s WHERE a = 0 AND b = (?, ?, ?)", 1, 2, 3); // Mix single and tuple inequalities - assertInvalid("SELECT * FROM %s WHERE a = 0 AND (b, c, d) > (?, ?, ?) AND b < ?", 0, 1, 0, 1); - assertInvalid("SELECT * FROM %s WHERE a = 0 AND (b, c, d) > (?, ?, ?) AND c < ?", 0, 1, 0, 1); - assertInvalid("SELECT * FROM %s WHERE a = 0 AND b > ? AND (b, c, d) < (?, ?, ?)", 1, 1, 1, 0); - assertInvalid("SELECT * FROM %s WHERE a = 0 AND c > ? AND (b, c, d) < (?, ?, ?)", 1, 1, 1, 0); - - assertInvalid("SELECT * FROM %s WHERE (a, b, c, d) IN ((?, ?, ?, ?))", 0, 1, 2, 3); - assertInvalid("SELECT * FROM %s WHERE (c, d) IN ((?, ?))", 0, 1); + assertInvalidMessage("Mixing single column relations and multi column relations on clustering columns is not allowed", + "SELECT * FROM %s WHERE a = 0 AND (b, c, d) > (?, ?, ?) AND b < ?", 0, 1, 0, 1); + assertInvalidMessage("Mixing single column relations and multi column relations on clustering columns is not allowed", + "SELECT * FROM %s WHERE a = 0 AND (b, c, d) > (?, ?, ?) AND c < ?", 0, 1, 0, 1); + assertInvalidMessage("Mixing single column relations and multi column relations on clustering columns is not allowed", + "SELECT * FROM %s WHERE a = 0 AND b > ? AND (b, c, d) < (?, ?, ?)", 1, 1, 1, 0); + assertInvalidMessage("Mixing single column relations and multi column relations on clustering columns is not allowed", + "SELECT * FROM %s WHERE a = 0 AND c > ? AND (b, c, d) < (?, ?, ?)", 1, 1, 1, 0); + + assertInvalidMessage("Multi-column relations can only be applied to clustering columns but was applied to: a", + "SELECT * FROM %s WHERE (a, b, c, d) IN ((?, ?, ?, ?))", 0, 1, 2, 3); + assertInvalidMessage("Clustering columns may not be skipped in multi-column relations. They should appear in the PRIMARY KEY order. Got (c, d) IN ((?, ?))", + "SELECT * FROM %s WHERE (c, d) IN ((?, ?))", 0, 1); + + assertInvalidMessage("Mixing single column relations and multi column relations on clustering columns is not allowed", + "SELECT * FROM %s WHERE a = ? AND (b, c) in ((?, ?), (?, ?)) AND d > ?", + 0, 0, 0, 0, 0, 0); assertInvalid("SELECT * FROM %s WHERE a = ? AND (b, c) in ((?, ?), (?, ?)) AND d > ?", 0, 0, 0, 0, 0, 0); } @@ -85,10 +106,12 @@ public class MultiColumnRelationTest extends CQLTester for (String compactOption : new String[]{"", " WITH COMPACT STORAGE"}) { createTable("CREATE TABLE %s (a int PRIMARY KEY, b int)" + compactOption); - - assertInvalid("SELECT * FROM %s WHERE (a) > (?)", 0); - assertInvalid("SELECT * FROM %s WHERE (a) = (?)", 0); - assertInvalid("SELECT * FROM %s WHERE (b) = (?)", 0); + assertInvalidMessage("Multi-column relations can only be applied to clustering columns but was applied to: a", + "SELECT * FROM %s WHERE (a) > (?)", 0); + assertInvalidMessage("Multi-column relations can only be applied to clustering columns but was applied to: a", + "SELECT * FROM %s WHERE (a) = (?)", 0); + assertInvalidMessage("Multi-column relations can only be applied to clustering columns but was applied to: b", + "SELECT * FROM %s WHERE (b) = (?)", 0); } } @@ -150,7 +173,8 @@ public class MultiColumnRelationTest extends CQLTester for (String compactOption : new String[]{"", " WITH COMPACT STORAGE"}) { createTable("CREATE TABLE %s (a int PRIMARY KEY, b int)" + compactOption); - assertInvalid("SELECT * FROM %s WHERE a = 0 AND (b) != (0)"); + assertInvalidMessage("Unsupported \"!=\" relation: (b) != (0)", + "SELECT * FROM %s WHERE a = 0 AND (b) != (0)"); } } @@ -444,10 +468,10 @@ public class MultiColumnRelationTest extends CQLTester // same query, but reversed order for the IN values assertRows(execute("SELECT * FROM %s WHERE a IN (?, ?) AND (b, c, d) IN (?, ?)", 1, 0, tuple(0, 1, 1), tuple(0, 1, 0)), - row(1, 0, 1, 0), - row(1, 0, 1, 1), row(0, 0, 1, 0), - row(0, 0, 1, 1) + row(0, 0, 1, 1), + row(1, 0, 1, 0), + row(1, 0, 1, 1) ); assertRows(execute("SELECT * FROM %s WHERE a IN (?, ?) and (b, c) IN ((?, ?))", 0, 1, 0, 1), @@ -555,4 +579,81 @@ public class MultiColumnRelationTest extends CQLTester assertEmpty(execute("SELECT * FROM %s WHERE a = ? AND (b, c) > (?, ?)", 0, 1, 0)); } } + + @Test + public void testMultipleClusteringWithIndex() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, d int, e int, PRIMARY KEY (a, b, c, d))"); + createIndex("CREATE INDEX ON %s (b)"); + createIndex("CREATE INDEX ON %s (e)"); + + execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 0, 0, 0, 0); + execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 0, 1, 0, 1); + execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 0, 1, 1, 2); + + execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 1, 0, 0, 0); + execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 1, 1, 0, 1); + execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 1, 1, 1, 2); + + execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 2, 0, 0, 0); + + assertRows(execute("SELECT * FROM %s WHERE (b) = (?)", 1), + row(0, 1, 0, 0, 0), + row(0, 1, 1, 0, 1), + row(0, 1, 1, 1, 2)); + + assertRows(execute("SELECT * FROM %s WHERE (b, c) = (?, ?) ALLOW FILTERING", 1, 1), + row(0, 1, 1, 0, 1), + row(0, 1, 1, 1, 2)); + + assertRows(execute("SELECT * FROM %s WHERE (b, c) = (?, ?) AND e = ? ALLOW FILTERING", 1, 1, 2), + row(0, 1, 1, 1, 2)); + + assertRows(execute("SELECT * FROM %s WHERE (b) IN ((?)) AND e = ? ALLOW FILTERING", 1, 2), + row(0, 1, 1, 1, 2)); + + assertInvalidMessage("IN restrictions are not supported on indexed columns", + "SELECT * FROM %s WHERE (b) IN ((?), (?)) AND e = ? ALLOW FILTERING", 0, 1, 2); + + assertInvalidMessage("IN restrictions are not supported on indexed columns", + "SELECT * FROM %s WHERE (b, c) IN ((?, ?)) AND e = ? ALLOW FILTERING", 0, 1, 2); + + assertInvalidMessage("IN restrictions are not supported on indexed columns", + "SELECT * FROM %s WHERE (b, c) IN ((?, ?), (?, ?)) AND e = ? ALLOW FILTERING", 0, 1, 1, 1, 2); + + assertInvalidMessage("Slice restrictions are not supported on indexed columns which are part of a multi column relation", + "SELECT * FROM %s WHERE (b) >= (?) AND e = ? ALLOW FILTERING", 1, 2); + } + + @Test + public void testMultiplePartitionKeyAndMultiClusteringWithIndex() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, d int, e int, PRIMARY KEY ((a, b), c, d, e))"); + createIndex("CREATE INDEX ON %s (c)"); + + execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 0, 0, 0, 0); + execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 0, 0, 1, 0); + execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 0, 0, 1, 1); + + execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 0, 1, 0, 0); + execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 0, 1, 1, 0); + execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 0, 1, 1, 1); + + execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 0, 2, 0, 0); + + assertRows(execute("SELECT * FROM %s WHERE a = ? AND (c) = (?) ALLOW FILTERING", 0, 1), + row(0, 0, 1, 0, 0), + row(0, 0, 1, 1, 0), + row(0, 0, 1, 1, 1)); + + assertRows(execute("SELECT * FROM %s WHERE a = ? AND (c, d) = (?, ?) ALLOW FILTERING", 0, 1, 1), + row(0, 0, 1, 1, 0), + row(0, 0, 1, 1, 1)); + + assertInvalidMessage("Partition key parts: b must be restricted as other parts are", + "SELECT * FROM %s WHERE a = ? AND (c, d) IN ((?, ?)) ALLOW FILTERING", 0, 1, 1); + + assertInvalidMessage("Partition key parts: b must be restricted as other parts are", + "SELECT * FROM %s WHERE a = ? AND (c, d) >= (?, ?) ALLOW FILTERING", 0, 1, 1); + } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/65a7088e/test/unit/org/apache/cassandra/cql3/SelectWithTokenFunctionTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/SelectWithTokenFunctionTest.java b/test/unit/org/apache/cassandra/cql3/SelectWithTokenFunctionTest.java index 6f9f5e2..39b62e3 100644 --- a/test/unit/org/apache/cassandra/cql3/SelectWithTokenFunctionTest.java +++ b/test/unit/org/apache/cassandra/cql3/SelectWithTokenFunctionTest.java @@ -30,17 +30,34 @@ public class SelectWithTokenFunctionTest extends CQLTester assertRows(execute("SELECT * FROM %s WHERE token(a) >= token(?)", 0), row(0, "a")); assertRows(execute("SELECT * FROM %s WHERE token(a) >= token(?) and token(a) < token(?)", 0, 1), row(0, "a")); assertInvalid("SELECT * FROM %s WHERE token(a) > token(?)", "a"); - assertInvalid("SELECT * FROM %s WHERE token(a, b) >= token(?, ?)", "b", 0); - assertInvalid("SELECT * FROM %s WHERE token(a) >= token(?) and token(a) >= token(?)", 0, 1); - assertInvalid("SELECT * FROM %s WHERE token(a) >= token(?) and token(a) = token(?)", 0, 1); + assertInvalidMessage("Columns \"a\" cannot be restricted by both a normal relation and a token relation", + "SELECT * FROM %s WHERE token(a) > token(?) AND a = ?", 1, 1); + assertInvalidMessage("Columns \"a\" cannot be restricted by both a normal relation and a token relation", + "SELECT * FROM %s WHERE a = ? and token(a) > token(?)", 1, 1); + assertInvalidMessage("The token() function must contains only partition key components", + "SELECT * FROM %s WHERE token(a, b) >= token(?, ?)", "b", 0); + assertInvalidMessage("More than one restriction was found for the start bound on a", + "SELECT * FROM %s WHERE token(a) >= token(?) and token(a) >= token(?)", 0, 1); + assertInvalidMessage("Columns \"a\" cannot be restricted by both an equality and an inequality relation", + "SELECT * FROM %s WHERE token(a) >= token(?) and token(a) = token(?)", 0, 1); assertInvalidSyntax("SELECT * FROM %s WHERE token(a) = token(?) and token(a) IN (token(?))", 0, 1); + + assertInvalidMessage("More than one restriction was found for the start bound on a", + "SELECT * FROM %s WHERE token(a) > token(?) AND token(a) > token(?)", 1, 2); + assertInvalidMessage("More than one restriction was found for the end bound on a", + "SELECT * FROM %s WHERE token(a) <= token(?) AND token(a) < token(?)", 1, 2); + assertInvalidMessage("Columns \"a\" cannot be restricted by both an equality and an inequality relation", + "SELECT * FROM %s WHERE token(a) > token(?) AND token(a) = token(?)", 1, 2); + assertInvalidMessage("a cannot be restricted by more than one relation if it includes an Equal", + "SELECT * FROM %s WHERE token(a) = token(?) AND token(a) > token(?)", 1, 2); } @Test public void testTokenFunctionWithPartitionKeyAndClusteringKeyArguments() throws Throwable { createTable("CREATE TABLE IF NOT EXISTS %s (a int, b text, PRIMARY KEY (a, b))"); - assertInvalid("SELECT * FROM %s WHERE token(a, b) > token(0, 'c')"); + assertInvalidMessage("The token() function must contains only partition key components", + "SELECT * FROM %s WHERE token(a, b) > token(0, 'c')"); } @Test @@ -59,8 +76,16 @@ public class SelectWithTokenFunctionTest extends CQLTester 0, "d"), row(0, "b"), row(0, "c")); - assertInvalid("SELECT * FROM %s WHERE token(a) > token(?) and token(b) > token(?)", 0, "a"); - assertInvalid("SELECT * FROM %s WHERE token(a) > token(?, ?) and token(a) < token(?, ?) and token(b) > token(?, ?) ", 0, "a", 0, "d", 0, "a"); - assertInvalid("SELECT * FROM %s WHERE token(b, a) > token(0, 'c')"); + assertInvalidMessage("The token() function must be applied to all partition key components or none of them", + "SELECT * FROM %s WHERE token(a) > token(?) and token(b) > token(?)", 0, "a"); + assertInvalidMessage("The token() function must be applied to all partition key components or none of them", + "SELECT * FROM %s WHERE token(a) > token(?, ?) and token(a) < token(?, ?) and token(b) > token(?, ?) ", + 0, "a", 0, "d", 0, "a"); + assertInvalidMessage("The token function arguments must be in the partition key order: a, b", + "SELECT * FROM %s WHERE token(b, a) > token(0, 'c')"); + assertInvalidMessage("The token() function must be applied to all partition key components or none of them", + "SELECT * FROM %s WHERE token(a, b) > token(?, ?) and token(b) < token(?, ?)", 0, "a", 0, "a"); + assertInvalidMessage("The token() function must be applied to all partition key components or none of them", + "SELECT * FROM %s WHERE token(a) > token(?, ?) and token(b) > token(?, ?)", 0, "a", 0, "a"); } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/65a7088e/test/unit/org/apache/cassandra/cql3/SingleColumnRelationTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/SingleColumnRelationTest.java b/test/unit/org/apache/cassandra/cql3/SingleColumnRelationTest.java index c93147b..112da06 100644 --- a/test/unit/org/apache/cassandra/cql3/SingleColumnRelationTest.java +++ b/test/unit/org/apache/cassandra/cql3/SingleColumnRelationTest.java @@ -31,9 +31,12 @@ public class SingleColumnRelationTest extends CQLTester createIndex("CREATE INDEX ON %s (c)"); createIndex("CREATE INDEX ON %s (d)"); - assertInvalid("SELECT * FROM %s WHERE a = 0 AND b=?", set(0)); - assertInvalid("SELECT * FROM %s WHERE a = 0 AND c=?", list(0)); - assertInvalid("SELECT * FROM %s WHERE a = 0 AND d=?", map(0, 0)); + assertInvalidMessage("Collection column 'b' (set<int>) cannot be restricted by a '=' relation", + "SELECT * FROM %s WHERE a = 0 AND b=?", set(0)); + assertInvalidMessage("Collection column 'c' (list<int>) cannot be restricted by a '=' relation", + "SELECT * FROM %s WHERE a = 0 AND c=?", list(0)); + assertInvalidMessage("Collection column 'd' (map<int, int>) cannot be restricted by a '=' relation", + "SELECT * FROM %s WHERE a = 0 AND d=?", map(0, 0)); } @Test @@ -44,11 +47,16 @@ public class SingleColumnRelationTest extends CQLTester execute("INSERT INTO %s (a, b, c) VALUES (0, {0}, 0)"); // non-EQ operators - assertInvalid("SELECT * FROM %s WHERE c = 0 AND b > ?", set(0)); - assertInvalid("SELECT * FROM %s WHERE c = 0 AND b >= ?", set(0)); - assertInvalid("SELECT * FROM %s WHERE c = 0 AND b < ?", set(0)); - assertInvalid("SELECT * FROM %s WHERE c = 0 AND b <= ?", set(0)); - assertInvalid("SELECT * FROM %s WHERE c = 0 AND b IN (?)", set(0)); + assertInvalidMessage("Collection column 'b' (set<int>) cannot be restricted by a '>' relation", + "SELECT * FROM %s WHERE c = 0 AND b > ?", set(0)); + assertInvalidMessage("Collection column 'b' (set<int>) cannot be restricted by a '>=' relation", + "SELECT * FROM %s WHERE c = 0 AND b >= ?", set(0)); + assertInvalidMessage("Collection column 'b' (set<int>) cannot be restricted by a '<' relation", + "SELECT * FROM %s WHERE c = 0 AND b < ?", set(0)); + assertInvalidMessage("Collection column 'b' (set<int>) cannot be restricted by a '<=' relation", + "SELECT * FROM %s WHERE c = 0 AND b <= ?", set(0)); + assertInvalidMessage("Collection column 'b' (set<int>) cannot be restricted by a 'IN' relation", + "SELECT * FROM %s WHERE c = 0 AND b IN (?)", set(0)); } @Test @@ -114,7 +122,8 @@ public class SingleColumnRelationTest extends CQLTester row("first", 2, 6, 2), row("first", 3, 7, 3)); - assertInvalid("select * from %s where a = ? and b in ? and c in ?", "first", null, Arrays.asList(7, 6)); + assertInvalidMessage("Invalid null value for IN restriction", + "select * from %s where a = ? and b in ? and c in ?", "first", null, Arrays.asList(7, 6)); assertRows(execute("select * from %s where a = ? and c >= ? and b in (?, ?)", "first", 6, 3, 2), row("first", 2, 6, 2), @@ -128,11 +137,32 @@ public class SingleColumnRelationTest extends CQLTester assertRows(execute("select * from %s where a = ? and c < ? and b in (?, ?)", "first", 7, 3, 2), row("first", 2, 6, 2)); +//--- + assertRows(execute("select * from %s where a = ? and c >= ? and c <= ? and b in (?, ?)", "first", 6, 7, 3, 2), + row("first", 2, 6, 2), + row("first", 3, 7, 3)); + + assertRows(execute("select * from %s where a = ? and c > ? and c <= ? and b in (?, ?)", "first", 6, 7, 3, 2), + row("first", 3, 7, 3)); + + assertEmpty(execute("select * from %s where a = ? and c > ? and c < ? and b in (?, ?)", "first", 6, 7, 3, 2)); + + assertInvalidMessage("Column \"c\" cannot be restricted by both an equality and an inequality relation", + "select * from %s where a = ? and c > ? and c = ? and b in (?, ?)", "first", 6, 7, 3, 2); + + assertInvalidMessage("c cannot be restricted by more than one relation if it includes an Equal", + "select * from %s where a = ? and c = ? and c > ? and b in (?, ?)", "first", 6, 7, 3, 2); assertRows(execute("select * from %s where a = ? and c in (?, ?) and b in (?, ?) order by b DESC", "first", 7, 6, 3, 2), row("first", 3, 7, 3), row("first", 2, 6, 2)); + + assertInvalidMessage("More than one restriction was found for the start bound on b", + "select * from %s where a = ? and b > ? and b > ?", "first", 6, 3, 2); + + assertInvalidMessage("More than one restriction was found for the end bound on b", + "select * from %s where a = ? and b < ? and b <= ?", "first", 6, 3, 2); } @Test @@ -144,8 +174,16 @@ public class SingleColumnRelationTest extends CQLTester execute("insert into %s (a, b, c, d) values (?, ?, ?, ?)", "first", 3, 3, 3); execute("insert into %s (a, b, c, d) values (?, ?, ?, ?)", "second", 4, 4, 4); - assertInvalid("select * from %s where a in (?, ?)", "first", "second"); - assertInvalid("select * from %s where a in (?, ?) and b in (?, ?)", "first", "second", 2, 3); + assertInvalidMessage("Partition KEY part a cannot be restricted by IN relation (only the last part of the partition key can)", + "select * from %s where a in (?, ?)", "first", "second"); + assertInvalidMessage("Partition KEY part a cannot be restricted by IN relation (only the last part of the partition key can)", + "select * from %s where a in (?, ?) and b in (?, ?)", "first", "second", 2, 3); + assertInvalidMessage("Partition key parts: b must be restricted as other parts are", + "select * from %s where a = ?", "first"); + assertInvalidMessage("b cannot be restricted by more than one relation if it includes a IN", + "select * from %s where a = ? AND b IN (?, ?) AND b = ?", "first", 2, 2, 3); + assertInvalidMessage("b cannot be restricted by more than one relation if it includes an Equal", + "select * from %s where a = ? AND b = ? AND b IN (?, ?)", "first", 2, 2, 3); } @Test @@ -167,4 +205,162 @@ public class SingleColumnRelationTest extends CQLTester row("first", 2, 6, 2), row("first", 3, 7, 3)); } + + @Test + public void testAllowFilteringWithClusteringColumn() throws Throwable + { + createTable("CREATE TABLE %s (k int, c int, v int, PRIMARY KEY (k, c))"); + + execute("INSERT INTO %s (k, c, v) VALUES(?, ?, ?)", 1, 2, 1); + execute("INSERT INTO %s (k, c, v) VALUES(?, ?, ?)", 1, 3, 2); + execute("INSERT INTO %s (k, c, v) VALUES(?, ?, ?)", 2, 2, 3); + + // Don't require filtering, always allowed + assertRows(execute("SELECT * FROM %s WHERE k = ?", 1), + row(1, 2, 1), + row(1, 3, 2)); + + assertRows(execute("SELECT * FROM %s WHERE k = ? AND c > ?", 1, 2), row(1, 3, 2)); + + assertRows(execute("SELECT * FROM %s WHERE k = ? AND c = ?", 1, 2), row(1, 2, 1)); + + assertRows(execute("SELECT * FROM %s WHERE k = ? ALLOW FILTERING", 1), + row(1, 2, 1), + row(1, 3, 2)); + + assertRows(execute("SELECT * FROM %s WHERE k = ? AND c > ? ALLOW FILTERING", 1, 2), row(1, 3, 2)); + + assertRows(execute("SELECT * FROM %s WHERE k = ? AND c = ? ALLOW FILTERING", 1, 2), row(1, 2, 1)); + + // Require filtering, allowed only with ALLOW FILTERING + assertInvalidMessage("Cannot execute this query as it might involve data filtering", + "SELECT * FROM %s WHERE c = ?", 2); + assertInvalidMessage("Cannot execute this query as it might involve data filtering", + "SELECT * FROM %s WHERE c > ? AND c <= ?", 2, 4); + + assertRows(execute("SELECT * FROM %s WHERE c = ? ALLOW FILTERING", 2), + row(1, 2, 1), + row(2, 2, 3)); + + assertRows(execute("SELECT * FROM %s WHERE c > ? AND c <= ? ALLOW FILTERING", 2, 4), row(1, 3, 2)); + } + + @Test + public void testAllowFilteringWithIndexedColumn() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, a int, b int)"); + createIndex("CREATE INDEX ON %s(a)"); + + execute("INSERT INTO %s(k, a, b) VALUES(?, ?, ?)", 1, 10, 100); + execute("INSERT INTO %s(k, a, b) VALUES(?, ?, ?)", 2, 20, 200); + execute("INSERT INTO %s(k, a, b) VALUES(?, ?, ?)", 3, 30, 300); + execute("INSERT INTO %s(k, a, b) VALUES(?, ?, ?)", 4, 40, 400); + + // Don't require filtering, always allowed + assertRows(execute("SELECT * FROM %s WHERE k = ?", 1), row(1, 10, 100)); + assertRows(execute("SELECT * FROM %s WHERE a = ?", 20), row(2, 20, 200)); + assertRows(execute("SELECT * FROM %s WHERE k = ? ALLOW FILTERING", 1), row(1, 10, 100)); + assertRows(execute("SELECT * FROM %s WHERE a = ? ALLOW FILTERING", 20), row(2, 20, 200)); + + assertInvalid("SELECT * FROM %s WHERE a = ? AND b = ?"); + assertRows(execute("SELECT * FROM %s WHERE a = ? AND b = ? ALLOW FILTERING", 20, 200), row(2, 20, 200)); + } + + @Test + public void testIndexQueriesOnComplexPrimaryKey() 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))"); + + createIndex("CREATE INDEX ON %s (ck1)"); + createIndex("CREATE INDEX ON %s (ck2)"); + createIndex("CREATE INDEX ON %s (pk0)"); + createIndex("CREATE INDEX ON %s (ck0)"); + + 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 + public void testIndexOnClusteringColumns() 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)"); + createIndex("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")); + + assertInvalidMessage("IN restrictions are not supported on indexed columns", + "SELECT v1 FROM %s WHERE id2 = 0 and time IN (1, 2) ALLOW FILTERING"); + } + + @Test + public void testCompositeIndexWithPrimaryKey() throws Throwable + { + createTable("CREATE TABLE %s (blog_id int, time1 int, time2 int, author text, content text, PRIMARY KEY (blog_id, time1, time2))"); + + createIndex("CREATE INDEX ON %s(author)"); + + String req = "INSERT INTO %s (blog_id, time1, time2, author, content) VALUES (?, ?, ?, ?, ?)"; + execute(req, 1, 0, 0, "foo", "bar1"); + execute(req, 1, 0, 1, "foo", "bar2"); + execute(req, 2, 1, 0, "foo", "baz"); + execute(req, 3, 0, 1, "gux", "qux"); + + assertRows(execute("SELECT blog_id, content FROM %s WHERE author='foo'"), + row(1, "bar1"), + row(1, "bar2"), + row(2, "baz")); + assertRows(execute("SELECT blog_id, content FROM %s WHERE time1 > 0 AND author='foo' ALLOW FILTERING"), row(2, "baz")); + assertRows(execute("SELECT blog_id, content FROM %s WHERE time1 = 1 AND author='foo' ALLOW FILTERING"), row(2, "baz")); + assertRows(execute("SELECT blog_id, content FROM %s WHERE time1 = 1 AND time2 = 0 AND author='foo' ALLOW FILTERING"), + row(2, "baz")); + assertEmpty(execute("SELECT content FROM %s WHERE time1 = 1 AND time2 = 1 AND author='foo' ALLOW FILTERING")); + assertEmpty(execute("SELECT content FROM %s WHERE time1 = 1 AND time2 > 0 AND author='foo' ALLOW FILTERING")); + + assertInvalidMessage("Cannot execute this query as it might involve data filtering", + "SELECT content FROM %s WHERE time2 >= 0 AND author='foo'"); + } + + @Test + public void testRangeQueryOnIndex() throws Throwable + { + createTable("CREATE TABLE %s (id int primary key, row int, setid int);"); + createIndex("CREATE INDEX ON %s (setid)"); + + String q = "INSERT INTO %s (id, row, setid) VALUES (?, ?, ?);"; + execute(q, 0, 0, 0); + execute(q, 1, 1, 0); + execute(q, 2, 2, 0); + execute(q, 3, 3, 0); + + assertInvalidMessage("Cannot execute this query as it might involve data filtering", + "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)); + } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/65a7088e/test/unit/org/apache/cassandra/cql3/ThriftCompatibilityTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/ThriftCompatibilityTest.java b/test/unit/org/apache/cassandra/cql3/ThriftCompatibilityTest.java index deb3082..88ee688 100644 --- a/test/unit/org/apache/cassandra/cql3/ThriftCompatibilityTest.java +++ b/test/unit/org/apache/cassandra/cql3/ThriftCompatibilityTest.java @@ -33,7 +33,7 @@ public class ThriftCompatibilityTest extends SchemaLoader @BeforeClass public static void defineSchema() throws Exception { - SchemaLoader.prepareServer(); + // The before class annotation of SchemaLoader will prepare the service so no need to do it here SchemaLoader.createKeyspace("thriftcompat", SimpleStrategy.class, KSMetaData.optsWithRF(1),