mirror of https://github.com/apache/cassandra
Allow filtering on partition key columns for queries without secondary indexes
patch by ZhaoYang and Alex Petrov; reviewed by Benjamin Lerer for CASSANDRA-11031
This commit is contained in:
parent
64f12ab2c8
commit
3f49c328f2
|
|
@ -1,4 +1,5 @@
|
|||
3.10
|
||||
* Allow filtering on partition key columns for queries without secondary indexes (CASSANDRA-11031)
|
||||
* Fix Cassandra Stress reporting thread model and precision (CASSANDRA-12585)
|
||||
* Add JMH benchmarks.jar (CASSANDRA-12586)
|
||||
* Add row offset support to SASI (CASSANDRA-11990)
|
||||
|
|
|
|||
2
NEWS.txt
2
NEWS.txt
|
|
@ -18,6 +18,8 @@ using the provided 'sstableupgrade' tool.
|
|||
|
||||
New features
|
||||
------------
|
||||
- Filtering on partition key columns is now also supported for queries without
|
||||
secondary indexes.
|
||||
- A slow query log has been added: slow queries will be logged at DEBUG level.
|
||||
For more details refer to CASSANDRA-12403 and slow_query_log_timeout_in_ms
|
||||
in cassandra.yaml.
|
||||
|
|
|
|||
|
|
@ -252,17 +252,6 @@ public final class SingleColumnRelation extends Relation
|
|||
checkFalse(!columnDef.isPrimaryKeyColumn() && !canHaveOnlyOneValue(),
|
||||
"IN predicates on non-primary-key columns (%s) is not yet supported", columnDef.name);
|
||||
}
|
||||
else if (isSlice())
|
||||
{
|
||||
// Non EQ relation is not supported without token(), even if we have a 2ndary index (since even those
|
||||
// are ordered by partitioner).
|
||||
// Note: In theory we could allow it for 2ndary index queries with ALLOW FILTERING, but that would
|
||||
// probably require some special casing
|
||||
// Note bis: This is also why we don't bother handling the 'tuple' notation of #4851 for keys. If we
|
||||
// lift the limitation for 2ndary
|
||||
// index with filtering, we'll need to handle it though.
|
||||
checkFalse(columnDef.isPartitionKey(), "Only EQ and IN relation are supported on the partition key (unless you use the token() function)");
|
||||
}
|
||||
|
||||
checkFalse(isContainsKey() && !(receiver.type instanceof MapType), "Cannot use CONTAINS KEY on non-map column %s", receiver.name);
|
||||
checkFalse(isContains() && !(receiver.type.isCollection()), "Cannot use CONTAINS on non-collection column %s", receiver.name);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ package org.apache.cassandra.cql3.restrictions;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.cql3.QueryOptions;
|
||||
import org.apache.cassandra.cql3.statements.Bound;
|
||||
|
||||
|
|
@ -48,4 +49,20 @@ interface PartitionKeyRestrictions extends Restrictions
|
|||
* @return <code>true</code> if the specified bound is inclusive, <code>false</code> otherwise
|
||||
*/
|
||||
public boolean isInclusive(Bound b);
|
||||
|
||||
/**
|
||||
* checks if specified restrictions require filtering
|
||||
*
|
||||
* @param cfm column family metadata
|
||||
* @return <code>true</code> if filtering is required, <code>false</code> otherwise
|
||||
*/
|
||||
public boolean needFiltering(CFMetaData cfm);
|
||||
|
||||
/**
|
||||
* Checks if the partition key has unrestricted components.
|
||||
*
|
||||
* @param cfm column family metadata
|
||||
* @return <code>true</code> if the partition key has unrestricted components, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean hasUnrestrictedPartitionKeyComponents(CFMetaData cfm);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,4 +129,30 @@ final class PartitionKeySingleRestrictionSet extends RestrictionSetWrapper imple
|
|||
restriction.addRowFilterTo(filter, indexManager, options);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needFiltering(CFMetaData cfm)
|
||||
{
|
||||
if (isEmpty())
|
||||
return false;
|
||||
// slice or has unrestricted key component
|
||||
return hasUnrestrictedPartitionKeyComponents(cfm) || hasSlice();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUnrestrictedPartitionKeyComponents(CFMetaData cfm)
|
||||
{
|
||||
return size() < cfm.partitionKeyColumns().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSlice()
|
||||
{
|
||||
for (SingleRestriction restriction : restrictions)
|
||||
{
|
||||
if (restriction.isSlice())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -266,6 +266,16 @@ final class RestrictionSet implements Restrictions, Iterable<SingleRestriction>
|
|||
return false;
|
||||
}
|
||||
|
||||
public final boolean hasSlice()
|
||||
{
|
||||
for (SingleRestriction restriction : this)
|
||||
{
|
||||
if (restriction.isSlice())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all of the underlying restrictions are EQ or IN restrictions.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -89,6 +89,11 @@ class RestrictionSetWrapper implements Restrictions
|
|||
return restrictions.hasIN();
|
||||
}
|
||||
|
||||
public boolean hasSlice()
|
||||
{
|
||||
return restrictions.hasSlice();
|
||||
}
|
||||
|
||||
public boolean hasOnlyEqualityRestrictions()
|
||||
{
|
||||
return restrictions.hasOnlyEqualityRestrictions();
|
||||
|
|
|
|||
|
|
@ -54,6 +54,12 @@ public interface Restrictions extends Restriction
|
|||
*/
|
||||
public boolean hasIN();
|
||||
|
||||
/**
|
||||
* Checks if any of the underlying restrictions is a slice.
|
||||
* @return <code>true</code> if any of the underlying restrictions is a slice, <code>false</code> otherwise
|
||||
*/
|
||||
public boolean hasSlice();
|
||||
|
||||
/**
|
||||
* Checks if all of the underlying restrictions are EQ or IN restrictions.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -190,11 +190,11 @@ public final class StatementRestrictions
|
|||
}
|
||||
|
||||
// At this point, the select statement if fully constructed, but we still have a few things to validate
|
||||
processPartitionKeyRestrictions(hasQueriableIndex);
|
||||
processPartitionKeyRestrictions(hasQueriableIndex, allowFiltering, forView);
|
||||
|
||||
// Some but not all of the partition key columns have been specified;
|
||||
// hence we need turn these restrictions into a row filter.
|
||||
if (usesSecondaryIndexing)
|
||||
if (usesSecondaryIndexing || partitionKeyRestrictions.needFiltering(cfm))
|
||||
filterRestrictions.add(partitionKeyRestrictions);
|
||||
|
||||
if (selectsOnlyStaticColumns && hasClusteringColumnsRestriction())
|
||||
|
|
@ -385,36 +385,48 @@ public final class StatementRestrictions
|
|||
return this.usesSecondaryIndexing;
|
||||
}
|
||||
|
||||
private void processPartitionKeyRestrictions(boolean hasQueriableIndex)
|
||||
private void processPartitionKeyRestrictions(boolean hasQueriableIndex, boolean allowFiltering, boolean forView)
|
||||
{
|
||||
if (!type.allowPartitionKeyRanges())
|
||||
{
|
||||
checkFalse(partitionKeyRestrictions.isOnToken(),
|
||||
"The token function cannot be used in WHERE clauses for %s statements", type);
|
||||
|
||||
if (hasUnrestrictedPartitionKeyComponents())
|
||||
if (partitionKeyRestrictions.hasUnrestrictedPartitionKeyComponents(cfm))
|
||||
throw invalidRequest("Some partition key parts are missing: %s",
|
||||
Joiner.on(", ").join(getPartitionKeyUnrestrictedComponents()));
|
||||
|
||||
// slice query
|
||||
checkFalse(partitionKeyRestrictions.hasSlice(),
|
||||
"Only EQ and IN relation are supported on the partition key (unless you use the token() function)"
|
||||
+ " for %s statements", type);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there is a queriable index, no special condition are required on the other restrictions.
|
||||
// But we still need to know 2 things:
|
||||
// - If we don't have a queriable index, is the query ok
|
||||
// - Is it queriable without 2ndary index, which is always more efficient
|
||||
// If a component of the partition key is restricted by a relation, all preceding
|
||||
// components must have a EQ. Only the last partition key component can be in IN relation.
|
||||
if (partitionKeyRestrictions.isOnToken())
|
||||
isKeyRange = true;
|
||||
// If there are no partition restrictions or there's only token restriction, we have to set a key range
|
||||
if (partitionKeyRestrictions.isOnToken())
|
||||
isKeyRange = true;
|
||||
|
||||
if (hasUnrestrictedPartitionKeyComponents())
|
||||
if (partitionKeyRestrictions.isEmpty() && partitionKeyRestrictions.hasUnrestrictedPartitionKeyComponents(cfm))
|
||||
{
|
||||
if (!partitionKeyRestrictions.isEmpty())
|
||||
{
|
||||
if (!hasQueriableIndex)
|
||||
throw invalidRequest("Partition key parts: %s must be restricted as other parts are",
|
||||
Joiner.on(", ").join(getPartitionKeyUnrestrictedComponents()));
|
||||
}
|
||||
isKeyRange = true;
|
||||
usesSecondaryIndexing = hasQueriableIndex;
|
||||
}
|
||||
|
||||
// If there is a queriable index, no special condition is required on the other restrictions.
|
||||
// But we still need to know 2 things:
|
||||
// - If we don't have a queriable index, is the query ok
|
||||
// - Is it queriable without 2ndary index, which is always more efficient
|
||||
// If a component of the partition key is restricted by a relation, all preceding
|
||||
// components must have a EQ. Only the last partition key component can be in IN relation.
|
||||
if (partitionKeyRestrictions.needFiltering(cfm))
|
||||
{
|
||||
if (!allowFiltering && !forView && !hasQueriableIndex
|
||||
&& (partitionKeyRestrictions.hasUnrestrictedPartitionKeyComponents(cfm) || partitionKeyRestrictions.hasSlice()))
|
||||
throw new InvalidRequestException(REQUIRES_ALLOW_FILTERING_MESSAGE);
|
||||
|
||||
if (partitionKeyRestrictions.hasIN())
|
||||
throw new InvalidRequestException("IN restrictions are not supported when the query involves filtering");
|
||||
|
||||
isKeyRange = true;
|
||||
usesSecondaryIndexing = hasQueriableIndex;
|
||||
|
|
@ -422,15 +434,6 @@ public final class StatementRestrictions
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the partition key has some unrestricted components.
|
||||
* @return <code>true</code> if the partition key has some unrestricted components, <code>false</code> otherwise.
|
||||
*/
|
||||
private boolean hasUnrestrictedPartitionKeyComponents()
|
||||
{
|
||||
return partitionKeyRestrictions.size() < cfm.partitionKeyColumns().size();
|
||||
}
|
||||
|
||||
public boolean hasPartitionKeyRestrictions()
|
||||
{
|
||||
return !partitionKeyRestrictions.isEmpty();
|
||||
|
|
@ -622,8 +625,8 @@ public final class StatementRestrictions
|
|||
private ByteBuffer getPartitionKeyBound(Bound b, QueryOptions options)
|
||||
{
|
||||
// Deal with unrestricted partition key components (special-casing is required to deal with 2i queries on the
|
||||
// first component of a composite partition key).
|
||||
if (hasUnrestrictedPartitionKeyComponents())
|
||||
// first component of a composite partition key) queries that filter on the partition key.
|
||||
if (partitionKeyRestrictions.needFiltering(cfm))
|
||||
return ByteBufferUtil.EMPTY_BYTE_BUFFER;
|
||||
|
||||
// We deal with IN queries for keys in other places, so we know buildBound will return only one result
|
||||
|
|
@ -804,7 +807,7 @@ public final class StatementRestrictions
|
|||
public boolean hasAllPKColumnsRestrictedByEqualities()
|
||||
{
|
||||
return !isPartitionKeyRestrictionsOnToken()
|
||||
&& !hasUnrestrictedPartitionKeyComponents()
|
||||
&& !partitionKeyRestrictions.hasUnrestrictedPartitionKeyComponents(cfm)
|
||||
&& (partitionKeyRestrictions.hasOnlyEqualityRestrictions())
|
||||
&& !hasUnrestrictedClusteringColumns()
|
||||
&& (clusteringColumnsRestrictions.hasOnlyEqualityRestrictions());
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import com.google.common.collect.ImmutableRangeSet;
|
|||
import com.google.common.collect.Range;
|
||||
import com.google.common.collect.RangeSet;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.config.ColumnDefinition;
|
||||
import org.apache.cassandra.cql3.QueryOptions;
|
||||
import org.apache.cassandra.cql3.functions.Function;
|
||||
|
|
@ -135,8 +136,8 @@ final class TokenFilter implements PartitionKeyRestrictions
|
|||
*/
|
||||
private List<ByteBuffer> filter(List<ByteBuffer> values, QueryOptions options) throws InvalidRequestException
|
||||
{
|
||||
RangeSet<Token> rangeSet = tokenRestriction.isSlice() ? toRangeSet(tokenRestriction, options)
|
||||
: toRangeSet(tokenRestriction.values(options));
|
||||
RangeSet<Token> rangeSet = tokenRestriction.hasSlice() ? toRangeSet(tokenRestriction, options)
|
||||
: toRangeSet(tokenRestriction.values(options));
|
||||
|
||||
return filterWithRangeSet(rangeSet, values);
|
||||
}
|
||||
|
|
@ -285,4 +286,22 @@ final class TokenFilter implements PartitionKeyRestrictions
|
|||
{
|
||||
return restrictions.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needFiltering(CFMetaData cfm)
|
||||
{
|
||||
return restrictions.needFiltering(cfm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUnrestrictedPartitionKeyComponents(CFMetaData cfm)
|
||||
{
|
||||
return restrictions.hasUnrestrictedPartitionKeyComponents(cfm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSlice()
|
||||
{
|
||||
return restrictions.hasSlice();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,11 +57,6 @@ public abstract class TokenRestriction implements PartitionKeyRestrictions
|
|||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
public boolean isSlice()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasIN()
|
||||
{
|
||||
return false;
|
||||
|
|
@ -84,6 +79,24 @@ public abstract class TokenRestriction implements PartitionKeyRestrictions
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needFiltering(CFMetaData cfm)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSlice()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUnrestrictedPartitionKeyComponents(CFMetaData cfm)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ColumnDefinition> getColumnDefs()
|
||||
{
|
||||
|
|
@ -225,7 +238,7 @@ public abstract class TokenRestriction implements PartitionKeyRestrictions
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isSlice()
|
||||
public boolean hasSlice()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import java.util.concurrent.ConcurrentMap;
|
|||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.Iterables;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
|
@ -274,9 +275,19 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression>
|
|||
return iter;
|
||||
|
||||
final CFMetaData metadata = iter.metadata();
|
||||
long numberOfStaticColumnExpressions = expressions.stream().filter(e -> e.column.isStatic()).count();
|
||||
final boolean filterStaticColumns = numberOfStaticColumnExpressions != 0;
|
||||
final boolean filterNonStaticColumns = (expressions.size() - numberOfStaticColumnExpressions) > 0;
|
||||
|
||||
List<Expression> partitionLevelExpressions = new ArrayList<>();
|
||||
List<Expression> rowLevelExpressions = new ArrayList<>();
|
||||
for (Expression e: expressions)
|
||||
{
|
||||
if (e.column.isStatic() || e.column.isPartitionKey())
|
||||
partitionLevelExpressions.add(e);
|
||||
else
|
||||
rowLevelExpressions.add(e);
|
||||
}
|
||||
|
||||
long numberOfRegularColumnExpressions = rowLevelExpressions.size();
|
||||
final boolean filterNonStaticColumns = numberOfRegularColumnExpressions > 0;
|
||||
|
||||
class IsSatisfiedFilter extends Transformation<UnfilteredRowIterator>
|
||||
{
|
||||
|
|
@ -285,9 +296,10 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression>
|
|||
{
|
||||
pk = partition.partitionKey();
|
||||
|
||||
// The filter might be on static columns, so need to check static row first.
|
||||
if (filterStaticColumns && applyToRow(partition.staticRow()) == null)
|
||||
return null;
|
||||
// Short-circuit all partitions that won't match based on static and partition keys
|
||||
for (Expression e : partitionLevelExpressions)
|
||||
if (!e.isSatisfiedBy(metadata, partition.partitionKey(), partition.staticRow()))
|
||||
return null;
|
||||
|
||||
UnfilteredRowIterator iterator = Transformation.apply(partition, this);
|
||||
return (filterNonStaticColumns && !iterator.hasNext()) ? null : iterator;
|
||||
|
|
@ -299,9 +311,10 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression>
|
|||
if (purged == null)
|
||||
return null;
|
||||
|
||||
for (Expression e : expressions)
|
||||
for (Expression e : rowLevelExpressions)
|
||||
if (!e.isSatisfiedBy(metadata, pk, purged))
|
||||
return null;
|
||||
|
||||
return row;
|
||||
}
|
||||
}
|
||||
|
|
@ -669,9 +682,6 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression>
|
|||
// TODO: we should try to merge both code someday.
|
||||
assert value != null;
|
||||
|
||||
if (row.isStatic() != column.isStatic())
|
||||
return true;
|
||||
|
||||
switch (operator)
|
||||
{
|
||||
case EQ:
|
||||
|
|
|
|||
|
|
@ -148,13 +148,6 @@ public class ViewFilteringTest extends CQLTester
|
|||
throw new RuntimeException("MV alter failed: " + goodStatements.get(i), e);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
createView("mv_foo", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE a = 1 AND b IS NOT NULL AND c IS NOT NULL AND d is NOT NULL PRIMARY KEY ((a, b), c, d)");
|
||||
Assert.fail("Partial partition key restriction should not be allowed");
|
||||
}
|
||||
catch (InvalidQueryException exc) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -265,6 +258,210 @@ public class ViewFilteringTest extends CQLTester
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPartitionKeyFilteringUnrestrictedPart() throws Throwable
|
||||
{
|
||||
List<String> mvPrimaryKeys = Arrays.asList("((a, b), c)", "((b, a), c)", "(a, b, c)", "(c, b, a)", "((c, a), b)");
|
||||
for (int i = 0; i < mvPrimaryKeys.size(); i++)
|
||||
{
|
||||
createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY ((a, b), c))");
|
||||
|
||||
execute("USE " + keyspace());
|
||||
executeNet(protocolVersion, "USE " + keyspace());
|
||||
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 0, 0);
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 0, 0);
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 0, 0, 0);
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 0, 1, 0);
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 1, 0, 0);
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 1, 1, 0);
|
||||
|
||||
logger.info("Testing MV primary key: {}", mvPrimaryKeys.get(i));
|
||||
|
||||
// only accept rows where a = 1
|
||||
String viewName= "mv_test" + i;
|
||||
createView(viewName, "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE a = 1 AND b IS NOT NULL AND c IS NOT NULL PRIMARY KEY " + mvPrimaryKeys.get(i));
|
||||
|
||||
waitForView(keyspace(), viewName);
|
||||
|
||||
assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i),
|
||||
row(1, 0, 0, 0),
|
||||
row(1, 0, 1, 0),
|
||||
row(1, 1, 0, 0),
|
||||
row(1, 1, 1, 0)
|
||||
);
|
||||
|
||||
// insert new rows that do not match the filter
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 2, 0, 0, 0);
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 2, 1, 0, 0);
|
||||
assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i),
|
||||
row(1, 0, 0, 0),
|
||||
row(1, 0, 1, 0),
|
||||
row(1, 1, 0, 0),
|
||||
row(1, 1, 1, 0)
|
||||
);
|
||||
|
||||
// insert new row that does match the filter
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 1, 2, 0);
|
||||
assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i),
|
||||
row(1, 0, 0, 0),
|
||||
row(1, 0, 1, 0),
|
||||
row(1, 1, 0, 0),
|
||||
row(1, 1, 1, 0),
|
||||
row(1, 1, 2, 0)
|
||||
);
|
||||
|
||||
// update rows that don't match the filter
|
||||
execute("UPDATE %s SET d = ? WHERE a = ? AND b = ? AND c = ?", 1, 0, 0, 0);
|
||||
execute("UPDATE %s SET d = ? WHERE a = ? AND b = ? AND c = ?", 1, 0, 1, 0);
|
||||
assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i),
|
||||
row(1, 0, 0, 0),
|
||||
row(1, 0, 1, 0),
|
||||
row(1, 1, 0, 0),
|
||||
row(1, 1, 1, 0),
|
||||
row(1, 1, 2, 0)
|
||||
);
|
||||
|
||||
// update a row that does match the filter
|
||||
execute("UPDATE %s SET d = ? WHERE a = ? AND b = ? AND c = ?", 1, 1, 1, 0);
|
||||
assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i),
|
||||
row(1, 0, 0, 0),
|
||||
row(1, 0, 1, 0),
|
||||
row(1, 1, 0, 1),
|
||||
row(1, 1, 1, 0),
|
||||
row(1, 1, 2, 0)
|
||||
);
|
||||
|
||||
// delete rows that don't match the filter
|
||||
execute("DELETE FROM %s WHERE a = ? AND b = ? AND c = ?", 0, 0, 0);
|
||||
execute("DELETE FROM %s WHERE a = ? AND b = ? AND c = ?", 0, 1, 0);
|
||||
execute("DELETE FROM %s WHERE a = ? AND b = ?", 0, 0);
|
||||
assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i),
|
||||
row(1, 0, 0, 0),
|
||||
row(1, 0, 1, 0),
|
||||
row(1, 1, 0, 1),
|
||||
row(1, 1, 1, 0),
|
||||
row(1, 1, 2, 0)
|
||||
);
|
||||
|
||||
// delete a row that does match the filter
|
||||
execute("DELETE FROM %s WHERE a = ? AND b = ? AND c = ?", 1, 1, 0);
|
||||
assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i),
|
||||
row(1, 0, 0, 0),
|
||||
row(1, 0, 1, 0),
|
||||
row(1, 1, 1, 0),
|
||||
row(1, 1, 2, 0)
|
||||
);
|
||||
|
||||
// delete a partition that matches the filter
|
||||
execute("DELETE FROM %s WHERE a = ? AND b = ?", 1, 0);
|
||||
assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i),
|
||||
row(1, 1, 1, 0),
|
||||
row(1, 1, 2, 0));
|
||||
execute("DELETE FROM %s WHERE a = ? AND b = ?", 1, 1);
|
||||
assertEmpty(execute("SELECT * FROM mv_test" + i));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPartitionKeyFilteringWithSlice() throws Throwable
|
||||
{
|
||||
List<String> mvPrimaryKeys = Arrays.asList("((a, b), c)", "((b, a), c)", "(a, b, c)", "(c, b, a)", "((c, a), b)");
|
||||
for (int i = 0; i < mvPrimaryKeys.size(); i++)
|
||||
{
|
||||
createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY ((a, b), c))");
|
||||
|
||||
execute("USE " + keyspace());
|
||||
executeNet(protocolVersion, "USE " + keyspace());
|
||||
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 1, 1);
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 10, 1, 2);
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 0, 2, 1);
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 10, 2, 2);
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 2, 1, 3, 1);
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 2, 10, 3, 2);
|
||||
|
||||
logger.info("Testing MV primary key: {}", mvPrimaryKeys.get(i));
|
||||
|
||||
// only accept rows where a = 1
|
||||
String viewName= "mv_test" + i;
|
||||
createView(viewName, "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE a > 0 AND b > 5 AND c IS NOT NULL PRIMARY KEY " + mvPrimaryKeys.get(i));
|
||||
|
||||
waitForView(keyspace(), viewName);
|
||||
|
||||
assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i),
|
||||
row(1, 10, 2, 2),
|
||||
row(2, 10, 3, 2)
|
||||
);
|
||||
|
||||
// insert new rows that do not match the filter
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 2, 0, 0, 0);
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 2, 1, 0, 0);
|
||||
assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i),
|
||||
row(1, 10, 2, 2),
|
||||
row(2, 10, 3, 2)
|
||||
);
|
||||
|
||||
// insert new row that does match the filter
|
||||
execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 3, 10, 4, 2);
|
||||
assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i),
|
||||
row(1, 10, 2, 2),
|
||||
row(2, 10, 3, 2),
|
||||
row(3, 10, 4, 2)
|
||||
);
|
||||
|
||||
// update rows that don't match the filter
|
||||
execute("UPDATE %s SET d = ? WHERE a = ? AND b = ? AND c = ?", 1, 0, 0, 0);
|
||||
execute("UPDATE %s SET d = ? WHERE a = ? AND b = ? AND c = ?", 1, 0, 1, 0);
|
||||
assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i),
|
||||
row(1, 10, 2, 2),
|
||||
row(2, 10, 3, 2),
|
||||
row(3, 10, 4, 2)
|
||||
);
|
||||
|
||||
// update a row that does match the filter
|
||||
execute("UPDATE %s SET d = ? WHERE a = ? AND b = ? AND c = ?", 100, 3, 10, 4);
|
||||
assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i),
|
||||
row(1, 10, 2, 2),
|
||||
row(2, 10, 3, 2),
|
||||
row(3, 10, 4, 100)
|
||||
);
|
||||
|
||||
// delete rows that don't match the filter
|
||||
execute("DELETE FROM %s WHERE a = ? AND b = ? AND c = ?", 0, 0, 0);
|
||||
execute("DELETE FROM %s WHERE a = ? AND b = ? AND c = ?", 0, 1, 0);
|
||||
execute("DELETE FROM %s WHERE a = ? AND b = ?", 0, 0);
|
||||
assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i),
|
||||
row(1, 10, 2, 2),
|
||||
row(2, 10, 3, 2),
|
||||
row(3, 10, 4, 100)
|
||||
);
|
||||
|
||||
// delete a row that does match the filter
|
||||
execute("DELETE FROM %s WHERE a = ? AND b = ? AND c = ?", 1, 1, 0);
|
||||
assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i),
|
||||
row(1, 10, 2, 2),
|
||||
row(2, 10, 3, 2),
|
||||
row(3, 10, 4, 100)
|
||||
);
|
||||
|
||||
// delete a partition that matches the filter
|
||||
execute("DELETE FROM %s WHERE a = ? AND b = ?", 1, 10);
|
||||
assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i),
|
||||
row(2, 10, 3, 2),
|
||||
row(3, 10, 4, 100));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static void waitForView(String keyspace, String view) throws InterruptedException
|
||||
{
|
||||
while (!SystemKeyspace.isViewBuilt(keyspace, view))
|
||||
Thread.sleep(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPartitionKeyRestrictions() throws Throwable
|
||||
{
|
||||
|
|
|
|||
|
|
@ -117,6 +117,19 @@ public class ViewTest extends CQLTester
|
|||
Assert.assertEquals(0, execute("select * from view1").size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void createMvWithUnrestrictedPKParts() throws Throwable
|
||||
{
|
||||
createTable("CREATE TABLE %s (k1 int, c1 int , val int, PRIMARY KEY (k1, c1))");
|
||||
|
||||
execute("USE " + keyspace());
|
||||
executeNet(protocolVersion, "USE " + keyspace());
|
||||
|
||||
createView("view1", "CREATE MATERIALIZED VIEW view1 AS SELECT k1 FROM %%s WHERE k1 IS NOT NULL AND c1 IS NOT NULL AND val IS NOT NULL PRIMARY KEY (val, k1, c1)");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClusteringKeyTombstone() throws Throwable
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1177,6 +1177,101 @@ public class SecondaryIndexTest extends CQLTester
|
|||
row(bytes("foo124"), EMPTY_BYTE_BUFFER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPartitionKeyWithIndex() throws Throwable
|
||||
{
|
||||
createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY ((a, b)))");
|
||||
createIndex("CREATE INDEX ON %s (a);");
|
||||
createIndex("CREATE INDEX ON %s (b);");
|
||||
|
||||
execute("INSERT INTO %s (a, b, c) VALUES (1,2,3)");
|
||||
execute("INSERT INTO %s (a, b, c) VALUES (2,3,4)");
|
||||
execute("INSERT INTO %s (a, b, c) VALUES (5,6,7)");
|
||||
|
||||
beforeAndAfterFlush(() -> {
|
||||
assertRows(execute("SELECT * FROM %s WHERE a = 1"),
|
||||
row(1, 2, 3));
|
||||
assertRows(execute("SELECT * FROM %s WHERE b = 3"),
|
||||
row(2, 3, 4));
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllowFilteringOnPartitionKeyWithSecondaryIndex() throws Throwable
|
||||
{
|
||||
createTable("CREATE TABLE %s (pk1 int, pk2 int, c1 int, c2 int, v int, " +
|
||||
"PRIMARY KEY ((pk1, pk2), c1, c2))");
|
||||
createIndex("CREATE INDEX v_idx_1 ON %s (v);");
|
||||
|
||||
for (int i = 1; i <= 5; i++)
|
||||
{
|
||||
for (int j = 1; j <= 2; j++)
|
||||
{
|
||||
execute("INSERT INTO %s (pk1, pk2, c1, c2, v) VALUES (?, ?, ?, ?, ?)", j, 1, 1, 1, i);
|
||||
execute("INSERT INTO %s (pk1, pk2, c1, c2, v) VALUES (?, ?, ?, ?, ?)", j, 1, 1, i, i);
|
||||
execute("INSERT INTO %s (pk1, pk2, c1, c2, v) VALUES (?, ?, ?, ?, ?)", j, 1, i, i, i);
|
||||
execute("INSERT INTO %s (pk1, pk2, c1, c2, v) VALUES (?, ?, ?, ?, ?)", j, i, i, i, i);
|
||||
}
|
||||
}
|
||||
|
||||
beforeAndAfterFlush(() -> {
|
||||
assertEmpty(execute("SELECT * FROM %s WHERE pk1 = 1 AND c1 > 0 AND c1 < 5 AND c2 = 1 AND v = 3 ALLOW FILTERING;"));
|
||||
|
||||
assertRows(execute("SELECT * FROM %s WHERE pk1 = 1 AND c1 > 0 AND c1 < 5 AND c2 = 3 AND v = 3 ALLOW FILTERING;"),
|
||||
row(1, 3, 3, 3, 3),
|
||||
row(1, 1, 1, 3, 3),
|
||||
row(1, 1, 3, 3, 3));
|
||||
|
||||
assertEmpty(execute("SELECT * FROM %s WHERE pk1 = 1 AND c2 > 1 AND c2 < 5 AND v = 1 ALLOW FILTERING;"));
|
||||
|
||||
assertRows(execute("SELECT * FROM %s WHERE pk1 = 1 AND c1 > 1 AND c2 > 2 AND v = 3 ALLOW FILTERING;"),
|
||||
row(1, 3, 3, 3, 3),
|
||||
row(1, 1, 3, 3, 3));
|
||||
|
||||
assertRows(execute("SELECT * FROM %s WHERE pk1 = 1 AND pk2 > 1 AND c2 > 2 AND v = 3 ALLOW FILTERING;"),
|
||||
row(1, 3, 3, 3, 3));
|
||||
|
||||
assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE pk2 > 1 AND c1 IN(0,1,2) AND v <= 3 ALLOW FILTERING;"),
|
||||
row(1, 2, 2, 2, 2),
|
||||
row(2, 2, 2, 2, 2));
|
||||
|
||||
assertRows(execute("SELECT * FROM %s WHERE pk1 >= 2 AND pk2 <=3 AND c1 IN(0,1,2) AND c2 IN(0,1,2) AND v < 3 ALLOW FILTERING;"),
|
||||
row(2, 2, 2, 2, 2),
|
||||
row(2, 1, 1, 2, 2),
|
||||
row(2, 1, 2, 2, 2));
|
||||
|
||||
assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
|
||||
"SELECT * FROM %s WHERE pk1 >= 1 AND pk2 <=3 AND c1 IN(0,1,2) AND c2 IN(0,1,2) AND v = 3");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllowFilteringOnPartitionKeyWithIndexForContains() throws Throwable
|
||||
{
|
||||
createTable("CREATE TABLE %s (k1 int, k2 int, v set<int>, PRIMARY KEY ((k1, k2)))");
|
||||
createIndex("CREATE INDEX ON %s(k2)");
|
||||
|
||||
execute("INSERT INTO %s (k1, k2, v) VALUES (?, ?, ?)", 0, 0, set(1, 2, 3));
|
||||
execute("INSERT INTO %s (k1, k2, v) VALUES (?, ?, ?)", 0, 1, set(2, 3, 4));
|
||||
execute("INSERT INTO %s (k1, k2, v) VALUES (?, ?, ?)", 1, 0, set(3, 4, 5));
|
||||
execute("INSERT INTO %s (k1, k2, v) VALUES (?, ?, ?)", 1, 1, set(4, 5, 6));
|
||||
|
||||
beforeAndAfterFlush(() -> {
|
||||
assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
|
||||
"SELECT * FROM %s WHERE k2 > ?", 0);
|
||||
|
||||
assertRows(execute("SELECT * FROM %s WHERE k2 > ? ALLOW FILTERING", 0),
|
||||
row(0, 1, set(2, 3, 4)),
|
||||
row(1, 1, set(4, 5, 6)));
|
||||
|
||||
assertRows(execute("SELECT * FROM %s WHERE k2 >= ? AND v CONTAINS ? ALLOW FILTERING", 1, 6),
|
||||
row(1, 1, set(4, 5, 6)));
|
||||
|
||||
assertEmpty(execute("SELECT * FROM %s WHERE k2 < ? AND v CONTAINS ? ALLOW FILTERING", 0, 7));
|
||||
});
|
||||
}
|
||||
|
||||
private ResultMessage.Prepared prepareStatement(String cql, boolean forThrift)
|
||||
{
|
||||
return QueryProcessor.prepare(String.format(cql, KEYSPACE, currentTable()),
|
||||
|
|
|
|||
|
|
@ -958,11 +958,14 @@ public class SelectMultiColumnRelationTest extends CQLTester
|
|||
row(0, 0, 1, 1, 0, 4),
|
||||
row(0, 0, 1, 1, 1, 5));
|
||||
|
||||
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, 2, 1);
|
||||
assertRows(execute("SELECT * FROM %s WHERE a = ? AND (c, d) IN ((?, ?)) ALLOW FILTERING", 0, 1, 1),
|
||||
row(0, 0, 1, 1, 0, 4),
|
||||
row(0, 0, 1, 1, 1, 5));
|
||||
|
||||
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);
|
||||
assertRows(execute("SELECT * FROM %s WHERE a = ? AND (c, d) >= (?, ?) ALLOW FILTERING", 0, 1, 1),
|
||||
row(0, 0, 1, 1, 0, 4),
|
||||
row(0, 0, 1, 1, 1, 5),
|
||||
row(0, 0, 2, 0, 0, 5));
|
||||
|
||||
assertRows(execute("SELECT * FROM %s WHERE a = ? AND b = ? AND (c) IN ((?)) AND f = ?", 0, 0, 1, 5),
|
||||
row(0, 0, 1, 1, 1, 5));
|
||||
|
|
|
|||
|
|
@ -27,8 +27,11 @@ import org.junit.Test;
|
|||
|
||||
import static junit.framework.Assert.assertNull;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.cql3.CQLTester;
|
||||
import org.apache.cassandra.cql3.UntypedResultSet;
|
||||
import org.apache.cassandra.cql3.restrictions.StatementRestrictions;
|
||||
import org.apache.cassandra.dht.ByteOrderedPartitioner;
|
||||
|
||||
/**
|
||||
|
|
@ -42,6 +45,33 @@ public class SelectOrderedPartitionerTest extends CQLTester
|
|||
DatabaseDescriptor.setPartitionerUnsafe(ByteOrderedPartitioner.instance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilteringOnPartitionKeyWithToken() throws Throwable
|
||||
{
|
||||
createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY ((a, b), c))");
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
execute("INSERT INTO %s (a,b,c,d) VALUES (?, ?, ?, ?)", i, i, i, i);
|
||||
execute("INSERT INTO %s (a,b,c,d) VALUES (?, ?, ?, ?)", i, i + 10, i + 10, i + 10);
|
||||
}
|
||||
|
||||
beforeAndAfterFlush(() -> {
|
||||
assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE token(a, b) > token(5, 10) AND b < 8 ALLOW FILTERING"),
|
||||
row(6, 6, 6, 6),
|
||||
row(7, 7, 7, 7));
|
||||
|
||||
assertRows(execute("SELECT * FROM %s WHERE token(a, b) > token(8, 10) AND a = 9 ALLOW FILTERING"),
|
||||
row(9, 9, 9, 9),
|
||||
row(9, 19, 19, 19));
|
||||
|
||||
assertRows(execute("SELECT * FROM %s WHERE token(a, b) > token(8, 10) AND a = 9 AND c = 19 ALLOW FILTERING"),
|
||||
row(9, 19, 19, 19));
|
||||
|
||||
assertEmpty(execute("SELECT * FROM %s WHERE token(a, b) = token(8, 8) AND b = 9 ALLOW FILTERING"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTokenFunctionWithSingleColumnPartitionKey() throws Throwable
|
||||
{
|
||||
|
|
@ -130,7 +160,7 @@ public class SelectOrderedPartitionerTest extends CQLTester
|
|||
assertRows(execute("SELECT * FROM %s WHERE token(a) < token(?) AND token(a) >= token(?) AND a IN (?, ?);",
|
||||
1, 3, 1, 3),
|
||||
row(3, 3));
|
||||
assertInvalidMessage("Only EQ and IN relation are supported on the partition key (unless you use the token() function)",
|
||||
assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
|
||||
"SELECT * FROM %s WHERE token(a) > token(?) AND token(a) <= token(?) AND a > ?;", 1, 3, 1);
|
||||
|
||||
assertRows(execute("SELECT * FROM %s WHERE token(a) > token(?) AND token(a) <= token(?) AND a IN ?;",
|
||||
|
|
@ -206,7 +236,7 @@ public class SelectOrderedPartitionerTest extends CQLTester
|
|||
assertEmpty(execute("SELECT * FROM %s WHERE b IN (?, ?) AND token(a, b) = token(?, ?) AND a = ?;",
|
||||
0, 1, 0, 0, 1));
|
||||
|
||||
assertInvalidMessage("Partition key parts: b must be restricted as other parts are",
|
||||
assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
|
||||
"SELECT * FROM %s WHERE token(a, b) > token(?, ?) AND a = ?;", 0, 0, 1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -206,9 +206,9 @@ public class SelectSingleColumnRelationTest extends CQLTester
|
|||
row("second", 1, 1, 1),
|
||||
row("second", 4, 4, 4));
|
||||
|
||||
assertInvalidMessage("Partition key parts: b must be restricted as other parts are",
|
||||
assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
|
||||
"select * from %s where a in (?, ?)", "first", "second");
|
||||
assertInvalidMessage("Partition key parts: b must be restricted as other parts are",
|
||||
assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
|
||||
"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);
|
||||
|
|
@ -498,11 +498,14 @@ public class SelectSingleColumnRelationTest extends CQLTester
|
|||
row(0, 0, 1, 1, 0, 4),
|
||||
row(0, 0, 1, 1, 1, 5));
|
||||
|
||||
assertInvalidMessage("Partition key parts: b must be restricted as other parts are",
|
||||
"SELECT * FROM %s WHERE a = ? AND c IN (?, ?) AND d IN (?) ALLOW FILTERING", 0, 0, 1, 1);
|
||||
assertRows(execute("SELECT * FROM %s WHERE a = ? AND c IN (?) AND d IN (?) ALLOW FILTERING", 0, 1, 1),
|
||||
row(0, 0, 1, 1, 0, 4),
|
||||
row(0, 0, 1, 1, 1, 5));
|
||||
|
||||
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);
|
||||
assertRows(execute("SELECT * FROM %s WHERE a = ? AND (c, d) >= (?, ?) ALLOW FILTERING", 0, 1, 1),
|
||||
row(0, 0, 1, 1, 0, 4),
|
||||
row(0, 0, 1, 1, 1, 5),
|
||||
row(0, 0, 2, 0, 0, 5));
|
||||
|
||||
assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
|
||||
"SELECT * FROM %s WHERE a = ? AND c IN (?, ?) AND f = ?", 0, 0, 1, 5);
|
||||
|
|
@ -520,8 +523,11 @@ public class SelectSingleColumnRelationTest extends CQLTester
|
|||
assertRows(execute("SELECT * FROM %s WHERE a = ? AND c IN (?, ?) AND d IN (?) AND f = ? ALLOW FILTERING", 0, 1, 3, 0, 3),
|
||||
row(0, 0, 1, 0, 0, 3));
|
||||
|
||||
assertInvalidMessage("Partition key parts: b must be restricted as other parts are",
|
||||
"SELECT * FROM %s WHERE a = ? AND c >= ? ALLOW FILTERING", 0, 1);
|
||||
assertRows(execute("SELECT * FROM %s WHERE a = ? AND c >= ? ALLOW FILTERING", 0, 1),
|
||||
row(0, 0, 1, 0, 0, 3),
|
||||
row(0, 0, 1, 1, 0, 4),
|
||||
row(0, 0, 1, 1, 1, 5),
|
||||
row(0, 0, 2, 0, 0, 5));
|
||||
|
||||
assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
|
||||
"SELECT * FROM %s WHERE a = ? AND c >= ? AND f = ?", 0, 1, 5);
|
||||
|
|
@ -592,7 +598,7 @@ public class SelectSingleColumnRelationTest extends CQLTester
|
|||
public void testInvalidSliceRestrictionOnPartitionKey() throws Throwable
|
||||
{
|
||||
createTable("CREATE TABLE %s (a int PRIMARY KEY, b int, c text)");
|
||||
assertInvalidMessage("Only EQ and IN relation are supported on the partition key (unless you use the token() function)",
|
||||
assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
|
||||
"SELECT * FROM %s WHERE a >= 1 and a < 4");
|
||||
assertInvalidMessage("Multi-column relations can only be applied to clustering columns but was applied to: a",
|
||||
"SELECT * FROM %s WHERE (a) >= (1) and (a) < (4)");
|
||||
|
|
@ -604,9 +610,9 @@ public class SelectSingleColumnRelationTest extends CQLTester
|
|||
createTable("CREATE TABLE %s (a int, b int, c text, PRIMARY KEY ((a, b)))");
|
||||
assertInvalidMessage("Multi-column relations can only be applied to clustering columns but was applied to: a",
|
||||
"SELECT * FROM %s WHERE (a, b) >= (1, 1) and (a, b) < (4, 1)");
|
||||
assertInvalidMessage("Only EQ and IN relation are supported on the partition key (unless you use the token() function)",
|
||||
assertInvalidMessage("Multi-column relations can only be applied to clustering columns but was applied to: a",
|
||||
"SELECT * FROM %s WHERE a >= 1 and (a, b) < (4, 1)");
|
||||
assertInvalidMessage("Only EQ and IN relation are supported on the partition key (unless you use the token() function)",
|
||||
assertInvalidMessage("Multi-column relations can only be applied to clustering columns but was applied to: a",
|
||||
"SELECT * FROM %s WHERE b >= 1 and (a, b) < (4, 1)");
|
||||
assertInvalidMessage("Multi-column relations can only be applied to clustering columns but was applied to: a",
|
||||
"SELECT * FROM %s WHERE (a, b) >= (1, 1) and (b) < (4)");
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -112,7 +112,7 @@ public class CassandraIndexTest extends CQLTester
|
|||
.indexName("k1_index")
|
||||
.withFirstRow(row(0, 0, 0, 0, 0))
|
||||
.withSecondRow(row(1, 1, 1, 1, 1))
|
||||
.missingIndexMessage("Partition key parts: k2 must be restricted as other parts are")
|
||||
.missingIndexMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE)
|
||||
.firstQueryExpression("k1=0")
|
||||
.secondQueryExpression("k1=1")
|
||||
.run();
|
||||
|
|
@ -127,7 +127,7 @@ public class CassandraIndexTest extends CQLTester
|
|||
.indexName("k2_index")
|
||||
.withFirstRow(row(0, 0, 0, 0, 0))
|
||||
.withSecondRow(row(1, 1, 1, 1, 1))
|
||||
.missingIndexMessage("Partition key parts: k1 must be restricted as other parts are")
|
||||
.missingIndexMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE)
|
||||
.firstQueryExpression("k2=0")
|
||||
.secondQueryExpression("k2=1")
|
||||
.run();
|
||||
|
|
|
|||
Loading…
Reference in New Issue