diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java index a2c4817229..913d23c4d0 100644 --- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java +++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java @@ -1554,6 +1554,12 @@ public class DatabaseDescriptor return conf.row_cache_size_in_mb; } + @VisibleForTesting + public static void setRowCacheSizeInMB(long val) + { + conf.row_cache_size_in_mb = val; + } + public static int getRowCacheSavePeriod() { return conf.row_cache_save_period; diff --git a/src/java/org/apache/cassandra/cql3/ResultSet.java b/src/java/org/apache/cassandra/cql3/ResultSet.java index 281923c881..ea26f344e9 100644 --- a/src/java/org/apache/cassandra/cql3/ResultSet.java +++ b/src/java/org/apache/cassandra/cql3/ResultSet.java @@ -254,6 +254,15 @@ public class ResultSet return new ResultMetadata(EnumSet.copyOf(flags), names, columnCount, pagingState); } + /** + * Return only the column names requested by the user, excluding those added for post-query re-orderings, + * see definition of names and columnCount. + **/ + public List requestNames() + { + return names.subList(0, columnCount); + } + // The maximum number of values that the ResultSet can hold. This can be bigger than columnCount due to CASSANDRA-4911 public int valueCount() { diff --git a/src/java/org/apache/cassandra/cql3/UntypedResultSet.java b/src/java/org/apache/cassandra/cql3/UntypedResultSet.java index bf3cbb5a99..49e0d86c53 100644 --- a/src/java/org/apache/cassandra/cql3/UntypedResultSet.java +++ b/src/java/org/apache/cassandra/cql3/UntypedResultSet.java @@ -95,7 +95,7 @@ public abstract class UntypedResultSet implements Iterable public List metadata() { - return cqlRows.metadata.names; + return cqlRows.metadata.requestNames(); } } diff --git a/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java b/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java index b1751a28c0..0661b563f0 100644 --- a/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java @@ -38,9 +38,11 @@ import org.apache.cassandra.service.ClientState; import org.apache.cassandra.service.ClientWarn; import org.apache.cassandra.service.QueryState; import org.apache.cassandra.service.StorageProxy; +import org.apache.cassandra.thrift.Column; import org.apache.cassandra.tracing.Tracing; import org.apache.cassandra.transport.messages.ResultMessage; import org.apache.cassandra.utils.NoSpamLogger; +import org.apache.cassandra.utils.Pair; /** * A BATCH statement parsed from a CQL query. @@ -342,11 +344,32 @@ public class BatchStatement implements CQLStatement private ResultMessage executeWithConditions(BatchQueryOptions options, QueryState state) throws RequestExecutionException, RequestValidationException + { + Pair> p = makeCasRequest(options, state); + CQL3CasRequest casRequest = p.left; + Set columnsWithConditions = p.right; + + ColumnFamily result = StorageProxy.cas(casRequest.cfm.ksName, + casRequest.cfm.cfName, + casRequest.key, + casRequest, + options.getSerialConsistency(), + options.getConsistency(), + state.getClientState()); + + return new ResultMessage.Rows(ModificationStatement.buildCasResultSet(casRequest.cfm.ksName, + casRequest.key, + casRequest.cfm.cfName, + result, + columnsWithConditions, + true, + options.forStatement(0))); + } + + private Pair> makeCasRequest(BatchQueryOptions options, QueryState state) { long now = state.getTimestamp(); ByteBuffer key = null; - String ksName = null; - String cfName = null; CQL3CasRequest casRequest = null; Set columnsWithConditions = new LinkedHashSet<>(); @@ -361,8 +384,6 @@ public class BatchStatement implements CQLStatement if (key == null) { key = pks.get(0); - ksName = statement.cfm.ksName; - cfName = statement.cfm.cfName; casRequest = new CQL3CasRequest(statement.cfm, key, true); } else if (!key.equals(pks.get(0))) @@ -383,23 +404,49 @@ public class BatchStatement implements CQLStatement casRequest.addRowUpdate(clusteringPrefix, statement, statementOptions, timestamp); } - ColumnFamily result = StorageProxy.cas(ksName, cfName, key, casRequest, options.getSerialConsistency(), options.getConsistency(), state.getClientState()); - - return new ResultMessage.Rows(ModificationStatement.buildCasResultSet(ksName, key, cfName, result, columnsWithConditions, true, options.forStatement(0))); + return Pair.create(casRequest, columnsWithConditions); } public ResultMessage executeInternal(QueryState queryState, QueryOptions options) throws RequestValidationException, RequestExecutionException { - assert !hasConditions; + if (hasConditions) + return executeInternalWithConditions(BatchQueryOptions.withoutPerStatementVariables(options), queryState); + + executeInternalWithoutCondition(queryState, options); + return new ResultMessage.Void(); + } + + private ResultMessage executeInternalWithoutCondition(QueryState queryState, QueryOptions options) throws RequestValidationException, RequestExecutionException + { for (IMutation mutation : getMutations(BatchQueryOptions.withoutPerStatementVariables(options), true, queryState.getTimestamp())) { - // We don't use counters internally. - assert mutation instanceof Mutation; - ((Mutation) mutation).apply(); + assert mutation instanceof Mutation || mutation instanceof CounterMutation; + + if (mutation instanceof Mutation) + ((Mutation) mutation).apply(); + else if (mutation instanceof CounterMutation) + ((CounterMutation) mutation).apply(); } return null; } + private ResultMessage executeInternalWithConditions(BatchQueryOptions options, QueryState state) throws RequestExecutionException, RequestValidationException + { + Pair> p = makeCasRequest(options, state); + CQL3CasRequest request = p.left; + Set columnsWithConditions = p.right; + + ColumnFamily result = ModificationStatement.casInternal(request, state); + + return new ResultMessage.Rows(ModificationStatement.buildCasResultSet(request.cfm.ksName, + request.key, + request.cfm.cfName, + result, + columnsWithConditions, + true, + options.forStatement(0))); + } + public interface BatchVariables { public List getVariablesForStatement(int statementInBatch); diff --git a/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java b/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java index 4ff9c27c97..081a14e9e3 100644 --- a/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java +++ b/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java @@ -36,10 +36,10 @@ import org.apache.cassandra.utils.Pair; */ public class CQL3CasRequest implements CASRequest { - private final CFMetaData cfm; - private final ByteBuffer key; - private final long now; - private final boolean isBatch; + final CFMetaData cfm; + final ByteBuffer key; + final long now; + final boolean isBatch; // We index RowCondition by the prefix of the row they applied to for 2 reasons: // 1) this allows to keep things sorted to build the ColumnSlice array below diff --git a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java index 0862a9fd7b..aac94bed5f 100644 --- a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java @@ -26,6 +26,7 @@ import com.google.common.collect.Lists; import org.apache.cassandra.auth.Permission; import org.apache.cassandra.config.CFMetaData; import org.apache.cassandra.config.ColumnDefinition; +import org.apache.cassandra.config.Schema; import org.apache.cassandra.cql3.*; import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.restrictions.Restriction; @@ -41,9 +42,12 @@ import org.apache.cassandra.exceptions.*; import org.apache.cassandra.service.ClientState; import org.apache.cassandra.service.QueryState; import org.apache.cassandra.service.StorageProxy; +import org.apache.cassandra.service.paxos.Commit; import org.apache.cassandra.thrift.ThriftValidation; import org.apache.cassandra.transport.messages.ResultMessage; +import org.apache.cassandra.triggers.TriggerExecutor; import org.apache.cassandra.utils.Pair; +import org.apache.cassandra.utils.UUIDGen; import static org.apache.cassandra.cql3.statements.RequestValidations.checkFalse; import static org.apache.cassandra.cql3.statements.RequestValidations.checkNotNull; @@ -485,6 +489,20 @@ public abstract class ModificationStatement implements CQLStatement public ResultMessage executeWithCondition(QueryState queryState, QueryOptions options) throws RequestExecutionException, RequestValidationException + { + CQL3CasRequest request = makeCasRequest(queryState, options); + + ColumnFamily result = StorageProxy.cas(keyspace(), + columnFamily(), + request.key, + request, + options.getSerialConsistency(), + options.getConsistency(), + queryState.getClientState()); + return new ResultMessage.Rows(buildCasResultSet(request.key, result, options)); + } + + private CQL3CasRequest makeCasRequest(QueryState queryState, QueryOptions options) { List keys = buildPartitionKeyNames(options); // We don't support IN for CAS operation so far @@ -498,15 +516,7 @@ public abstract class ModificationStatement implements CQLStatement CQL3CasRequest request = new CQL3CasRequest(cfm, key, false); addConditions(prefix, request, options); request.addRowUpdate(prefix, this, options, now); - - ColumnFamily result = StorageProxy.cas(keyspace(), - columnFamily(), - key, - request, - options.getSerialConsistency(), - options.getConsistency(), - queryState.getClientState()); - return new ResultMessage.Rows(buildCasResultSet(key, result, options)); + return request; } public void addConditions(Composite clusteringPrefix, CQL3CasRequest request, QueryOptions options) throws InvalidRequestException @@ -608,9 +618,13 @@ public abstract class ModificationStatement implements CQLStatement public ResultMessage executeInternal(QueryState queryState, QueryOptions options) throws RequestValidationException, RequestExecutionException { - if (hasConditions()) - throw new UnsupportedOperationException(); + return hasConditions() + ? executeInternalWithCondition(queryState, options) + : executeInternalWithoutCondition(queryState, options); + } + public ResultMessage executeInternalWithoutCondition(QueryState queryState, QueryOptions options) throws RequestValidationException, RequestExecutionException + { for (IMutation mutation : getMutations(options, true, queryState.getTimestamp())) { assert mutation instanceof Mutation || mutation instanceof CounterMutation; @@ -623,6 +637,40 @@ public abstract class ModificationStatement implements CQLStatement return null; } + public ResultMessage executeInternalWithCondition(QueryState state, QueryOptions options) throws RequestValidationException, RequestExecutionException + { + CQL3CasRequest request = makeCasRequest(state, options); + ColumnFamily result = casInternal(request, state); + return new ResultMessage.Rows(buildCasResultSet(request.key, result, options)); + } + + static ColumnFamily casInternal(CQL3CasRequest request, QueryState state) + { + long millis = state.getTimestamp() / 1000; + long nanos = ((state.getTimestamp() - (millis * 1000)) + 1) * 10; + UUID ballot = UUIDGen.getTimeUUID(millis, nanos); + CFMetaData metadata = Schema.instance.getCFMetaData(request.cfm.ksName, request.cfm.cfName); + + ReadCommand readCommand = ReadCommand.create(request.cfm.ksName, request.key, request.cfm.cfName, request.now, request.readFilter()); + Keyspace keyspace = Keyspace.open(request.cfm.ksName); + + Row row = readCommand.getRow(keyspace); + ColumnFamily current = row.cf; + if (!request.appliesTo(current)) + { + if (current == null) + current = ArrayBackedSortedColumns.factory.create(metadata); + return current; + } + + ColumnFamily updates = request.makeUpdates(current); + updates = TriggerExecutor.instance.execute(request.key, updates); + + Commit proposal = Commit.newProposal(request.key, ballot, updates); + proposal.makeMutation().apply(); + return null; + } + /** * Convert statement into a list of mutations to apply on the server * diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java index 8ce555ffb2..e2708cd3f4 100644 --- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java @@ -164,37 +164,13 @@ public class SelectStatement implements CQLStatement int limit = getLimit(options); long now = System.currentTimeMillis(); Pageable command = getPageableCommand(options, limit, now); - - int pageSize = options.getPageSize(); - - // An aggregation query will never be paged for the user, but we always page it internally to avoid OOM. - // If we user provided a pageSize we'll use that to page internally (because why not), otherwise we use our default - // Note that if there are some nodes in the cluster with a version less than 2.0, we can't use paging (CASSANDRA-6707). - if (selection.isAggregate() && pageSize <= 0) - pageSize = DEFAULT_COUNT_PAGE_SIZE; + int pageSize = getPageSize(options); if (pageSize <= 0 || command == null || !QueryPagers.mayNeedPaging(command, pageSize)) - { return execute(command, options, limit, now, state); - } QueryPager pager = QueryPagers.pager(command, cl, state.getClientState(), options.getPagingState()); - - if (selection.isAggregate()) - return pageAggregateQuery(pager, options, pageSize, now); - - // We can't properly do post-query ordering if we page (see #6722) - checkFalse(needsPostQueryOrdering(), - "Cannot page queries with both ORDER BY and a IN restriction on the partition key;" - + " you must either remove the ORDER BY or the IN and sort client side, or disable paging for this query"); - - List page = pager.fetchPage(pageSize); - ResultMessage.Rows msg = processResults(page, options, limit, now); - - if (!pager.isExhausted()) - msg.result.metadata.setHasMorePages(pager.state()); - - return msg; + return execute(pager, options, limit, now, pageSize); } private Pageable getPageableCommand(QueryOptions options, int limit, long now) throws RequestValidationException @@ -212,7 +188,21 @@ public class SelectStatement implements CQLStatement return getPageableCommand(options, getLimit(options), System.currentTimeMillis()); } - private ResultMessage.Rows execute(Pageable command, QueryOptions options, int limit, long now, QueryState state) throws RequestValidationException, RequestExecutionException + private int getPageSize(QueryOptions options) + { + int pageSize = options.getPageSize(); + + // An aggregation query will never be paged for the user, but we always page it internally to avoid OOM. + // If we user provided a pageSize we'll use that to page internally (because why not), otherwise we use our default + // Note that if there are some nodes in the cluster with a version less than 2.0, we can't use paging (CASSANDRA-6707). + if (selection.isAggregate() && pageSize <= 0) + pageSize = DEFAULT_COUNT_PAGE_SIZE; + + return pageSize; + } + + private ResultMessage.Rows execute(Pageable command, QueryOptions options, int limit, long now, QueryState state) + throws RequestValidationException, RequestExecutionException { List rows; if (command == null) @@ -229,6 +219,26 @@ public class SelectStatement implements CQLStatement return processResults(rows, options, limit, now); } + private ResultMessage.Rows execute(QueryPager pager, QueryOptions options, int limit, long now, int pageSize) + throws RequestValidationException, RequestExecutionException + { + if (selection.isAggregate()) + return pageAggregateQuery(pager, options, pageSize, now); + + // We can't properly do post-query ordering if we page (see #6722) + checkFalse(needsPostQueryOrdering(), + "Cannot page queries with both ORDER BY and a IN restriction on the partition key;" + + " you must either remove the ORDER BY or the IN and sort client side, or disable paging for this query"); + + List page = pager.fetchPage(pageSize); + ResultMessage.Rows msg = processResults(page, options, limit, now); + + if (!pager.isExhausted()) + msg.result.metadata.setHasMorePages(pager.state()); + + return msg; + } + private ResultMessage.Rows pageAggregateQuery(QueryPager pager, QueryOptions options, int pageSize, long now) throws RequestValidationException, RequestExecutionException { @@ -267,13 +277,21 @@ public class SelectStatement implements CQLStatement int limit = getLimit(options); long now = System.currentTimeMillis(); Pageable command = getPageableCommand(options, limit, now); - List rows = command == null - ? Collections.emptyList() - : (command instanceof Pageable.ReadCommands - ? readLocally(keyspace(), ((Pageable.ReadCommands)command).commands) - : ((RangeSliceCommand)command).executeLocally()); + int pageSize = getPageSize(options); - return processResults(rows, options, limit, now); + if (pageSize <= 0 || command == null || !QueryPagers.mayNeedPaging(command, pageSize)) + { + List rows = command == null + ? Collections.emptyList() + : (command instanceof Pageable.ReadCommands + ? readLocally(keyspace(), ((Pageable.ReadCommands)command).commands) + : ((RangeSliceCommand)command).executeLocally()); + + return processResults(rows, options, limit, now); + } + + QueryPager pager = QueryPagers.localPager(command); + return execute(pager, options, limit, now, pageSize); } public ResultSet process(List rows) throws InvalidRequestException diff --git a/src/java/org/apache/cassandra/cql3/statements/TruncateStatement.java b/src/java/org/apache/cassandra/cql3/statements/TruncateStatement.java index 16c531c1f2..9234a79849 100644 --- a/src/java/org/apache/cassandra/cql3/statements/TruncateStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/TruncateStatement.java @@ -22,6 +22,8 @@ import java.util.concurrent.TimeoutException; import org.apache.cassandra.auth.Permission; import org.apache.cassandra.cql3.*; +import org.apache.cassandra.db.ColumnFamilyStore; +import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.exceptions.*; import org.apache.cassandra.transport.messages.ResultMessage; import org.apache.cassandra.service.ClientState; @@ -71,6 +73,15 @@ public class TruncateStatement extends CFStatement implements CQLStatement public ResultMessage executeInternal(QueryState state, QueryOptions options) { - throw new UnsupportedOperationException(); + try + { + ColumnFamilyStore cfs = Keyspace.open(keyspace()).getColumnFamilyStore(columnFamily()); + cfs.truncateBlocking(); + } + catch (Exception e) + { + throw new TruncateException(e); + } + return null; } } diff --git a/src/java/org/apache/cassandra/service/StorageProxy.java b/src/java/org/apache/cassandra/service/StorageProxy.java index 7801c3e0a7..ac42eb02d2 100644 --- a/src/java/org/apache/cassandra/service/StorageProxy.java +++ b/src/java/org/apache/cassandra/service/StorageProxy.java @@ -228,7 +228,9 @@ public class StorageProxy implements StorageProxyMBean Tracing.trace("Reading existing values for CAS precondition"); long timestamp = System.currentTimeMillis(); ReadCommand readCommand = ReadCommand.create(keyspaceName, key, cfName, timestamp, request.readFilter()); - List rows = read(Arrays.asList(readCommand), consistencyForPaxos == ConsistencyLevel.LOCAL_SERIAL ? ConsistencyLevel.LOCAL_QUORUM : ConsistencyLevel.QUORUM); + List rows = read(Arrays.asList(readCommand), consistencyForPaxos == ConsistencyLevel.LOCAL_SERIAL + ? ConsistencyLevel.LOCAL_QUORUM + : ConsistencyLevel.QUORUM); ColumnFamily current = rows.get(0).cf; if (!request.appliesTo(current)) { diff --git a/src/java/org/apache/cassandra/utils/UUIDGen.java b/src/java/org/apache/cassandra/utils/UUIDGen.java index 33f14a4d23..16190e2977 100644 --- a/src/java/org/apache/cassandra/utils/UUIDGen.java +++ b/src/java/org/apache/cassandra/utils/UUIDGen.java @@ -82,10 +82,15 @@ public class UUIDGen return new UUID(createTime(fromUnixTimestamp(when)), clockSeqAndNode); } - @VisibleForTesting - public static UUID getTimeUUID(long when, long clockSeqAndNode) + public static UUID getTimeUUID(long when, long nanos) { - return new UUID(createTime(fromUnixTimestamp(when)), clockSeqAndNode); + return new UUID(createTime(fromUnixTimestamp(when, nanos)), clockSeqAndNode); + } + + @VisibleForTesting + public static UUID getTimeUUID(long when, long nanos, long clockSeqAndNode) + { + return new UUID(createTime(fromUnixTimestamp(when, nanos)), clockSeqAndNode); } /** creates a type 1 uuid from raw bytes. */ @@ -169,7 +174,12 @@ public class UUIDGen * @return */ private static long fromUnixTimestamp(long timestamp) { - return (timestamp - START_EPOCH) * 10000; + return fromUnixTimestamp(timestamp, 0L); + } + + private static long fromUnixTimestamp(long timestamp, long nanos) + { + return ((timestamp - START_EPOCH) * 10000) + nanos; } /** diff --git a/test/long/org/apache/cassandra/cql3/ManyRowsTest.java b/test/long/org/apache/cassandra/cql3/ManyRowsTest.java new file mode 100644 index 0000000000..82eeabdacf --- /dev/null +++ b/test/long/org/apache/cassandra/cql3/ManyRowsTest.java @@ -0,0 +1,92 @@ +/* + * 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 java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + +import org.junit.Test; + +public class ManyRowsTest extends CQLTester +{ + /** + * Migrated from cql_tests.py:TestCQL.large_count_test() + */ + @Test + public void testLargeCount() throws Throwable + { + createTable("CREATE TABLE %s (k int, v int, PRIMARY KEY (k))"); + + // We know we page at 10K, so test counting just before, at 10K, just after and + // a bit after that. + for (int k = 1; k < 10000; k++) + execute("INSERT INTO %s (k) VALUES (?)", k); + + assertRows(execute("SELECT COUNT(*) FROM %s"), row(9999L)); + + execute("INSERT INTO %s (k) VALUES (?)", 10000); + + assertRows(execute("SELECT COUNT(*) FROM %s"), row(10000L)); + + execute("INSERT INTO %s (k) VALUES (?)", 10001); + + assertRows(execute("SELECT COUNT(*) FROM %s"), row(10001L)); + + for (int k = 10002; k < 15001; k++) + execute("INSERT INTO %s (k) VALUES (?)", k); + + assertRows(execute("SELECT COUNT(*) FROM %s"), row(15000L)); + } + + /** + * Test for CASSANDRA-8410, + * migrated from cql_tests.py:TestCQL.large_clustering_in_test() + */ + @Test + public void testLargeClustering() throws Throwable + { + createTable("CREATE TABLE %s (k int, c int, v int, PRIMARY KEY (k, c) )"); + + execute("INSERT INTO %s (k, c, v) VALUES (?, ?, ?)", 0, 0, 0); + + // try to fetch one existing row and 9999 non-existing rows + List inValues = new ArrayList(10000); + for (int i = 0; i < 10000; i++) + inValues.add(i); + + assertRows(execute("SELECT * FROM %s WHERE k=? AND c IN ?", 0, inValues), + row(0, 0, 0)); + + // insert approximately 1000 random rows between 0 and 10k + Random rnd = new Random(); + Set clusteringValues = new HashSet<>(); + for (int i = 0; i < 1000; i++) + clusteringValues.add(rnd.nextInt(10000)); + + clusteringValues.add(0); + + for (int i : clusteringValues) // TODO - this was done in parallel by dtests + execute("INSERT INTO %s (k, c, v) VALUES (?, ?, ?)", 0, i, i); + + assertRowCount(execute("SELECT * FROM %s WHERE k=? AND c IN ?", 0, inValues), clusteringValues.size()); + } +} diff --git a/test/unit/org/apache/cassandra/cql3/AliasTest.java b/test/unit/org/apache/cassandra/cql3/AliasTest.java deleted file mode 100644 index 132aa04574..0000000000 --- a/test/unit/org/apache/cassandra/cql3/AliasTest.java +++ /dev/null @@ -1,40 +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; - -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"); - - } -} diff --git a/test/unit/org/apache/cassandra/cql3/CQLTester.java b/test/unit/org/apache/cassandra/cql3/CQLTester.java index d47b9d2a26..4b4631e906 100644 --- a/test/unit/org/apache/cassandra/cql3/CQLTester.java +++ b/test/unit/org/apache/cassandra/cql3/CQLTester.java @@ -35,11 +35,18 @@ import org.junit.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.datastax.driver.core.*; +import static junit.framework.Assert.assertNotNull; +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.ColumnDefinitions; +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.ProtocolVersion; import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; import org.apache.cassandra.SchemaLoader; import org.apache.cassandra.concurrent.ScheduledExecutors; import org.apache.cassandra.config.CFMetaData; +import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.config.Schema; import org.apache.cassandra.cql3.functions.FunctionName; import org.apache.cassandra.cql3.statements.ParsedStatement; @@ -51,6 +58,7 @@ import org.apache.cassandra.db.marshal.TupleType; import org.apache.cassandra.exceptions.CassandraException; import org.apache.cassandra.exceptions.ConfigurationException; import org.apache.cassandra.exceptions.SyntaxException; +import org.apache.cassandra.dht.Murmur3Partitioner; import org.apache.cassandra.io.util.FileUtils; import org.apache.cassandra.serializers.TypeSerializer; import org.apache.cassandra.service.ClientState; @@ -71,6 +79,7 @@ public abstract class CQLTester public static final String KEYSPACE = "cql_test_keyspace"; public static final String KEYSPACE_PER_TEST = "cql_test_keyspace_alt"; protected static final boolean USE_PREPARED_VALUES = Boolean.valueOf(System.getProperty("cassandra.test.use_prepared", "true")); + protected static final long ROW_CACHE_SIZE_IN_MB = Integer.valueOf(System.getProperty("cassandra.test.row_cache_size_in_mb", "0")); private static final AtomicInteger seqNumber = new AtomicInteger(); private static org.apache.cassandra.transport.Server server; @@ -79,7 +88,7 @@ public abstract class CQLTester private static final Cluster[] cluster; private static final Session[] session; - static int maxProtocolVersion; + public static int maxProtocolVersion; static { int version; for (version = 1; version <= Server.CURRENT_VERSION; ) @@ -129,9 +138,12 @@ public abstract class CQLTester private boolean usePrepared = USE_PREPARED_VALUES; @BeforeClass - public static void setUpClass() throws Throwable + public static void setUpClass() { - schemaChange(String.format("CREATE KEYSPACE IF NOT EXISTS %s WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}", KEYSPACE)); + if (ROW_CACHE_SIZE_IN_MB > 0) + DatabaseDescriptor.setRowCacheSizeInMB(ROW_CACHE_SIZE_IN_MB); + + DatabaseDescriptor.setPartitioner(Murmur3Partitioner.instance); } @AfterClass @@ -151,6 +163,7 @@ public abstract class CQLTester @Before public void beforeTest() throws Throwable { + schemaChange(String.format("CREATE KEYSPACE IF NOT EXISTS %s WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}", KEYSPACE)); schemaChange(String.format("CREATE KEYSPACE IF NOT EXISTS %s WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}", KEYSPACE_PER_TEST)); } @@ -178,16 +191,16 @@ public abstract class CQLTester { try { - for (int i = tablesToDrop.size() - 1; i >=0; i--) + for (int i = tablesToDrop.size() - 1; i >= 0; i--) schemaChange(String.format("DROP TABLE IF EXISTS %s.%s", KEYSPACE, tablesToDrop.get(i))); - for (int i = aggregatesToDrop.size() - 1; i >=0; i--) + for (int i = aggregatesToDrop.size() - 1; i >= 0; i--) schemaChange(String.format("DROP AGGREGATE IF EXISTS %s", aggregatesToDrop.get(i))); - for (int i = functionsToDrop.size() - 1; i >=0; i--) + for (int i = functionsToDrop.size() - 1; i >= 0; i--) schemaChange(String.format("DROP FUNCTION IF EXISTS %s", functionsToDrop.get(i))); - for (int i = typesToDrop.size() - 1; i >=0; i--) + for (int i = typesToDrop.size() - 1; i >= 0; i--) schemaChange(String.format("DROP TYPE IF EXISTS %s.%s", KEYSPACE, typesToDrop.get(i))); // Dropping doesn't delete the sstables. It's not a huge deal but it's cleaner to cleanup after us @@ -198,10 +211,10 @@ public abstract class CQLTester final CountDownLatch latch = new CountDownLatch(1); ScheduledExecutors.nonPeriodicTasks.execute(new Runnable() { - public void run() - { - latch.countDown(); - } + public void run() + { + latch.countDown(); + } }); latch.await(2, TimeUnit.SECONDS); @@ -272,9 +285,25 @@ public abstract class CQLTester } } - public boolean usePrepared() + public void compact() { - return USE_PREPARED_VALUES; + try + { + String currentTable = currentTable(); + if (currentTable != null) + Keyspace.open(KEYSPACE).getColumnFamilyStore(currentTable).forceMajorCompaction(); + } + catch (InterruptedException | ExecutionException e) + { + throw new RuntimeException(e); + } + } + + public void cleanupCache() + { + String currentTable = currentTable(); + if (currentTable != null) + Keyspace.open(KEYSPACE).getColumnFamilyStore(currentTable).cleanupCache(); } public static FunctionName parseFunctionName(String qualifiedName) @@ -379,14 +408,20 @@ public abstract class CQLTester protected String createTable(String query) { - String currentTable = "table_" + seqNumber.getAndIncrement(); - tables.add(currentTable); + String currentTable = createTableName(); String fullQuery = formatQuery(query); logger.info(fullQuery); schemaChange(fullQuery); return currentTable; } + protected String createTableName() + { + String currentTable = "table_" + seqNumber.getAndIncrement(); + tables.add(currentTable); + return currentTable; + } + protected void createTableMayThrow(String query) throws Throwable { String currentTable = "table_" + seqNumber.getAndIncrement(); @@ -424,6 +459,37 @@ public abstract class CQLTester schemaChange(fullQuery); } + /** + * Index creation is asynchronous, this method searches in the system table IndexInfo + * for the specified index and returns true if it finds it, which indicates the + * index was built. If we haven't found it after 5 seconds we give-up. + */ + protected boolean waitForIndex(String keyspace, String table, String index) throws Throwable + { + long start = System.currentTimeMillis(); + boolean indexCreated = false; + String indedName = String.format("%s.%s", table, index); + while (!indexCreated) + { + Object[][] results = getRows(execute("select index_name from system.\"IndexInfo\" where table_name = ?", keyspace)); + for(int i = 0; i < results.length; i++) + { + if (indedName.equals(results[i][0])) + { + indexCreated = true; + break; + } + } + + if (System.currentTimeMillis() - start > 5000) + break; + + Thread.sleep(10); + } + + return indexCreated; + } + protected void createIndexMayThrow(String query) throws Throwable { String fullQuery = formatQuery(query); @@ -593,7 +659,7 @@ public abstract class CQLTester Object[] expected = rows[i]; UntypedResultSet.Row actual = iter.next(); - Assert.assertEquals(String.format("Invalid number of (expected) values provided for row %d", i), meta.size(), expected.length); + Assert.assertEquals(String.format("Invalid number of (expected) values provided for row %d", i), expected.length, meta.size()); for (int j = 0; j < meta.size(); j++) { @@ -602,8 +668,17 @@ public abstract class CQLTester ByteBuffer actualValue = actual.getBytes(column.name.toString()); if (!Objects.equal(expectedByteValue, actualValue)) - Assert.fail(String.format("Invalid value for row %d column %d (%s of type %s), expected <%s> but got <%s>", - i, j, column.name, column.type.asCQL3Type(), formatValue(expectedByteValue, column.type), formatValue(actualValue, column.type))); + { + Object actualValueDecoded = column.type.getSerializer().deserialize(actualValue); + if (!actualValueDecoded.equals(expected[j])) + Assert.fail(String.format("Invalid value for row %d column %d (%s of type %s), expected <%s> but got <%s>", + i, + j, + column.name, + column.type.asCQL3Type(), + formatValue(expectedByteValue, column.type), + formatValue(actualValue, column.type))); + } } i++; } @@ -621,6 +696,65 @@ public abstract class CQLTester Assert.assertTrue(String.format("Got %s rows than expected. Expected %d but got %d", rows.length>i ? "less" : "more", rows.length, i), i == rows.length); } + protected void assertRowCount(UntypedResultSet result, int numExpectedRows) + { + if (result == null) + { + if (numExpectedRows > 0) + Assert.fail(String.format("No rows returned by query but %d expected", numExpectedRows)); + return; + } + + List meta = result.metadata(); + Iterator iter = result.iterator(); + int i = 0; + while (iter.hasNext() && i < numExpectedRows) + { + UntypedResultSet.Row actual = iter.next(); + assertNotNull(actual); + i++; + } + + if (iter.hasNext()) + { + while (iter.hasNext()) + { + iter.next(); + i++; + } + Assert.fail(String.format("Got less rows than expected. Expected %d but got %d.", numExpectedRows, i)); + } + + Assert.assertTrue(String.format("Got %s rows than expected. Expected %d but got %d", numExpectedRows>i ? "less" : "more", numExpectedRows, i), i == numExpectedRows); + } + + protected Object[][] getRows(UntypedResultSet result) + { + if (result == null) + return new Object[0][]; + + List ret = new ArrayList<>(); + List meta = result.metadata(); + + Iterator iter = result.iterator(); + while (iter.hasNext()) + { + UntypedResultSet.Row rowVal = iter.next(); + Object[] row = new Object[meta.size()]; + for (int j = 0; j < meta.size(); j++) + { + ColumnSpecification column = meta.get(j); + ByteBuffer val = rowVal.getBytes(column.name.toString()); + row[j] = val == null ? null : column.type.getSerializer().deserialize(val); + } + + ret.add(row); + } + + Object[][] a = new Object[ret.size()][]; + return ret.toArray(a); + } + protected void assertColumnNames(UntypedResultSet result, String... expectedColumnNames) { if (result == null) diff --git a/test/unit/org/apache/cassandra/cql3/ContainsRelationTest.java b/test/unit/org/apache/cassandra/cql3/ContainsRelationTest.java deleted file mode 100644 index a987bb2366..0000000000 --- a/test/unit/org/apache/cassandra/cql3/ContainsRelationTest.java +++ /dev/null @@ -1,283 +0,0 @@ -package org.apache.cassandra.cql3; - -import org.junit.Test; - -public class ContainsRelationTest extends CQLTester -{ - @Test - public void testSetContains() throws Throwable - { - createTable("CREATE TABLE %s (account text, id int, categories set, PRIMARY KEY (account, id))"); - createIndex("CREATE INDEX ON %s(categories)"); - - execute("INSERT INTO %s (account, id , categories) VALUES (?, ?, ?)", "test", 5, set("lmn")); - - assertEmpty(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ?", "xyz", "lmn")); - - assertRows(execute("SELECT * FROM %s WHERE categories CONTAINS ?", "lmn"), - row("test", 5, set("lmn")) - ); - - assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ?", "test", "lmn"), - row("test", 5, set("lmn")) - ); - - assertRows(execute("SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, "lmn"), - row("test", 5, set("lmn")) - ); - - assertInvalidMessage("Unsupported null value for indexed column categories", - "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, null); - - assertInvalidMessage("Unsupported unset value for indexed column categories", - "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, unset()); - - 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")); - } - - @Test - public void testListContains() throws Throwable - { - createTable("CREATE TABLE %s (account text, id int, categories list, PRIMARY KEY (account, id))"); - createIndex("CREATE INDEX ON %s(categories)"); - - execute("INSERT INTO %s (account, id , categories) VALUES (?, ?, ?)", "test", 5, list("lmn")); - - assertEmpty(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ?", "xyz", "lmn")); - - assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ?;", "test", "lmn"), - row("test", 5, list("lmn")) - ); - - assertRows(execute("SELECT * FROM %s WHERE categories CONTAINS ?", "lmn"), - row("test", 5, list("lmn")) - ); - - assertRows(execute("SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?;", "test", 5, "lmn"), - row("test", 5, list("lmn")) - ); - - assertInvalidMessage("Unsupported null value for indexed column categories", - "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, null); - - assertInvalidMessage("Unsupported unset value for indexed column categories", - "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, unset()); - - 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")); - } - - @Test - public void testListContainsWithFiltering() throws Throwable - { - createTable("CREATE TABLE %s (e int PRIMARY KEY, f list, s int)"); - createIndex("CREATE INDEX ON %s(f)"); - for(int i = 0; i < 3; i++) - { - execute("INSERT INTO %s (e, f, s) VALUES (?, ?, ?)", i, list("Dubai"), 4); - } - for(int i = 3; i < 5; i++) - { - execute("INSERT INTO %s (e, f, s) VALUES (?, ?, ?)", i, list("Dubai"), 3); - } - assertRows(execute("SELECT * FROM %s WHERE f CONTAINS ? AND s=? allow filtering", "Dubai", 3), - row(3, list("Dubai"), 3), - row(4, list("Dubai"), 3)); - } - - @Test - public void testMapKeyContains() throws Throwable - { - createTable("CREATE TABLE %s (account text, id int, categories map, PRIMARY KEY (account, id))"); - createIndex("CREATE INDEX ON %s(keys(categories))"); - - execute("INSERT INTO %s (account, id , categories) VALUES (?, ?, ?)", "test", 5, map("lmn", "foo")); - - assertEmpty(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS KEY ?", "xyz", "lmn")); - - assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS KEY ?", "test", "lmn"), - row("test", 5, map("lmn", "foo")) - ); - assertRows(execute("SELECT * FROM %s WHERE categories CONTAINS KEY ?", "lmn"), - row("test", 5, map("lmn", "foo")) - ); - - assertRows(execute("SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS KEY ?", "test", 5, "lmn"), - row("test", 5, map("lmn", "foo")) - ); - - assertInvalidMessage("Unsupported null value for indexed column categories", - "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS KEY ?", "test", 5, null); - - assertInvalidMessage("Unsupported unset value for indexed column categories", - "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS KEY ?", "test", 5, unset()); - - 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")); - - 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 - public void testMapValueContains() throws Throwable - { - createTable("CREATE TABLE %s (account text, id int, categories map, PRIMARY KEY (account, id))"); - createIndex("CREATE INDEX ON %s(categories)"); - - execute("INSERT INTO %s (account, id , categories) VALUES (?, ?, ?)", "test", 5, map("lmn", "foo")); - - assertEmpty(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ?", "xyz", "foo")); - - assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ?", "test", "foo"), - row("test", 5, map("lmn", "foo")) - ); - - assertRows(execute("SELECT * FROM %s WHERE categories CONTAINS ?", "foo"), - row("test", 5, map("lmn", "foo")) - ); - - assertRows(execute("SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, "foo"), - row("test", 5, map("lmn", "foo")) - ); - - assertInvalidMessage("Unsupported null value for indexed column categories", - "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, null); - - assertInvalidMessage("Unsupported unset value for indexed column categories", - "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, unset()); - - 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" - , "test", 5, "foo", "notPresent")); - } - - // See CASSANDRA-7525 - @Test - public void testQueryMultipleIndexTypes() throws Throwable - { - createTable("CREATE TABLE %s (account text, id int, categories map, PRIMARY KEY (account, id))"); - - // create an index on - createIndex("CREATE INDEX id_index ON %s(id)"); - createIndex("CREATE INDEX categories_values_index ON %s(categories)"); - - execute("INSERT INTO %s (account, id , categories) VALUES (?, ?, ?)", "test", 5, map("lmn", "foo")); - - assertRows(execute("SELECT * FROM %s WHERE categories CONTAINS ? AND id = ? ALLOW FILTERING", "foo", 5), - row("test", 5, map("lmn", "foo")) - ); - - assertRows( - execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ? AND id = ? ALLOW FILTERING", "test", "foo", 5), - row("test", 5, map("lmn", "foo")) - ); - } - - // See CASSANDRA-8033 - @Test - public void testFilterForContains() throws Throwable - { - createTable("CREATE TABLE %s (k1 int, k2 int, v set, 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)); - - assertRows(execute("SELECT * FROM %s WHERE k2 = ?", 1), - 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", 1, 7)); - } - - // See CASSANDRA-8073 - @Test - public void testIndexLookupWithClusteringPrefix() throws Throwable - { - createTable("CREATE TABLE %s (a int, b int, c int, d set, PRIMARY KEY (a, b, c))"); - createIndex("CREATE INDEX ON %s(d)"); - execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 0, set(1, 2, 3)); - execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 1, set(3, 4, 5)); - execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 0, set(1, 2, 3)); - execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 1, set(3, 4, 5)); - - assertRows(execute("SELECT * FROM %s WHERE a=? AND b=? AND d CONTAINS ?", 0, 1, 3), - row(0, 1, 0, set(1, 2, 3)), - row(0, 1, 1, set(3, 4, 5)) - ); - - assertRows(execute("SELECT * FROM %s WHERE a=? AND b=? AND d CONTAINS ?", 0, 1, 2), - row(0, 1, 0, set(1, 2, 3)) - ); - - assertRows(execute("SELECT * FROM %s WHERE a=? AND b=? AND d CONTAINS ?", 0, 1, 5), - row(0, 1, 1, set(3, 4, 5)) - ); - } - - @Test - public void testContainsKeyAndContainsWithIndexOnMapKey() throws Throwable - { - createTable("CREATE TABLE %s (account text, id int, categories map, PRIMARY KEY (account, id))"); - createIndex("CREATE INDEX ON %s(keys(categories))"); - - 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")); - - assertInvalidMessage("No secondary indexes on the restricted columns support the provided operators: 'categories CONTAINS '", - "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")), - row("test", 6, map("lmn", "foo2"))); - assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS KEY ? AND categories CONTAINS ? ALLOW FILTERING", - "test", "lmn", "foo"), - row("test", 5, map("lmn", "foo"))); - assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ? AND categories CONTAINS KEY ? ALLOW FILTERING", - "test", "foo", "lmn"), - row("test", 5, map("lmn", "foo"))); - } - - @Test - public void testContainsKeyAndContainsWithIndexOnMapValue() throws Throwable - { - createTable("CREATE TABLE %s (account text, id int, categories map, PRIMARY KEY (account, id))"); - createIndex("CREATE INDEX ON %s(categories)"); - - 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")); - - assertInvalidMessage("No secondary indexes on the restricted columns support the provided operators: 'categories CONTAINS KEY '", - "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")), - row("test", 6, map("lmn2", "foo"))); - assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS KEY ? AND categories CONTAINS ? ALLOW FILTERING", - "test", "lmn", "foo"), - row("test", 5, map("lmn", "foo"))); - assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ? AND categories CONTAINS KEY ? ALLOW FILTERING", - "test", "foo", "lmn"), - row("test", 5, map("lmn", "foo"))); - } -} diff --git a/test/unit/org/apache/cassandra/cql3/CreateAndAlterKeyspaceTest.java b/test/unit/org/apache/cassandra/cql3/CreateAndAlterKeyspaceTest.java deleted file mode 100644 index 9e0ca21643..0000000000 --- a/test/unit/org/apache/cassandra/cql3/CreateAndAlterKeyspaceTest.java +++ /dev/null @@ -1,37 +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; - -import org.junit.Test; - -public class CreateAndAlterKeyspaceTest extends CQLTester -{ - @Test - // tests CASSANDRA-9565 - public void testCreateAndAlterWithDoubleWith() throws Throwable - { - String[] stmts = new String[] {"ALTER KEYSPACE WITH WITH DURABLE_WRITES = true", - "ALTER KEYSPACE ks WITH WITH DURABLE_WRITES = true", - "CREATE KEYSPACE WITH WITH DURABLE_WRITES = true", - "CREATE KEYSPACE ks WITH WITH DURABLE_WRITES = true"}; - - for (String stmt : stmts) { - assertInvalidSyntaxMessage("no viable alternative at input 'WITH'", stmt); - } - } -} diff --git a/test/unit/org/apache/cassandra/cql3/CreateIndexStatementTest.java b/test/unit/org/apache/cassandra/cql3/CreateIndexStatementTest.java deleted file mode 100644 index 1e2e08433d..0000000000 --- a/test/unit/org/apache/cassandra/cql3/CreateIndexStatementTest.java +++ /dev/null @@ -1,101 +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; - -import java.util.Locale; - -import org.apache.commons.lang3.StringUtils; - -import org.junit.Test; - -public class CreateIndexStatementTest extends CQLTester -{ - @Test - public void testCreateAndDropIndex() throws Throwable - { - testCreateAndDropIndex("test", false); - testCreateAndDropIndex("test2", true); - } - - @Test - public void testCreateAndDropIndexWithQuotedIdentifier() throws Throwable - { - testCreateAndDropIndex("\"quoted_ident\"", false); - testCreateAndDropIndex("\"quoted_ident2\"", true); - } - - @Test - public void testCreateAndDropIndexWithCamelCaseIdentifier() throws Throwable - { - testCreateAndDropIndex("CamelCase", false); - testCreateAndDropIndex("CamelCase2", true); - } - - /** - * Test creating and dropping an index with the specified name. - * - * @param indexName the index name - * @param addKeyspaceOnDrop add the keyspace name in the drop statement - * @throws Throwable if an error occurs - */ - private void testCreateAndDropIndex(String indexName, boolean addKeyspaceOnDrop) throws Throwable - { - execute("USE system"); - assertInvalidMessage("Index '" + removeQuotes(indexName.toLowerCase(Locale.US)) + "' could not be found", "DROP INDEX " + indexName + ";"); - - createTable("CREATE TABLE %s (a int primary key, b int);"); - createIndex("CREATE INDEX " + indexName + " ON %s(b);"); - createIndex("CREATE INDEX IF NOT EXISTS " + indexName + " ON %s(b);"); - - assertInvalidMessage("Index already exists", "CREATE INDEX " + indexName + " ON %s(b)"); - - execute("INSERT INTO %s (a, b) values (?, ?);", 0, 0); - execute("INSERT INTO %s (a, b) values (?, ?);", 1, 1); - execute("INSERT INTO %s (a, b) values (?, ?);", 2, 2); - execute("INSERT INTO %s (a, b) values (?, ?);", 3, 1); - - assertRows(execute("SELECT * FROM %s where b = ?", 1), row(1, 1), row(3, 1)); - assertInvalidMessage("Index '" + removeQuotes(indexName.toLowerCase(Locale.US)) + "' could not be found in any of the tables of keyspace 'system'", "DROP INDEX " + indexName); - - if (addKeyspaceOnDrop) - { - dropIndex("DROP INDEX " + KEYSPACE + "." + indexName); - } - else - { - execute("USE " + KEYSPACE); - execute("DROP INDEX " + indexName); - } - - assertInvalidMessage("No secondary indexes on the restricted columns support the provided operators", - "SELECT * FROM %s where b = ?", 1); - dropIndex("DROP INDEX IF EXISTS " + indexName); - assertInvalidMessage("Index '" + removeQuotes(indexName.toLowerCase(Locale.US)) + "' could not be found", "DROP INDEX " + indexName); - } - - /** - * Removes the quotes from the specified index name. - * - * @param indexName the index name from which the quotes must be removed. - * @return the unquoted index name. - */ - private static String removeQuotes(String indexName) - { - return StringUtils.remove(indexName, '\"'); - } -} diff --git a/test/unit/org/apache/cassandra/cql3/CreateTableTest.java b/test/unit/org/apache/cassandra/cql3/CreateTableTest.java deleted file mode 100644 index d14e87b0f3..0000000000 --- a/test/unit/org/apache/cassandra/cql3/CreateTableTest.java +++ /dev/null @@ -1,69 +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; - -import org.junit.Test; - -import org.apache.cassandra.utils.ByteBufferUtil; - -import static junit.framework.Assert.assertFalse; - -public class CreateTableTest extends CQLTester -{ - @Test - public void testCQL3PartitionKeyOnlyTable() - { - createTable("CREATE TABLE %s (id text PRIMARY KEY);"); - assertFalse(currentTableMetadata().isThriftCompatible()); - } - - @Test - public void testCreateTableWithSmallintColumns() throws Throwable - { - createTable("CREATE TABLE %s (a text, b smallint, c smallint, primary key (a, b));"); - execute("INSERT INTO %s (a, b, c) VALUES ('1', 1, 2)"); - execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", "2", Short.MAX_VALUE, Short.MIN_VALUE); - - assertRows(execute("SELECT * FROM %s"), - row("1", (short) 1, (short) 2), - row("2", Short.MAX_VALUE, Short.MIN_VALUE)); - - assertInvalidMessage("Expected 2 bytes for a smallint (4)", - "INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", "3", 1, 2); - assertInvalidMessage("Expected 2 bytes for a smallint (0)", - "INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", "3", (short) 1, ByteBufferUtil.EMPTY_BYTE_BUFFER); - } - - @Test - public void testCreateTinyintColumns() throws Throwable - { - createTable("CREATE TABLE %s (a text, b tinyint, c tinyint, primary key (a, b));"); - execute("INSERT INTO %s (a, b, c) VALUES ('1', 1, 2)"); - execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", "2", Byte.MAX_VALUE, Byte.MIN_VALUE); - - assertRows(execute("SELECT * FROM %s"), - row("1", (byte) 1, (byte) 2), - row("2", Byte.MAX_VALUE, Byte.MIN_VALUE)); - - assertInvalidMessage("Expected 1 byte for a tinyint (4)", - "INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", "3", 1, 2); - - assertInvalidMessage("Expected 1 byte for a tinyint (0)", - "INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", "3", (byte) 1, ByteBufferUtil.EMPTY_BYTE_BUFFER); - } -} diff --git a/test/unit/org/apache/cassandra/cql3/CreateTriggerStatementTest.java b/test/unit/org/apache/cassandra/cql3/CreateTriggerStatementTest.java deleted file mode 100644 index 6557c16640..0000000000 --- a/test/unit/org/apache/cassandra/cql3/CreateTriggerStatementTest.java +++ /dev/null @@ -1,121 +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; - -import java.nio.ByteBuffer; -import java.util.Collection; -import java.util.Collections; - -import org.apache.cassandra.config.CFMetaData; -import org.apache.cassandra.config.Schema; -import org.apache.cassandra.config.TriggerDefinition; -import org.apache.cassandra.db.ColumnFamily; -import org.apache.cassandra.db.Mutation; -import org.apache.cassandra.triggers.ITrigger; -import org.junit.Test; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -public class CreateTriggerStatementTest extends CQLTester -{ - @Test - public void testCreateTrigger() throws Throwable - { - createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY (a))"); - execute("CREATE TRIGGER trigger_1 ON %s USING '" + TestTrigger.class.getName() + "'"); - assertTriggerExists("trigger_1", TestTrigger.class); - execute("CREATE TRIGGER trigger_2 ON %s USING '" + TestTrigger.class.getName() + "'"); - assertTriggerExists("trigger_2", TestTrigger.class); - assertInvalid("CREATE TRIGGER trigger_1 ON %s USING '" + TestTrigger.class.getName() + "'"); - execute("CREATE TRIGGER \"Trigger 3\" ON %s USING '" + TestTrigger.class.getName() + "'"); - assertTriggerExists("Trigger 3", TestTrigger.class); - } - - @Test - public void testCreateTriggerIfNotExists() throws Throwable - { - createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY (a, b))"); - - execute("CREATE TRIGGER IF NOT EXISTS trigger_1 ON %s USING '" + TestTrigger.class.getName() + "'"); - assertTriggerExists("trigger_1", TestTrigger.class); - - execute("CREATE TRIGGER IF NOT EXISTS trigger_1 ON %s USING '" + TestTrigger.class.getName() + "'"); - assertTriggerExists("trigger_1", TestTrigger.class); - } - - @Test - public void testDropTrigger() throws Throwable - { - createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY (a))"); - - execute("CREATE TRIGGER trigger_1 ON %s USING '" + TestTrigger.class.getName() + "'"); - assertTriggerExists("trigger_1", TestTrigger.class); - - execute("DROP TRIGGER trigger_1 ON %s"); - assertTriggerDoesNotExists("trigger_1", TestTrigger.class); - - execute("CREATE TRIGGER trigger_1 ON %s USING '" + TestTrigger.class.getName() + "'"); - assertTriggerExists("trigger_1", TestTrigger.class); - - assertInvalid("DROP TRIGGER trigger_2 ON %s"); - - execute("CREATE TRIGGER \"Trigger 3\" ON %s USING '" + TestTrigger.class.getName() + "'"); - assertTriggerExists("Trigger 3", TestTrigger.class); - - execute("DROP TRIGGER \"Trigger 3\" ON %s"); - assertTriggerDoesNotExists("Trigger 3", TestTrigger.class); - } - - @Test - public void testDropTriggerIfExists() throws Throwable - { - createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY (a))"); - - execute("DROP TRIGGER IF EXISTS trigger_1 ON %s"); - assertTriggerDoesNotExists("trigger_1", TestTrigger.class); - - execute("CREATE TRIGGER trigger_1 ON %s USING '" + TestTrigger.class.getName() + "'"); - assertTriggerExists("trigger_1", TestTrigger.class); - - execute("DROP TRIGGER IF EXISTS trigger_1 ON %s"); - assertTriggerDoesNotExists("trigger_1", TestTrigger.class); - } - - private void assertTriggerExists(String name, Class clazz) - { - CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), currentTable()).copy(); - assertTrue("the trigger does not exist", cfm.containsTriggerDefinition(TriggerDefinition.create(name, - clazz.getName()))); - } - - private void assertTriggerDoesNotExists(String name, Class clazz) - { - CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), currentTable()).copy(); - assertFalse("the trigger exists", cfm.containsTriggerDefinition(TriggerDefinition.create(name, - clazz.getName()))); - } - - public static class TestTrigger implements ITrigger - { - public Collection augment(ByteBuffer key, ColumnFamily update) - { - return Collections.emptyList(); - } - } -} diff --git a/test/unit/org/apache/cassandra/cql3/IndexedValuesValidationTest.java b/test/unit/org/apache/cassandra/cql3/IndexedValuesValidationTest.java deleted file mode 100644 index 487fbc286f..0000000000 --- a/test/unit/org/apache/cassandra/cql3/IndexedValuesValidationTest.java +++ /dev/null @@ -1,149 +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; - -import java.nio.ByteBuffer; -import java.util.HashMap; -import java.util.Map; - -import org.junit.Test; - -import org.apache.cassandra.utils.FBUtilities; - -import static org.junit.Assert.fail; - -public class IndexedValuesValidationTest extends CQLTester -{ - private static final int TOO_BIG = 1024 * 65; - // CASSANDRA-8280/8081 - // reject updates with indexed values where value > 64k - @Test - public void testIndexOnCompositeValueOver64k() throws Throwable - { - createTable("CREATE TABLE %s(a int, b int, c blob, PRIMARY KEY (a))"); - createIndex("CREATE INDEX ON %s(c)"); - failInsert("INSERT INTO %s (a, b, c) VALUES (0, 0, ?)", ByteBuffer.allocate(TOO_BIG)); - } - - @Test - public void testIndexOnClusteringColumnInsertPartitionKeyAndClusteringsOver64k() throws Throwable - { - createTable("CREATE TABLE %s(a blob, b blob, c blob, d int, PRIMARY KEY (a, b, c))"); - createIndex("CREATE INDEX ON %s(b)"); - - // CompositeIndexOnClusteringKey creates index entries composed of the - // PK plus all of the non-indexed clustering columns from the primary row - // so we should reject where len(a) + len(c) > 65560 as this will form the - // total clustering in the index table - ByteBuffer a = ByteBuffer.allocate(100); - ByteBuffer b = ByteBuffer.allocate(10); - ByteBuffer c = ByteBuffer.allocate(FBUtilities.MAX_UNSIGNED_SHORT - 99); - - failInsert("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, 0)", a, b, c); - } - - @Test - public void testCompactTableWithValueOver64k() throws Throwable - { - createTable("CREATE TABLE %s(a int, b blob, PRIMARY KEY (a)) WITH COMPACT STORAGE"); - createIndex("CREATE INDEX ON %s(b)"); - failInsert("INSERT INTO %s (a, b) VALUES (0, ?)", ByteBuffer.allocate(TOO_BIG)); - } - - @Test - public void testIndexOnCollectionValueInsertPartitionKeyAndCollectionKeyOver64k() throws Throwable - { - createTable("CREATE TABLE %s(a blob , b map, PRIMARY KEY (a))"); - createIndex("CREATE INDEX ON %s(b)"); - - // A collection key > 64k by itself will be rejected from - // the primary table. - // To test index validation we need to ensure that - // len(b) < 64k, but len(a) + len(b) > 64k as that will - // form the clustering in the index table - ByteBuffer a = ByteBuffer.allocate(100); - ByteBuffer b = ByteBuffer.allocate(FBUtilities.MAX_UNSIGNED_SHORT - 100); - - failInsert("UPDATE %s SET b[?] = 0 WHERE a = ?", b, a); - } - - @Test - public void testIndexOnCollectionKeyInsertPartitionKeyAndClusteringOver64k() throws Throwable - { - createTable("CREATE TABLE %s(a blob, b blob, c map, PRIMARY KEY (a, b))"); - createIndex("CREATE INDEX ON %s(KEYS(c))"); - - // Basically the same as the case with non-collection clustering - // CompositeIndexOnCollectionKeyy creates index entries composed of the - // PK plus all of the clustering columns from the primary row, except the - // collection element - which becomes the partition key in the index table - ByteBuffer a = ByteBuffer.allocate(100); - ByteBuffer b = ByteBuffer.allocate(FBUtilities.MAX_UNSIGNED_SHORT - 100); - ByteBuffer c = ByteBuffer.allocate(10); - - failInsert("UPDATE %s SET c[?] = 0 WHERE a = ? and b = ?", c, a, b); - } - - @Test - public void testIndexOnPartitionKeyInsertValueOver64k() throws Throwable - { - createTable("CREATE TABLE %s(a int, b int, c blob, PRIMARY KEY ((a, b)))"); - createIndex("CREATE INDEX ON %s(a)"); - succeedInsert("INSERT INTO %s (a, b, c) VALUES (0, 0, ?)", ByteBuffer.allocate(TOO_BIG)); - } - - @Test - public void testIndexOnClusteringColumnInsertValueOver64k() throws Throwable - { - createTable("CREATE TABLE %s(a int, b int, c blob, PRIMARY KEY (a, b))"); - createIndex("CREATE INDEX ON %s(b)"); - succeedInsert("INSERT INTO %s (a, b, c) VALUES (0, 0, ?)", ByteBuffer.allocate(TOO_BIG)); - } - - @Test - public void testIndexOnFullCollectionEntryInsertCollectionValueOver64k() throws Throwable - { - createTable("CREATE TABLE %s(a int, b frozen>, PRIMARY KEY (a))"); - createIndex("CREATE INDEX ON %s(full(b))"); - Map map = new HashMap(); - map.put(0, ByteBuffer.allocate(1024 * 65)); - failInsert("INSERT INTO %s (a, b) VALUES (0, ?)", map); - } - - public void failInsert(String insertCQL, Object...args) throws Throwable - { - try - { - execute(insertCQL, args); - fail("Expected statement to fail validation"); - } - catch (Exception e) - { - // as expected - } - } - - public void succeedInsert(String insertCQL, Object...args) throws Throwable - { - execute(insertCQL, args); - flush(); - } -} diff --git a/test/unit/org/apache/cassandra/cql3/ModificationTest.java b/test/unit/org/apache/cassandra/cql3/ModificationTest.java deleted file mode 100644 index 6397a15ed0..0000000000 --- a/test/unit/org/apache/cassandra/cql3/ModificationTest.java +++ /dev/null @@ -1,112 +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; - -import org.junit.Test; - -public class ModificationTest extends CQLTester -{ - @Test - public void testModificationWithUnset() throws Throwable - { - createTable("CREATE TABLE %s (k int PRIMARY KEY, s text, i int)"); - - // insert using nulls - execute("INSERT INTO %s (k, s, i) VALUES (10, ?, ?)", "text", 10); - execute("INSERT INTO %s (k, s, i) VALUES (10, ?, ?)", null, null); - assertRows(execute("SELECT s, i FROM %s WHERE k = 10"), - row(null, null) // sending null deletes the data - ); - // insert using UNSET - execute("INSERT INTO %s (k, s, i) VALUES (11, ?, ?)", "text", 10); - execute("INSERT INTO %s (k, s, i) VALUES (11, ?, ?)", unset(), unset()); - assertRows(execute("SELECT s, i FROM %s WHERE k=11"), - row("text", 10) // unset columns does not delete the existing data - ); - - assertInvalidMessage("Invalid unset value for column k", "UPDATE %s SET i = 0 WHERE k = ?", unset()); - assertInvalidMessage("Invalid unset value for column k", "DELETE FROM %s WHERE k = ?", unset()); - assertInvalidMessage("Invalid unset value for argument in call to function blobasint", "SELECT * FROM %s WHERE k = blobAsInt(?)", unset()); - } - - @Test - public void testTtlWithUnset() throws Throwable - { - createTable("CREATE TABLE %s (k int PRIMARY KEY, i int)"); - execute("INSERT INTO %s (k, i) VALUES (1, 1) USING TTL ?", unset()); // treat as 'unlimited' - assertRows(execute("SELECT ttl(i) FROM %s"), - row(new Object[] {null}) - ); - } - - @Test - public void testTimestampWithUnset() throws Throwable - { - createTable("CREATE TABLE %s (k int PRIMARY KEY, i int)"); - execute("INSERT INTO %s (k, i) VALUES (1, 1) USING TIMESTAMP ?", unset()); // treat as 'now' - } - - @Test - public void testCounterUpdatesWithUnset() throws Throwable - { - createTable("CREATE TABLE %s (k int PRIMARY KEY, c counter)"); - - // set up - execute("UPDATE %s SET c = c + 1 WHERE k = 10"); - assertRows(execute("SELECT c FROM %s WHERE k = 10"), - row(1L) - ); - // increment - execute("UPDATE %s SET c = c + ? WHERE k = 10", 1L); - assertRows(execute("SELECT c FROM %s WHERE k = 10"), - row(2L) - ); - execute("UPDATE %s SET c = c + ? WHERE k = 10", unset()); - assertRows(execute("SELECT c FROM %s WHERE k = 10"), - row(2L) // no change to the counter value - ); - // decrement - execute("UPDATE %s SET c = c - ? WHERE k = 10", 1L); - assertRows(execute("SELECT c FROM %s WHERE k = 10"), - row(1L) - ); - execute("UPDATE %s SET c = c - ? WHERE k = 10", unset()); - assertRows(execute("SELECT c FROM %s WHERE k = 10"), - row(1L) // no change to the counter value - ); - } - - @Test - public void testBatchWithUnset() throws Throwable - { - createTable("CREATE TABLE %s (k int PRIMARY KEY, s text, i int)"); - - // test batch and update - String qualifiedTable = keyspace() + "." + currentTable(); - execute("BEGIN BATCH " + - "INSERT INTO %s (k, s, i) VALUES (100, 'batchtext', 7); " + - "INSERT INTO " + qualifiedTable + " (k, s, i) VALUES (111, 'batchtext', 7); " + - "UPDATE " + qualifiedTable + " SET s=?, i=? WHERE k = 100; " + - "UPDATE " + qualifiedTable + " SET s=?, i=? WHERE k=111; " + - "APPLY BATCH;", null, unset(), unset(), null); - assertRows(execute("SELECT k, s, i FROM %s where k in (100,111)"), - row(100, null, 7), - row(111, "batchtext", null) - ); - } -} diff --git a/test/unit/org/apache/cassandra/cql3/RangeDeletionTest.java b/test/unit/org/apache/cassandra/cql3/RangeDeletionTest.java deleted file mode 100644 index b31d0c247a..0000000000 --- a/test/unit/org/apache/cassandra/cql3/RangeDeletionTest.java +++ /dev/null @@ -1,35 +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; - -import org.junit.Test; - -public class RangeDeletionTest extends CQLTester -{ - @Test - public void testCassandra8558() throws Throwable - { - createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY (a, b, c))"); - - execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 1, 1, 1); - flush(); - execute("DELETE FROM %s WHERE a=? AND b=?", 1, 1); - flush(); - assertEmpty(execute("SELECT * FROM %s WHERE a=? AND b=? AND c=?", 1, 1, 1)); - } -} diff --git a/test/unit/org/apache/cassandra/cql3/SelectionOrderingTest.java b/test/unit/org/apache/cassandra/cql3/SelectionOrderingTest.java deleted file mode 100644 index 301aaf46a9..0000000000 --- a/test/unit/org/apache/cassandra/cql3/SelectionOrderingTest.java +++ /dev/null @@ -1,233 +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; - -import org.junit.Test; - -public class SelectionOrderingTest extends CQLTester -{ - - @Test - public void testNormalSelectionOrderSingleClustering() throws Throwable - { - for (String descOption : new String[]{"", " WITH CLUSTERING ORDER BY (b DESC)"}) - { - createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY (a, b))" + descOption); - execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, 0, 0); - execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, 1, 1); - execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, 2, 2); - - assertRows(execute("SELECT * FROM %s WHERE a=? ORDER BY b ASC", 0), - row(0, 0, 0), - row(0, 1, 1), - row(0, 2, 2) - ); - - assertRows(execute("SELECT * FROM %s WHERE a=? ORDER BY b DESC", 0), - row(0, 2, 2), - row(0, 1, 1), - row(0, 0, 0) - ); - - // order by the only column in the selection - assertRows(execute("SELECT b FROM %s WHERE a=? ORDER BY b ASC", 0), - row(0), row(1), row(2)); - - assertRows(execute("SELECT b FROM %s WHERE a=? ORDER BY b DESC", 0), - row(2), row(1), row(0)); - - // order by a column not in the selection - assertRows(execute("SELECT c FROM %s WHERE a=? ORDER BY b ASC", 0), - row(0), row(1), row(2)); - - assertRows(execute("SELECT c FROM %s WHERE a=? ORDER BY b DESC", 0), - row(2), row(1), row(0)); - } - } - - @Test - public void testFunctionSelectionOrderSingleClustering() throws Throwable - { - for (String descOption : new String[]{"", " WITH CLUSTERING ORDER BY (b DESC)"}) - { - createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY (a, b))" + descOption); - execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, 0, 0); - execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, 1, 1); - execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, 2, 2); - - // order by the only column in the selection - assertRows(execute("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY b ASC", 0), - row(0), row(1), row(2)); - - assertRows(execute("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY b DESC", 0), - row(2), row(1), row(0)); - - // order by a column not in the selection - assertRows(execute("SELECT blobAsInt(intAsBlob(c)) FROM %s WHERE a=? ORDER BY b ASC", 0), - row(0), row(1), row(2)); - - assertRows(execute("SELECT blobAsInt(intAsBlob(c)) FROM %s WHERE a=? ORDER BY b DESC", 0), - row(2), row(1), row(0)); - - assertInvalid("SELECT * FROM %s WHERE a=? ORDER BY c ASC", 0); - assertInvalid("SELECT * FROM %s WHERE a=? ORDER BY c DESC", 0); - } - } - - @Test - public void testFieldSelectionOrderSingleClustering() throws Throwable - { - String type = createType("CREATE TYPE %s (a int)"); - - for (String descOption : new String[]{"", " WITH CLUSTERING ORDER BY (b DESC)"}) - { - createTable("CREATE TABLE %s (a int, b int, c frozen<" + type + " >, PRIMARY KEY (a, b))" + descOption); - execute("INSERT INTO %s (a, b, c) VALUES (?, ?, {a: ?})", 0, 0, 0); - execute("INSERT INTO %s (a, b, c) VALUES (?, ?, {a: ?})", 0, 1, 1); - execute("INSERT INTO %s (a, b, c) VALUES (?, ?, {a: ?})", 0, 2, 2); - - // order by a column not in the selection - assertRows(execute("SELECT c.a FROM %s WHERE a=? ORDER BY b ASC", 0), - row(0), row(1), row(2)); - - assertRows(execute("SELECT c.a FROM %s WHERE a=? ORDER BY b DESC", 0), - row(2), row(1), row(0)); - - assertRows(execute("SELECT blobAsInt(intAsBlob(c.a)) FROM %s WHERE a=? ORDER BY b DESC", 0), - row(2), row(1), row(0)); - dropTable("DROP TABLE %s"); - } - } - - @Test - public void testNormalSelectionOrderMultipleClustering() throws Throwable - { - createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY (a, b, c))"); - execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 0, 0); - execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 1, 1); - execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 2, 2); - execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 0, 3); - execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 1, 4); - execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 2, 5); - - assertRows(execute("SELECT * FROM %s WHERE a=? ORDER BY b ASC", 0), - row(0, 0, 0, 0), - row(0, 0, 1, 1), - row(0, 0, 2, 2), - row(0, 1, 0, 3), - row(0, 1, 1, 4), - row(0, 1, 2, 5) - ); - - assertRows(execute("SELECT * FROM %s WHERE a=? ORDER BY b DESC", 0), - row(0, 1, 2, 5), - row(0, 1, 1, 4), - row(0, 1, 0, 3), - row(0, 0, 2, 2), - row(0, 0, 1, 1), - row(0, 0, 0, 0) - ); - - assertRows(execute("SELECT * FROM %s WHERE a=? ORDER BY b DESC, c DESC", 0), - row(0, 1, 2, 5), - row(0, 1, 1, 4), - row(0, 1, 0, 3), - row(0, 0, 2, 2), - row(0, 0, 1, 1), - row(0, 0, 0, 0) - ); - - assertInvalid("SELECT * FROM %s WHERE a=? ORDER BY c ASC", 0); - assertInvalid("SELECT * FROM %s WHERE a=? ORDER BY c DESC", 0); - assertInvalid("SELECT * FROM %s WHERE a=? ORDER BY b ASC, c DESC", 0); - assertInvalid("SELECT * FROM %s WHERE a=? ORDER BY b DESC, c ASC", 0); - assertInvalid("SELECT * FROM %s WHERE a=? ORDER BY d ASC", 0); - - // select and order by b - assertRows(execute("SELECT b FROM %s WHERE a=? ORDER BY b ASC", 0), - row(0), row(0), row(0), row(1), row(1), row(1)); - assertRows(execute("SELECT b FROM %s WHERE a=? ORDER BY b DESC", 0), - row(1), row(1), row(1), row(0), row(0), row(0)); - - // select c, order by b - assertRows(execute("SELECT c FROM %s WHERE a=? ORDER BY b ASC", 0), - row(0), row(1), row(2), row(0), row(1), row(2)); - assertRows(execute("SELECT c FROM %s WHERE a=? ORDER BY b DESC", 0), - row(2), row(1), row(0), row(2), row(1), row(0)); - - // select c, order by b, c - assertRows(execute("SELECT c FROM %s WHERE a=? ORDER BY b ASC, c ASC", 0), - row(0), row(1), row(2), row(0), row(1), row(2)); - assertRows(execute("SELECT c FROM %s WHERE a=? ORDER BY b DESC, c DESC", 0), - row(2), row(1), row(0), row(2), row(1), row(0)); - - // select d, order by b, c - assertRows(execute("SELECT d FROM %s WHERE a=? ORDER BY b ASC, c ASC", 0), - row(0), row(1), row(2), row(3), row(4), row(5)); - assertRows(execute("SELECT d FROM %s WHERE a=? ORDER BY b DESC, c DESC", 0), - row(5), row(4), row(3), row(2), row(1), row(0)); - } - - @Test - public void testFunctionSelectionOrderMultipleClustering() throws Throwable - { - createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY (a, b, c))"); - execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 0, 0); - execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 1, 1); - execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 2, 2); - execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 0, 3); - execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 1, 4); - execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 2, 5); - - assertInvalid("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY c ASC", 0); - assertInvalid("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY c DESC", 0); - assertInvalid("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY b ASC, c DESC", 0); - assertInvalid("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY b DESC, c ASC", 0); - assertInvalid("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY d ASC", 0); - - // select and order by b - assertRows(execute("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY b ASC", 0), - row(0), row(0), row(0), row(1), row(1), row(1)); - assertRows(execute("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY b DESC", 0), - row(1), row(1), row(1), row(0), row(0), row(0)); - - assertRows(execute("SELECT b, blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY b ASC", 0), - row(0, 0), row(0, 0), row(0, 0), row(1, 1), row(1, 1), row(1, 1)); - assertRows(execute("SELECT b, blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY b DESC", 0), - row(1, 1), row(1, 1), row(1, 1), row(0, 0), row(0, 0), row(0, 0)); - - // select c, order by b - assertRows(execute("SELECT blobAsInt(intAsBlob(c)) FROM %s WHERE a=? ORDER BY b ASC", 0), - row(0), row(1), row(2), row(0), row(1), row(2)); - assertRows(execute("SELECT blobAsInt(intAsBlob(c)) FROM %s WHERE a=? ORDER BY b DESC", 0), - row(2), row(1), row(0), row(2), row(1), row(0)); - - // select c, order by b, c - assertRows(execute("SELECT blobAsInt(intAsBlob(c)) FROM %s WHERE a=? ORDER BY b ASC, c ASC", 0), - row(0), row(1), row(2), row(0), row(1), row(2)); - assertRows(execute("SELECT blobAsInt(intAsBlob(c)) FROM %s WHERE a=? ORDER BY b DESC, c DESC", 0), - row(2), row(1), row(0), row(2), row(1), row(0)); - - // select d, order by b, c - assertRows(execute("SELECT blobAsInt(intAsBlob(d)) FROM %s WHERE a=? ORDER BY b ASC, c ASC", 0), - row(0), row(1), row(2), row(3), row(4), row(5)); - assertRows(execute("SELECT blobAsInt(intAsBlob(d)) FROM %s WHERE a=? ORDER BY b DESC, c DESC", 0), - row(5), row(4), row(3), row(2), row(1), row(0)); - - } -} diff --git a/test/unit/org/apache/cassandra/cql3/StaticColumnsQueryTest.java b/test/unit/org/apache/cassandra/cql3/StaticColumnsQueryTest.java deleted file mode 100644 index e27f96850b..0000000000 --- a/test/unit/org/apache/cassandra/cql3/StaticColumnsQueryTest.java +++ /dev/null @@ -1,280 +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; - -import org.junit.Test; - -/** - * Test column ranges and ordering with static column in table - */ -public class StaticColumnsQueryTest extends CQLTester -{ - @Test - public void testSingleClustering() throws Throwable - { - createTable("CREATE TABLE %s (p text, c text, v text, s text static, PRIMARY KEY (p, c))"); - - execute("INSERT INTO %s(p, c, v, s) values (?, ?, ?, ?)", "p1", "k1", "v1", "sv1"); - execute("INSERT INTO %s(p, c, v) values (?, ?, ?)", "p1", "k2", "v2"); - execute("INSERT INTO %s(p, s) values (?, ?)", "p2", "sv2"); - - assertRows(execute("SELECT * FROM %s WHERE p=?", "p1"), - row("p1", "k1", "sv1", "v1"), - row("p1", "k2", "sv1", "v2") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=?", "p2"), - row("p2", null, "sv2", null) - ); - - // Ascending order - - assertRows(execute("SELECT * FROM %s WHERE p=? ORDER BY c ASC", "p1"), - row("p1", "k1", "sv1", "v1"), - row("p1", "k2", "sv1", "v2") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? ORDER BY c ASC", "p2"), - row("p2", null, "sv2", null) - ); - - // Descending order - - assertRows(execute("SELECT * FROM %s WHERE p=? ORDER BY c DESC", "p1"), - row("p1", "k2", "sv1", "v2"), - row("p1", "k1", "sv1", "v1") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? ORDER BY c DESC", "p2"), - row("p2", null, "sv2", null) - ); - - // No order with one relation - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=?", "p1", "k1"), - row("p1", "k1", "sv1", "v1"), - row("p1", "k2", "sv1", "v2") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=?", "p1", "k2"), - row("p1", "k2", "sv1", "v2") - ); - - assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c>=?", "p1", "k3")); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c =?", "p1", "k1"), - row("p1", "k1", "sv1", "v1") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c<=?", "p1", "k1"), - row("p1", "k1", "sv1", "v1") - ); - - assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c<=?", "p1", "k0")); - - // Ascending with one relation - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c ASC", "p1", "k1"), - row("p1", "k1", "sv1", "v1"), - row("p1", "k2", "sv1", "v2") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c ASC", "p1", "k2"), - row("p1", "k2", "sv1", "v2") - ); - - assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c ASC", "p1", "k3")); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c =? ORDER BY c ASC", "p1", "k1"), - row("p1", "k1", "sv1", "v1") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c<=? ORDER BY c ASC", "p1", "k1"), - row("p1", "k1", "sv1", "v1") - ); - - assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c<=? ORDER BY c ASC", "p1", "k0")); - - // Descending with one relation - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c DESC", "p1", "k1"), - row("p1", "k2", "sv1", "v2"), - row("p1", "k1", "sv1", "v1") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c DESC", "p1", "k2"), - row("p1", "k2", "sv1", "v2") - ); - - assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c DESC", "p1", "k3")); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c =? ORDER BY c DESC", "p1", "k1"), - row("p1", "k1", "sv1", "v1") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c<=? ORDER BY c DESC", "p1", "k1"), - row("p1", "k1", "sv1", "v1") - ); - - assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c<=? ORDER BY c DESC", "p1", "k0")); - - // IN - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c IN (?, ?)", "p1", "k1", "k2"), - row("p1", "k1", "sv1", "v1"), - row("p1", "k2", "sv1", "v2") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c IN (?, ?) ORDER BY c ASC", "p1", "k1", "k2"), - row("p1", "k1", "sv1", "v1"), - row("p1", "k2", "sv1", "v2") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c IN (?, ?) ORDER BY c DESC", "p1", "k1", "k2"), - row("p1", "k2", "sv1", "v2"), - row("p1", "k1", "sv1", "v1") - ); - } - - @Test - public void testSingleClusteringReversed() throws Throwable - { - createTable("CREATE TABLE %s (p text, c text, v text, s text static, PRIMARY KEY (p, c)) WITH CLUSTERING ORDER BY (c DESC)"); - - execute("INSERT INTO %s(p, c, v, s) values (?, ?, ?, ?)", "p1", "k1", "v1", "sv1"); - execute("INSERT INTO %s(p, c, v) values (?, ?, ?)", "p1", "k2", "v2"); - execute("INSERT INTO %s(p, s) values (?, ?)", "p2", "sv2"); - - assertRows(execute("SELECT * FROM %s WHERE p=?", "p1"), - row("p1", "k2", "sv1", "v2"), - row("p1", "k1", "sv1", "v1") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=?", "p2"), - row("p2", null, "sv2", null) - ); - - // Ascending order - - assertRows(execute("SELECT * FROM %s WHERE p=? ORDER BY c ASC", "p1"), - row("p1", "k1", "sv1", "v1"), - row("p1", "k2", "sv1", "v2") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? ORDER BY c ASC", "p2"), - row("p2", null, "sv2", null) - ); - - // Descending order - - assertRows(execute("SELECT * FROM %s WHERE p=? ORDER BY c DESC", "p1"), - row("p1", "k2", "sv1", "v2"), - row("p1", "k1", "sv1", "v1") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? ORDER BY c DESC", "p2"), - row("p2", null, "sv2", null) - ); - - // No order with one relation - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=?", "p1", "k1"), - row("p1", "k2", "sv1", "v2"), - row("p1", "k1", "sv1", "v1") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=?", "p1", "k2"), - row("p1", "k2", "sv1", "v2") - ); - - assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c>=?", "p1", "k3")); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c=?", "p1", "k1"), - row("p1", "k1", "sv1", "v1") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c<=?", "p1", "k1"), - row("p1", "k1", "sv1", "v1") - ); - - assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c<=?", "p1", "k0")); - - // Ascending with one relation - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c ASC", "p1", "k1"), - row("p1", "k1", "sv1", "v1"), - row("p1", "k2", "sv1", "v2") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c ASC", "p1", "k2"), - row("p1", "k2", "sv1", "v2") - ); - - assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c ASC", "p1", "k3")); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c=? ORDER BY c ASC", "p1", "k1"), - row("p1", "k1", "sv1", "v1") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c<=? ORDER BY c ASC", "p1", "k1"), - row("p1", "k1", "sv1", "v1") - ); - - assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c<=? ORDER BY c ASC", "p1", "k0")); - - // Descending with one relation - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c DESC", "p1", "k1"), - row("p1", "k2", "sv1", "v2"), - row("p1", "k1", "sv1", "v1") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c DESC", "p1", "k2"), - row("p1", "k2", "sv1", "v2") - ); - - assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c DESC", "p1", "k3")); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c=? ORDER BY c DESC", "p1", "k1"), - row("p1", "k1", "sv1", "v1") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c<=? ORDER BY c DESC", "p1", "k1"), - row("p1", "k1", "sv1", "v1") - ); - - assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c<=? ORDER BY c DESC", "p1", "k0")); - - // IN - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c IN (?, ?)", "p1", "k1", "k2"), - row("p1", "k2", "sv1", "v2"), - row("p1", "k1", "sv1", "v1") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c IN (?, ?) ORDER BY c ASC", "p1", "k1", "k2"), - row("p1", "k1", "sv1", "v1"), - row("p1", "k2", "sv1", "v2") - ); - - assertRows(execute("SELECT * FROM %s WHERE p=? AND c IN (?, ?) ORDER BY c DESC", "p1", "k1", "k2"), - row("p1", "k2", "sv1", "v2"), - row("p1", "k1", "sv1", "v1") - ); - } -} diff --git a/test/unit/org/apache/cassandra/cql3/ThriftCompatibilityTest.java b/test/unit/org/apache/cassandra/cql3/ThriftCompatibilityTest.java index 3125b28fff..7b72ef867f 100644 --- a/test/unit/org/apache/cassandra/cql3/ThriftCompatibilityTest.java +++ b/test/unit/org/apache/cassandra/cql3/ThriftCompatibilityTest.java @@ -27,6 +27,7 @@ import org.junit.Test; import org.apache.cassandra.SchemaLoader; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; public class ThriftCompatibilityTest extends SchemaLoader { diff --git a/test/unit/org/apache/cassandra/cql3/selection/SelectionColumnMappingTest.java b/test/unit/org/apache/cassandra/cql3/selection/SelectionColumnMappingTest.java index 5bacf0d21c..2f1d3618ad 100644 --- a/test/unit/org/apache/cassandra/cql3/selection/SelectionColumnMappingTest.java +++ b/test/unit/org/apache/cassandra/cql3/selection/SelectionColumnMappingTest.java @@ -3,13 +3,16 @@ package org.apache.cassandra.cql3.selection; import java.util.Collections; import com.google.common.collect.ImmutableList; +import org.junit.BeforeClass; import org.junit.Test; import org.apache.cassandra.config.ColumnDefinition; +import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.config.Schema; import org.apache.cassandra.cql3.*; import org.apache.cassandra.cql3.statements.SelectStatement; import org.apache.cassandra.db.marshal.*; +import org.apache.cassandra.dht.ByteOrderedPartitioner; import org.apache.cassandra.exceptions.RequestValidationException; import org.apache.cassandra.service.ClientState; import org.apache.cassandra.utils.ByteBufferUtil; @@ -25,6 +28,12 @@ public class SelectionColumnMappingTest extends CQLTester UserType userType; String functionName; + @BeforeClass + public static void setUpClass() + { + DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance); + } + @Test public void testSelectionColumnMapping() throws Throwable { diff --git a/test/unit/org/apache/cassandra/cql3/CollectionsTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/CollectionsTest.java similarity index 52% rename from test/unit/org/apache/cassandra/cql3/CollectionsTest.java rename to test/unit/org/apache/cassandra/cql3/validation/entities/CollectionsTest.java index c9c6d31cc8..2e72c398fd 100644 --- a/test/unit/org/apache/cassandra/cql3/CollectionsTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/CollectionsTest.java @@ -15,10 +15,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.entities; + +import java.util.UUID; import org.junit.Test; +import org.apache.cassandra.cql3.CQLTester; + public class CollectionsTest extends CQLTester { @Test @@ -85,26 +89,26 @@ public class CollectionsTest extends CQLTester execute("DELETE s[?] FROM %s WHERE k = 0", "v1"); assertRows(execute("SELECT s FROM %s WHERE k = 0"), - row(set("v2", "v3", "v4")) + row(set("v2", "v3", "v4")) ); // Full overwrite execute("UPDATE %s SET s = ? WHERE k = 0", set("v6", "v5")); assertRows(execute("SELECT s FROM %s WHERE k = 0"), - row(set("v5", "v6")) + row(set("v5", "v6")) ); execute("UPDATE %s SET s = s + ? WHERE k = 0", set("v7")); assertRows(execute("SELECT s FROM %s WHERE k = 0"), - row(set("v5", "v6", "v7")) + row(set("v5", "v6", "v7")) ); execute("UPDATE %s SET s = s - ? WHERE k = 0", set("v6", "v5")); assertRows(execute("SELECT s FROM %s WHERE k = 0"), - row(set("v7")) + row(set("v7")) ); execute("DELETE s[?] FROM %s WHERE k = 0", set("v7")); @@ -115,7 +119,7 @@ public class CollectionsTest extends CQLTester execute("DELETE s FROM %s WHERE k = 0"); assertRows(execute("SELECT s FROM %s WHERE k = 0"), - row((Object)null) + row((Object) null) ); } @@ -146,38 +150,38 @@ public class CollectionsTest extends CQLTester execute("UPDATE %s SET m = ? WHERE k = 0", map("v6", 6, "v5", 5)); assertRows(execute("SELECT m FROM %s WHERE k = 0"), - row(map("v5", 5, "v6", 6)) + row(map("v5", 5, "v6", 6)) ); execute("UPDATE %s SET m = m + ? WHERE k = 0", map("v7", 7)); assertRows(execute("SELECT m FROM %s WHERE k = 0"), - row(map("v5", 5, "v6", 6, "v7", 7)) + row(map("v5", 5, "v6", 6, "v7", 7)) ); execute("DELETE m[?] FROM %s WHERE k = 0", "v7"); assertRows(execute("SELECT m FROM %s WHERE k = 0"), - row(map("v5", 5, "v6", 6)) + row(map("v5", 5, "v6", 6)) ); execute("DELETE m[?] FROM %s WHERE k = 0", "v6"); assertRows(execute("SELECT m FROM %s WHERE k = 0"), - row(map("v5", 5)) + row(map("v5", 5)) ); execute("DELETE m[?] FROM %s WHERE k = 0", "v5"); assertRows(execute("SELECT m FROM %s WHERE k = 0"), - row((Object)null) + row((Object) null) ); // Deleting a non-existing key should succeed execute("DELETE m[?] FROM %s WHERE k = 0", "v5"); assertRows(execute("SELECT m FROM %s WHERE k = 0"), - row((Object) null) + row((Object) null) ); // The empty map is parsed as an empty set (because we don't have enough info at parsing @@ -246,18 +250,18 @@ public class CollectionsTest extends CQLTester Object m = map("k", "v"); execute("INSERT INTO %s (k, m) VALUES (10, ?)", m); assertRows(execute("SELECT m FROM %s WHERE k = 10"), - row(m) + row(m) ); // test putting an unset map, should not delete the contents execute("INSERT INTO %s (k, m) VALUES (10, ?)", unset()); assertRows(execute("SELECT m FROM %s WHERE k = 10"), - row(m) + row(m) ); // test unset variables in a map update operaiotn, should not delete the contents execute("UPDATE %s SET m['k'] = ? WHERE k = 10", unset()); assertRows(execute("SELECT m FROM %s WHERE k = 10"), - row(m) + row(m) ); assertInvalidMessage("Invalid unset map key", "UPDATE %s SET m[?] = 'foo' WHERE k = 10", unset()); @@ -273,19 +277,19 @@ public class CollectionsTest extends CQLTester Object l = list("foo", "foo"); execute("INSERT INTO %s (k, l) VALUES (10, ?)", l); assertRows(execute("SELECT l FROM %s WHERE k = 10"), - row(l) + row(l) ); // replace list with unset value execute("INSERT INTO %s (k, l) VALUES (10, ?)", unset()); assertRows(execute("SELECT l FROM %s WHERE k = 10"), - row(l) + row(l) ); // add to position execute("UPDATE %s SET l[1] = ? WHERE k = 10", unset()); assertRows(execute("SELECT l FROM %s WHERE k = 10"), - row(l) + row(l) ); // set in index @@ -294,13 +298,13 @@ public class CollectionsTest extends CQLTester // remove element by index execute("DELETE l[?] FROM %s WHERE k = 10", unset()); assertRows(execute("SELECT l FROM %s WHERE k = 10"), - row(l) + row(l) ); // remove all occurrences of element execute("UPDATE %s SET l = l - ? WHERE k = 10", unset()); assertRows(execute("SELECT l FROM %s WHERE k = 10"), - row(l) + row(l) ); // select with in clause @@ -316,25 +320,269 @@ public class CollectionsTest extends CQLTester Object s = set("bar", "baz", "foo"); execute("INSERT INTO %s (k, s) VALUES (10, ?)", s); assertRows(execute("SELECT s FROM %s WHERE k = 10"), - row(s) + row(s) ); // replace set with unset value execute("INSERT INTO %s (k, s) VALUES (10, ?)", unset()); assertRows(execute("SELECT s FROM %s WHERE k = 10"), - row(s) + row(s) ); // add to set execute("UPDATE %s SET s = s + ? WHERE k = 10", unset()); assertRows(execute("SELECT s FROM %s WHERE k = 10"), - row(s) + row(s) ); // remove all occurrences of element execute("UPDATE %s SET s = s - ? WHERE k = 10", unset()); assertRows(execute("SELECT s FROM %s WHERE k = 10"), - row(s) + row(s) ); } + + /** + * Migrated from cql_tests.py:TestCQL.set_test() + */ + @Test + public void testSet() throws Throwable + { + createTable("CREATE TABLE %s ( fn text, ln text, tags set, PRIMARY KEY (fn, ln) )"); + + execute("UPDATE %s SET tags = tags + { 'foo' } WHERE fn='Tom' AND ln='Bombadil'"); + execute("UPDATE %s SET tags = tags + { 'bar' } WHERE fn='Tom' AND ln='Bombadil'"); + execute("UPDATE %s SET tags = tags + { 'foo' } WHERE fn='Tom' AND ln='Bombadil'"); + execute("UPDATE %s SET tags = tags + { 'foobar' } WHERE fn='Tom' AND ln='Bombadil'"); + execute("UPDATE %s SET tags = tags - { 'bar' } WHERE fn='Tom' AND ln='Bombadil'"); + + assertRows(execute("SELECT tags FROM %s"), + row(set("foo", "foobar"))); + + execute("UPDATE %s SET tags = { 'a', 'c', 'b' } WHERE fn='Bilbo' AND ln='Baggins'"); + assertRows(execute("SELECT tags FROM %s WHERE fn='Bilbo' AND ln='Baggins'"), + row(set("a", "b", "c"))); + + execute("UPDATE %s SET tags = { 'm', 'n' } WHERE fn='Bilbo' AND ln='Baggins'"); + assertRows(execute("SELECT tags FROM %s WHERE fn='Bilbo' AND ln='Baggins'"), + row(set("m", "n"))); + + execute("DELETE tags['m'] FROM %s WHERE fn='Bilbo' AND ln='Baggins'"); + assertRows(execute("SELECT tags FROM %s WHERE fn='Bilbo' AND ln='Baggins'"), + row(set("n"))); + + execute("DELETE tags FROM %s WHERE fn='Bilbo' AND ln='Baggins'"); + assertEmpty(execute("SELECT tags FROM %s WHERE fn='Bilbo' AND ln='Baggins'")); + } + + /** + * Migrated from cql_tests.py:TestCQL.map_test() + */ + @Test + public void testMap() throws Throwable + { + createTable("CREATE TABLE %s (fn text, ln text, m map, PRIMARY KEY (fn, ln))"); + + execute("UPDATE %s SET m['foo'] = 3 WHERE fn='Tom' AND ln='Bombadil'"); + execute("UPDATE %s SET m['bar'] = 4 WHERE fn='Tom' AND ln='Bombadil'"); + execute("UPDATE %s SET m['woot'] = 5 WHERE fn='Tom' AND ln='Bombadil'"); + execute("UPDATE %s SET m['bar'] = 6 WHERE fn='Tom' AND ln='Bombadil'"); + execute("DELETE m['foo'] FROM %s WHERE fn='Tom' AND ln='Bombadil'"); + + assertRows(execute("SELECT m FROM %s"), + row(map("bar", 6, "woot", 5))); + + execute("UPDATE %s SET m = { 'a' : 4 , 'c' : 3, 'b' : 2 } WHERE fn='Bilbo' AND ln='Baggins'"); + assertRows(execute("SELECT m FROM %s WHERE fn='Bilbo' AND ln='Baggins'"), + row(map("a", 4, "b", 2, "c", 3))); + + execute("UPDATE %s SET m = { 'm' : 4 , 'n' : 1, 'o' : 2 } WHERE fn='Bilbo' AND ln='Baggins'"); + assertRows(execute("SELECT m FROM %s WHERE fn='Bilbo' AND ln='Baggins'"), + row(map("m", 4, "n", 1, "o", 2))); + + execute("UPDATE %s SET m = {} WHERE fn='Bilbo' AND ln='Baggins'"); + assertEmpty(execute("SELECT m FROM %s WHERE fn='Bilbo' AND ln='Baggins'")); + } + + /** + * Migrated from cql_tests.py:TestCQL.list_test() + */ + @Test + public void testList() throws Throwable + { + createTable("CREATE TABLE %s (fn text, ln text, tags list, PRIMARY KEY (fn, ln))"); + + execute("UPDATE %s SET tags = tags + [ 'foo' ] WHERE fn='Tom' AND ln='Bombadil'"); + execute("UPDATE %s SET tags = tags + [ 'bar' ] WHERE fn='Tom' AND ln='Bombadil'"); + execute("UPDATE %s SET tags = tags + [ 'foo' ] WHERE fn='Tom' AND ln='Bombadil'"); + execute("UPDATE %s SET tags = tags + [ 'foobar' ] WHERE fn='Tom' AND ln='Bombadil'"); + + assertRows(execute("SELECT tags FROM %s"), + row(list("foo", "bar", "foo", "foobar"))); + + execute("UPDATE %s SET tags = [ 'a', 'c', 'b', 'c' ] WHERE fn='Bilbo' AND ln='Baggins'"); + assertRows(execute("SELECT tags FROM %s WHERE fn='Bilbo' AND ln='Baggins'"), + row(list("a", "c", "b", "c"))); + + execute("UPDATE %s SET tags = [ 'm', 'n' ] + tags WHERE fn='Bilbo' AND ln='Baggins'"); + assertRows(execute("SELECT tags FROM %s WHERE fn='Bilbo' AND ln='Baggins'"), + row(list("m", "n", "a", "c", "b", "c"))); + + execute("UPDATE %s SET tags[2] = 'foo', tags[4] = 'bar' WHERE fn='Bilbo' AND ln='Baggins'"); + assertRows(execute("SELECT tags FROM %s WHERE fn='Bilbo' AND ln='Baggins'"), + row(list("m", "n", "foo", "c", "bar", "c"))); + + execute("DELETE tags[2] FROM %s WHERE fn='Bilbo' AND ln='Baggins'"); + assertRows(execute("SELECT tags FROM %s WHERE fn='Bilbo' AND ln='Baggins'"), + row(list("m", "n", "c", "bar", "c"))); + + execute("UPDATE %s SET tags = tags - [ 'bar' ] WHERE fn='Bilbo' AND ln='Baggins'"); + assertRows(execute("SELECT tags FROM %s WHERE fn='Bilbo' AND ln='Baggins'"), + row(list("m", "n", "c", "c"))); + } + + /** + * Migrated from cql_tests.py:TestCQL.multi_collection_test() + */ + @Test + public void testMultiCollections() throws Throwable + { + UUID id = UUID.fromString("b017f48f-ae67-11e1-9096-005056c00008"); + + createTable("CREATE TABLE %s (k uuid PRIMARY KEY, L list, M map, S set )"); + + execute("UPDATE %s SET L = [1, 3, 5] WHERE k = ?", id); + execute("UPDATE %s SET L = L + [7, 11, 13] WHERE k = ?;", id); + execute("UPDATE %s SET S = {1, 3, 5} WHERE k = ?", id); + execute("UPDATE %s SET S = S + {7, 11, 13} WHERE k = ?", id); + execute("UPDATE %s SET M = {'foo': 1, 'bar' : 3} WHERE k = ?", id); + execute("UPDATE %s SET M = M + {'foobar' : 4} WHERE k = ?", id); + + assertRows(execute("SELECT L, M, S FROM %s WHERE k = ?", id), + row(list(1, 3, 5, 7, 11, 13), + map("bar", 3, "foo", 1, "foobar", 4), + set(1, 3, 5, 7, 11, 13))); + } + + + /** + * Migrated from cql_tests.py:TestCQL.collection_and_regular_test() + */ + @Test + public void testCollectionAndRegularColumns() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, l list, c int)"); + + execute("INSERT INTO %s (k, l, c) VALUES(3, [0, 1, 2], 4)"); + execute("UPDATE %s SET l[0] = 1, c = 42 WHERE k = 3"); + assertRows(execute("SELECT l, c FROM %s WHERE k = 3"), + row(list(1, 1, 2), 42)); + } + + /** + * Migrated from cql_tests.py:TestCQL.multi_list_set_test() + */ + @Test + public void testMultipleLists() throws Throwable + { + createTable(" CREATE TABLE %s (k int PRIMARY KEY, l1 list, l2 list)"); + + execute("INSERT INTO %s (k, l1, l2) VALUES (0, [1, 2, 3], [4, 5, 6])"); + execute("UPDATE %s SET l2[1] = 42, l1[1] = 24 WHERE k = 0"); + + assertRows(execute("SELECT l1, l2 FROM %s WHERE k = 0"), + row(list(1, 24, 3), list(4, 42, 6))); + } + + /** + * Test you can add columns in a table with collections (#4982 bug), + * migrated from cql_tests.py:TestCQL.alter_with_collections_test() + */ + @Test + public void testAlterCollections() throws Throwable + { + createTable("CREATE TABLE %s (key int PRIMARY KEY, aset set)"); + execute("ALTER TABLE %s ADD c text"); + execute("ALTER TABLE %s ADD alist list"); + } + + /** + * Migrated from cql_tests.py:TestCQL.collection_compact_test() + */ + @Test + public void testCompactCollections() throws Throwable + { + String tableName = KEYSPACE + "." + createTableName(); + assertInvalid(String.format("CREATE TABLE %s (user ascii PRIMARY KEY, mails list < text >) WITH COMPACT STORAGE;", tableName)); + } + + /** + * Migrated from cql_tests.py:TestCQL.collection_function_test() + */ + @Test + public void testFunctionsOnCollections() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, l set)"); + + assertInvalid("SELECT ttl(l) FROM %s WHERE k = 0"); + assertInvalid("SELECT writetime(l) FROM %s WHERE k = 0"); + } + + /** + * Migrated from cql_tests.py:TestCQL.bug_5376() + */ + @Test + public void testInClauseWithCollections() throws Throwable + { + createTable("CREATE TABLE %s (key text, c bigint, v text, x set < text >, PRIMARY KEY(key, c) )"); + + assertInvalid("select * from %s where key = 'foo' and c in (1,3,4)"); + } + + /** + * Test for bug #5795, + * migrated from cql_tests.py:TestCQL.nonpure_function_collection_test() + */ + @Test + public void testNonPureFunctionCollection() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, v list)"); + + // we just want to make sure this doesn't throw + execute("INSERT INTO %s (k, v) VALUES (0, [now()])"); + } + + /** + * Test for 5805 bug, + * migrated from cql_tests.py:TestCQL.collection_flush_test() + */ + @Test + public void testCollectionFlush() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, s set)"); + + execute("INSERT INTO %s (k, s) VALUES (1, {1})"); + flush(); + + execute("INSERT INTO %s (k, s) VALUES (1, {2})"); + flush(); + + assertRows(execute("SELECT * FROM %s"), + row(1, set(2))); + } + + /** + * Test for 6276, + * migrated from cql_tests.py:TestCQL.drop_and_readd_collection_test() + */ + @Test + public void testDropAndReaddCollection() throws Throwable + { + createTable("create table %s (k int primary key, v set, x int)"); + execute("insert into %s (k, v) VALUES (0, {'fffffffff'})"); + flush(); + execute("alter table %s drop v"); + assertInvalid("alter table %s add v set"); + } + } diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/CountersTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/CountersTest.java new file mode 100644 index 0000000000..e5ff251492 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/CountersTest.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.cql3.validation.entities; + +import org.junit.Test; + +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.cassandra.exceptions.InvalidRequestException; + +public class CountersTest extends CQLTester +{ + /** + * Check for a table with counters, + * migrated from cql_tests.py:TestCQL.counters_test() + */ + @Test + public void testCounters() throws Throwable + { + createTable("CREATE TABLE %s (userid int, url text, total counter, PRIMARY KEY (userid, url)) WITH COMPACT STORAGE"); + + execute("UPDATE %s SET total = total + 1 WHERE userid = 1 AND url = 'http://foo.com'"); + assertRows(execute("SELECT total FROM %s WHERE userid = 1 AND url = 'http://foo.com'"), + row(1L)); + + execute("UPDATE %s SET total = total - 4 WHERE userid = 1 AND url = 'http://foo.com'"); + assertRows(execute("SELECT total FROM %s WHERE userid = 1 AND url = 'http://foo.com'"), + row(-3L)); + + execute("UPDATE %s SET total = total+1 WHERE userid = 1 AND url = 'http://foo.com'"); + assertRows(execute("SELECT total FROM %s WHERE userid = 1 AND url = 'http://foo.com'"), + row(-2L)); + + execute("UPDATE %s SET total = total -2 WHERE userid = 1 AND url = 'http://foo.com'"); + assertRows(execute("SELECT total FROM %s WHERE userid = 1 AND url = 'http://foo.com'"), + row(-4L)); + } + + /** + * Test for the validation bug of #4706, + * migrated from cql_tests.py:TestCQL.validate_counter_regular_test() + */ + @Test + public void testRegularCounters() throws Throwable + { + assertInvalidThrowMessage("Cannot add a non counter column", + ConfigurationException.class, + String.format("CREATE TABLE %s.%s (id bigint PRIMARY KEY, count counter, things set)", KEYSPACE, createTableName())); + } + + /** + * Migrated from cql_tests.py:TestCQL.collection_counter_test() + */ + @Test + public void testCountersOnCollections() throws Throwable + { + String tableName = KEYSPACE + "." + createTableName(); + assertInvalidThrow(InvalidRequestException.class, + String.format("CREATE TABLE %s (k int PRIMARY KEY, l list)", tableName)); + + tableName = KEYSPACE + "." + createTableName(); + assertInvalidThrow(InvalidRequestException.class, + String.format("CREATE TABLE %s (k int PRIMARY KEY, s set)", tableName)); + + tableName = KEYSPACE + "." + createTableName(); + assertInvalidThrow(InvalidRequestException.class, + String.format("CREATE TABLE %s (k int PRIMARY KEY, m map)", tableName)); + } + + @Test + public void testCounterUpdatesWithUnset() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, c counter)"); + + // set up + execute("UPDATE %s SET c = c + 1 WHERE k = 10"); + assertRows(execute("SELECT c FROM %s WHERE k = 10"), + row(1L) + ); + // increment + execute("UPDATE %s SET c = c + ? WHERE k = 10", 1L); + assertRows(execute("SELECT c FROM %s WHERE k = 10"), + row(2L) + ); + execute("UPDATE %s SET c = c + ? WHERE k = 10", unset()); + assertRows(execute("SELECT c FROM %s WHERE k = 10"), + row(2L) // no change to the counter value + ); + // decrement + execute("UPDATE %s SET c = c - ? WHERE k = 10", 1L); + assertRows(execute("SELECT c FROM %s WHERE k = 10"), + row(1L) + ); + execute("UPDATE %s SET c = c - ? WHERE k = 10", unset()); + assertRows(execute("SELECT c FROM %s WHERE k = 10"), + row(1L) // no change to the counter value + ); + } +} diff --git a/test/unit/org/apache/cassandra/cql3/TimestampTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/DateTypeTest.java similarity index 62% rename from test/unit/org/apache/cassandra/cql3/TimestampTest.java rename to test/unit/org/apache/cassandra/cql3/validation/entities/DateTypeTest.java index 6673904d54..7fa5e67889 100644 --- a/test/unit/org/apache/cassandra/cql3/TimestampTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/DateTypeTest.java @@ -15,22 +15,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; + +package org.apache.cassandra.cql3.validation.entities; import org.junit.Test; -public class TimestampTest extends CQLTester +import org.apache.cassandra.cql3.CQLTester; + +public class DateTypeTest extends CQLTester { + /** + * Check dates are correctly recognized and validated, + * migrated from cql_tests.py:TestCQL.date_test() + */ @Test - public void testNegativeTimestamps() throws Throwable + public void testDate() throws Throwable { - createTable("CREATE TABLE %s (k int PRIMARY KEY, v int)"); + createTable("CREATE TABLE %s (k int PRIMARY KEY, t timestamp)"); - execute("INSERT INTO %s (k, v) VALUES (?, ?) USING TIMESTAMP ?", 1, 1, -42L); - assertRows(execute("SELECT writetime(v) FROM %s WHERE k = ?", 1), - row(-42L) - ); - - assertInvalid("INSERT INTO %s (k, v) VALUES (?, ?) USING TIMESTAMP ?", 2, 2, Long.MIN_VALUE); + execute("INSERT INTO %s (k, t) VALUES (0, '2011-02-03')"); + assertInvalid("INSERT INTO %s (k, t) VALUES (0, '2011-42-42')"); } } diff --git a/test/unit/org/apache/cassandra/cql3/FrozenCollectionsTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/FrozenCollectionsTest.java similarity index 99% rename from test/unit/org/apache/cassandra/cql3/FrozenCollectionsTest.java rename to test/unit/org/apache/cassandra/cql3/validation/entities/FrozenCollectionsTest.java index cdb748995b..857139d024 100644 --- a/test/unit/org/apache/cassandra/cql3/FrozenCollectionsTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/FrozenCollectionsTest.java @@ -15,14 +15,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.entities; +import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.db.marshal.*; +import org.apache.cassandra.dht.ByteOrderedPartitioner; import org.apache.cassandra.exceptions.ConfigurationException; import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.exceptions.SyntaxException; import org.apache.commons.lang3.StringUtils; import org.junit.Assert; +import org.junit.BeforeClass; import org.junit.Test; import java.util.ArrayList; @@ -33,6 +37,12 @@ import static org.junit.Assert.assertEquals; public class FrozenCollectionsTest extends CQLTester { + @BeforeClass + public static void setUpClass() + { + DatabaseDescriptor.setPartitioner(new ByteOrderedPartitioner()); + } + @Test public void testPartitionKeyUsage() throws Throwable { diff --git a/test/unit/org/apache/cassandra/cql3/JsonTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/JsonTest.java similarity index 99% rename from test/unit/org/apache/cassandra/cql3/JsonTest.java rename to test/unit/org/apache/cassandra/cql3/validation/entities/JsonTest.java index 0380dddedd..7f8fa0bb91 100644 --- a/test/unit/org/apache/cassandra/cql3/JsonTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/JsonTest.java @@ -15,11 +15,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.entities; +import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.cql3.Json; +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.dht.ByteOrderedPartitioner; import org.apache.cassandra.serializers.SimpleDateSerializer; import org.apache.cassandra.serializers.TimeSerializer; import org.apache.cassandra.utils.ByteBufferUtil; + +import org.junit.BeforeClass; import org.junit.Test; import java.math.BigDecimal; @@ -35,6 +41,11 @@ import static org.junit.Assert.fail; public class JsonTest extends CQLTester { + @BeforeClass + public static void setUp() + { + DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance); + } @Test public void testFromJsonFct() throws Throwable diff --git a/test/unit/org/apache/cassandra/cql3/SecondaryIndexOnMapEntriesTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexOnMapEntriesTest.java similarity index 96% rename from test/unit/org/apache/cassandra/cql3/SecondaryIndexOnMapEntriesTest.java rename to test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexOnMapEntriesTest.java index e502f6aaa6..fb0d027316 100644 --- a/test/unit/org/apache/cassandra/cql3/SecondaryIndexOnMapEntriesTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexOnMapEntriesTest.java @@ -15,10 +15,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.entities; +import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.cql3.UntypedResultSet; +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.dht.ByteOrderedPartitioner; import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.commons.lang3.StringUtils; +import org.junit.BeforeClass; import org.junit.Test; import java.util.ArrayList; @@ -30,6 +35,12 @@ import static org.junit.Assert.fail; public class SecondaryIndexOnMapEntriesTest extends CQLTester { + @BeforeClass + public static void setUp() + { + DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance); + } + @Test public void testShouldNotCreateIndexOnFrozenMaps() throws Throwable { diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java new file mode 100644 index 0000000000..0b812c60c7 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java @@ -0,0 +1,645 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cassandra.cql3.validation.entities; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.lang3.StringUtils; + +import org.junit.Test; + +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.cassandra.exceptions.SyntaxException; +import org.apache.cassandra.utils.FBUtilities; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class SecondaryIndexTest extends CQLTester +{ + private static final int TOO_BIG = 1024 * 65; + + @Test + public void testCreateAndDropIndex() throws Throwable + { + testCreateAndDropIndex("test", false); + testCreateAndDropIndex("test2", true); + } + + @Test + public void testCreateAndDropIndexWithQuotedIdentifier() throws Throwable + { + testCreateAndDropIndex("\"quoted_ident\"", false); + testCreateAndDropIndex("\"quoted_ident2\"", true); + } + + @Test + public void testCreateAndDropIndexWithCamelCaseIdentifier() throws Throwable + { + testCreateAndDropIndex("CamelCase", false); + testCreateAndDropIndex("CamelCase2", true); + } + + /** + * Test creating and dropping an index with the specified name. + * + * @param indexName the index name + * @param addKeyspaceOnDrop add the keyspace name in the drop statement + * @throws Throwable if an error occurs + */ + private void testCreateAndDropIndex(String indexName, boolean addKeyspaceOnDrop) throws Throwable + { + execute("USE system"); + assertInvalidMessage("Index '" + removeQuotes(indexName.toLowerCase(Locale.US)) + "' could not be found", "DROP INDEX " + indexName + ";"); + + createTable("CREATE TABLE %s (a int primary key, b int);"); + createIndex("CREATE INDEX " + indexName + " ON %s(b);"); + createIndex("CREATE INDEX IF NOT EXISTS " + indexName + " ON %s(b);"); + + assertInvalidMessage("Index already exists", "CREATE INDEX " + indexName + " ON %s(b)"); + + execute("INSERT INTO %s (a, b) values (?, ?);", 0, 0); + execute("INSERT INTO %s (a, b) values (?, ?);", 1, 1); + execute("INSERT INTO %s (a, b) values (?, ?);", 2, 2); + execute("INSERT INTO %s (a, b) values (?, ?);", 3, 1); + + assertRows(execute("SELECT * FROM %s where b = ?", 1), row(1, 1), row(3, 1)); + assertInvalidMessage("Index '" + removeQuotes(indexName.toLowerCase(Locale.US)) + "' could not be found in any of the tables of keyspace 'system'", + "DROP INDEX " + indexName); + + if (addKeyspaceOnDrop) + { + dropIndex("DROP INDEX " + KEYSPACE + "." + indexName); + } + else + { + execute("USE " + KEYSPACE); + execute("DROP INDEX " + indexName); + } + + assertInvalidMessage("No secondary indexes on the restricted columns support the provided operators", + "SELECT * FROM %s where b = ?", 1); + dropIndex("DROP INDEX IF EXISTS " + indexName); + assertInvalidMessage("Index '" + removeQuotes(indexName.toLowerCase(Locale.US)) + "' could not be found", "DROP INDEX " + indexName); + } + + /** + * Removes the quotes from the specified index name. + * + * @param indexName the index name from which the quotes must be removed. + * @return the unquoted index name. + */ + private static String removeQuotes(String indexName) + { + return StringUtils.remove(indexName, '\"'); + } + + /** + * Check that you can query for an indexed column even with a key EQ clause, + * migrated from cql_tests.py:TestCQL.static_cf_test() + */ + @Test + public void testSelectWithEQ() throws Throwable + { + createTable("CREATE TABLE %s (userid uuid PRIMARY KEY, firstname text, lastname text, age int)"); + createIndex("CREATE INDEX byAge ON %s(age)"); + + UUID id1 = UUID.fromString("550e8400-e29b-41d4-a716-446655440000"); + UUID id2 = UUID.fromString("f47ac10b-58cc-4372-a567-0e02b2c3d479"); + + execute("INSERT INTO %s (userid, firstname, lastname, age) VALUES (?, 'Frodo', 'Baggins', 32)", id1); + execute("UPDATE %s SET firstname = 'Samwise', lastname = 'Gamgee', age = 33 WHERE userid = ?", id2); + + assertEmpty(execute("SELECT firstname FROM %s WHERE userid = ? AND age = 33", id1)); + + assertRows(execute("SELECT firstname FROM %s WHERE userid = ? AND age = 33", id2), + row("Samwise")); + } + + /** + * Check CREATE INDEX without name and validate the index can be dropped, + * migrated from cql_tests.py:TestCQL.nameless_index_test() + */ + @Test + public void testNamelessIndex() throws Throwable + { + createTable(" CREATE TABLE %s (id text PRIMARY KEY, birth_year int)"); + + createIndex("CREATE INDEX on %s (birth_year)"); + + execute("INSERT INTO %s (id, birth_year) VALUES ('Tom', 42)"); + execute("INSERT INTO %s (id, birth_year) VALUES ('Paul', 24)"); + execute("INSERT INTO %s (id, birth_year) VALUES ('Bob', 42)"); + + assertRows(execute("SELECT id FROM %s WHERE birth_year = 42"), + row("Tom"), + row("Bob")); + + execute("DROP INDEX %s_birth_year_idx"); + + assertInvalid("SELECT id FROM users WHERE birth_year = 42"); + } + + /** + * Test range queries with 2ndary indexes (#4257), + * migrated from cql_tests.py:TestCQL.range_query_2ndary_test() + */ + @Test + public void testRangeQuery() throws Throwable + { + createTable("CREATE TABLE %s (id int primary key, row int, setid int)"); + createIndex("CREATE INDEX indextest_setid_idx ON %s (setid)"); + + execute("INSERT INTO %s (id, row, setid) VALUES (?, ?, ?)", 0, 0, 0); + execute("INSERT INTO %s (id, row, setid) VALUES (?, ?, ?)", 1, 1, 0); + execute("INSERT INTO %s (id, row, setid) VALUES (?, ?, ?)", 2, 2, 0); + execute("INSERT INTO %s (id, row, setid) VALUES (?, ?, ?)", 3, 3, 0); + + assertInvalid("SELECT * FROM %s WHERE setid = 0 AND row < 1"); + + assertRows(execute("SELECT * FROM %s WHERE setid = 0 AND row < 1 ALLOW FILTERING"), + row(0, 0, 0)); + } + + /** + * Check for unknown compression parameters options (#4266), + * migrated from cql_tests.py:TestCQL.compression_option_validation_test() + */ + @Test + public void testUnknownCompressionOptions() throws Throwable + { + String tableName = createTableName(); + assertInvalidThrow(SyntaxException.class, String.format( + "CREATE TABLE %s (key varchar PRIMARY KEY, password varchar, gender varchar) WITH compression_parameters:sstable_compressor = 'DeflateCompressor'", tableName)); + + + assertInvalidThrow(ConfigurationException.class, String.format( + "CREATE TABLE %s (key varchar PRIMARY KEY, password varchar, gender varchar) WITH compression = { 'sstable_compressor': 'DeflateCompressor' }", tableName)); + } + + /** + * Check one can use arbitrary name for datacenter when creating keyspace (#4278), + * migrated from cql_tests.py:TestCQL.keyspace_creation_options_test() + */ + @Test + public void testDataCenterName() throws Throwable + { + execute("CREATE KEYSPACE Foo WITH replication = { 'class' : 'NetworkTopologyStrategy', 'us-east' : 1, 'us-west' : 1 };"); + } + + /** + * Migrated from cql_tests.py:TestCQL.indexes_composite_test() + */ + @Test + public void testIndexOnComposite() throws Throwable + { + String tableName = createTable("CREATE TABLE %s (blog_id int, timestamp int, author text, content text, PRIMARY KEY (blog_id, timestamp))"); + + execute("INSERT INTO %s (blog_id, timestamp, author, content) VALUES (?, ?, ?, ?)", 0, 0, "bob", "1st post"); + execute("INSERT INTO %s (blog_id, timestamp, author, content) VALUES (?, ?, ?, ?)", 0, 1, "tom", "2nd post"); + execute("INSERT INTO %s (blog_id, timestamp, author, content) VALUES (?, ?, ?, ?)", 0, 2, "bob", "3rd post"); + execute("INSERT INTO %s (blog_id, timestamp, author, content) VALUES (?, ?, ?, ?)", 0, 3, "tom", "4th post"); + execute("INSERT INTO %s (blog_id, timestamp, author, content) VALUES (?, ?, ?, ?)", 1, 0, "bob", "5th post"); + + createIndex("CREATE INDEX authoridx ON %s (author)"); + + assertTrue(waitForIndex(keyspace(), tableName, "authoridx")); + + assertRows(execute("SELECT blog_id, timestamp FROM %s WHERE author = 'bob'"), + row(1, 0), + row(0, 0), + row(0, 2)); + + execute("INSERT INTO %s (blog_id, timestamp, author, content) VALUES (?, ?, ?, ?)", 1, 1, "tom", "6th post"); + execute("INSERT INTO %s (blog_id, timestamp, author, content) VALUES (?, ?, ?, ?)", 1, 2, "tom", "7th post"); + execute("INSERT INTO %s (blog_id, timestamp, author, content) VALUES (?, ?, ?, ?)", 1, 3, "bob", "8th post"); + + assertRows(execute("SELECT blog_id, timestamp FROM %s WHERE author = 'bob'"), + row(1, 0), + row(1, 3), + row(0, 0), + row(0, 2)); + + execute("DELETE FROM %s WHERE blog_id = 0 AND timestamp = 2"); + + assertRows(execute("SELECT blog_id, timestamp FROM %s WHERE author = 'bob'"), + row(1, 0), + row(1, 3), + row(0, 0)); + } + + /** + * Test for the validation bug of #4709, + * migrated from cql_tests.py:TestCQL.refuse_in_with_indexes_test() + */ + @Test + public void testInvalidIndexSelect() throws Throwable + { + createTable("create table %s (pk varchar primary key, col1 varchar, col2 varchar)"); + createIndex("create index on %s (col1)"); + createIndex("create index on %s (col2)"); + + execute("insert into %s (pk, col1, col2) values ('pk1','foo1','bar1')"); + execute("insert into %s (pk, col1, col2) values ('pk1a','foo1','bar1')"); + execute("insert into %s (pk, col1, col2) values ('pk1b','foo1','bar1')"); + execute("insert into %s (pk, col1, col2) values ('pk1c','foo1','bar1')"); + execute("insert into %s (pk, col1, col2) values ('pk2','foo2','bar2')"); + execute("insert into %s (pk, col1, col2) values ('pk3','foo3','bar3')"); + assertInvalid("select * from %s where col2 in ('bar1', 'bar2')"); + + //Migrated from cql_tests.py:TestCQL.bug_6050_test() + createTable("CREATE TABLE %s (k int PRIMARY KEY, a int, b int)"); + + createIndex("CREATE INDEX ON %s (a)"); + assertInvalid("SELECT * FROM %s WHERE a = 3 AND b IN (1, 3)"); + + } + + /** + * Migrated from cql_tests.py:TestCQL.edge_2i_on_complex_pk_test() + */ + @Test + public void testIndexesOnComplexPrimaryKey() throws Throwable + { + createTable("CREATE TABLE %s (pk0 int, pk1 int, ck0 int, ck1 int, ck2 int, value int, PRIMARY KEY ((pk0, pk1), ck0, ck1, ck2))"); + + execute("CREATE INDEX ON %s (pk0)"); + execute("CREATE INDEX ON %s (ck0)"); + execute("CREATE INDEX ON %s (ck1)"); + execute("CREATE INDEX ON %s (ck2)"); + + execute("INSERT INTO %s (pk0, pk1, ck0, ck1, ck2, value) VALUES (0, 1, 2, 3, 4, 5)"); + execute("INSERT INTO %s (pk0, pk1, ck0, ck1, ck2, value) VALUES (1, 2, 3, 4, 5, 0)"); + execute("INSERT INTO %s (pk0, pk1, ck0, ck1, ck2, value) VALUES (2, 3, 4, 5, 0, 1)"); + execute("INSERT INTO %s (pk0, pk1, ck0, ck1, ck2, value) VALUES (3, 4, 5, 0, 1, 2)"); + execute("INSERT INTO %s (pk0, pk1, ck0, ck1, ck2, value) VALUES (4, 5, 0, 1, 2, 3)"); + execute("INSERT INTO %s (pk0, pk1, ck0, ck1, ck2, value) VALUES (5, 0, 1, 2, 3, 4)"); + + assertRows(execute("SELECT value FROM %s WHERE pk0 = 2"), + row(1)); + + assertRows(execute("SELECT value FROM %s WHERE ck0 = 0"), + row(3)); + + assertRows(execute("SELECT value FROM %s WHERE pk0 = 3 AND pk1 = 4 AND ck1 = 0"), + row(2)); + + assertRows(execute("SELECT value FROM %s WHERE pk0 = 5 AND pk1 = 0 AND ck0 = 1 AND ck2 = 3 ALLOW FILTERING"), + row(4)); + } + + /** + * Test for CASSANDRA-5240, + * migrated from cql_tests.py:TestCQL.bug_5240_test() + */ + @Test + public void testIndexOnCompoundRowKey() throws Throwable + { + createTable("CREATE TABLE %s (interval text, seq int, id int, severity int, PRIMARY KEY ((interval, seq), id) ) WITH CLUSTERING ORDER BY (id DESC)"); + + execute("CREATE INDEX ON %s (severity)"); + + execute("insert into %s (interval, seq, id , severity) values('t',1, 1, 1)"); + execute("insert into %s (interval, seq, id , severity) values('t',1, 2, 1)"); + execute("insert into %s (interval, seq, id , severity) values('t',1, 3, 2)"); + execute("insert into %s (interval, seq, id , severity) values('t',1, 4, 3)"); + execute("insert into %s (interval, seq, id , severity) values('t',2, 1, 3)"); + execute("insert into %s (interval, seq, id , severity) values('t',2, 2, 3)"); + execute("insert into %s (interval, seq, id , severity) values('t',2, 3, 1)"); + execute("insert into %s (interval, seq, id , severity) values('t',2, 4, 2)"); + + assertRows(execute("select * from %s where severity = 3 and interval = 't' and seq =1"), + row("t", 1, 4, 3)); + } + + /** + * Migrated from cql_tests.py:TestCQL.secondary_index_counters() + */ + @Test + public void testIndexOnCountersInvalid() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, c counter)"); + assertInvalid("CREATE INDEX ON test(c)"); + } + + /** + * Migrated from cql_tests.py:TestCQL.collection_indexing_test() + */ + @Test + public void testIndexOnCollections() throws Throwable + { + createTable(" CREATE TABLE %s ( k int, v int, l list, s set, m map, PRIMARY KEY (k, v))"); + + createIndex("CREATE INDEX ON %s (l)"); + createIndex("CREATE INDEX ON %s (s)"); + createIndex("CREATE INDEX ON %s (m)"); + + execute("INSERT INTO %s (k, v, l, s, m) VALUES (0, 0, [1, 2], {'a'}, {'a' : 1})"); + execute("INSERT INTO %s (k, v, l, s, m) VALUES (0, 1, [3, 4], {'b', 'c'}, {'a' : 1, 'b' : 2})"); + execute("INSERT INTO %s (k, v, l, s, m) VALUES (0, 2, [1], {'a', 'c'}, {'c' : 3})"); + execute("INSERT INTO %s (k, v, l, s, m) VALUES (1, 0, [1, 2, 4], {}, {'b' : 1})"); + execute("INSERT INTO %s (k, v, l, s, m) VALUES (1, 1, [4, 5], {'d'}, {'a' : 1, 'b' : 3})"); + + // lists + assertRows(execute("SELECT k, v FROM %s WHERE l CONTAINS 1"), row(1, 0), row(0, 0), row(0, 2)); + assertRows(execute("SELECT k, v FROM %s WHERE k = 0 AND l CONTAINS 1"), row(0, 0), row(0, 2)); + assertRows(execute("SELECT k, v FROM %s WHERE l CONTAINS 2"), row(1, 0), row(0, 0)); + assertEmpty(execute("SELECT k, v FROM %s WHERE l CONTAINS 6")); + + // sets + assertRows(execute("SELECT k, v FROM %s WHERE s CONTAINS 'a'"), row(0, 0), row(0, 2)); + assertRows(execute("SELECT k, v FROM %s WHERE k = 0 AND s CONTAINS 'a'"), row(0, 0), row(0, 2)); + assertRows(execute("SELECT k, v FROM %s WHERE s CONTAINS 'd'"), row(1, 1)); + assertEmpty(execute("SELECT k, v FROM %s WHERE s CONTAINS 'e'")); + + // maps + assertRows(execute("SELECT k, v FROM %s WHERE m CONTAINS 1"), row(1, 0), row(1, 1), row(0, 0), row(0, 1)); + assertRows(execute("SELECT k, v FROM %s WHERE k = 0 AND m CONTAINS 1"), row(0, 0), row(0, 1)); + assertRows(execute("SELECT k, v FROM %s WHERE m CONTAINS 2"), row(0, 1)); + assertEmpty(execute("SELECT k, v FROM %s WHERE m CONTAINS 4")); + } + + /** + * Migrated from cql_tests.py:TestCQL.map_keys_indexing() + */ + @Test + public void testIndexOnMapKeys() throws Throwable + { + createTable("CREATE TABLE %s (k int, v int, m map, PRIMARY KEY (k, v))"); + + createIndex("CREATE INDEX ON %s(keys(m))"); + + execute("INSERT INTO %s (k, v, m) VALUES (0, 0, {'a' : 1})"); + execute("INSERT INTO %s (k, v, m) VALUES (0, 1, {'a' : 1, 'b' : 2})"); + execute("INSERT INTO %s (k, v, m) VALUES (0, 2, {'c' : 3})"); + execute("INSERT INTO %s (k, v, m) VALUES (1, 0, {'b' : 1})"); + execute("INSERT INTO %s (k, v, m) VALUES (1, 1, {'a' : 1, 'b' : 3})"); + + // maps + assertRows(execute("SELECT k, v FROM %s WHERE m CONTAINS KEY 'a'"), row(1, 1), row(0, 0), row(0, 1)); + assertRows(execute("SELECT k, v FROM %s WHERE k = 0 AND m CONTAINS KEY 'a'"), row(0, 0), row(0, 1)); + assertRows(execute("SELECT k, v FROM %s WHERE m CONTAINS KEY 'c'"), row(0, 2)); + assertEmpty(execute("SELECT k, v FROM %s WHERE m CONTAINS KEY 'd'")); + + // we're not allowed to create a value index if we already have a key one + assertInvalid("CREATE INDEX ON %s(m)"); + } + + /** + * Test for #6950 bug, + * migrated from cql_tests.py:TestCQL.key_index_with_reverse_clustering() + */ + @Test + public void testIndexOnKeyWithReverseClustering() throws Throwable + { + createTable(" CREATE TABLE %s (k1 int, k2 int, v int, PRIMARY KEY ((k1, k2), v) ) WITH CLUSTERING ORDER BY (v DESC)"); + + createIndex("CREATE INDEX ON %s (k2)"); + + execute("INSERT INTO %s (k1, k2, v) VALUES (0, 0, 1)"); + execute("INSERT INTO %s (k1, k2, v) VALUES (0, 1, 2)"); + execute("INSERT INTO %s (k1, k2, v) VALUES (0, 0, 3)"); + execute("INSERT INTO %s (k1, k2, v) VALUES (1, 0, 4)"); + execute("INSERT INTO %s (k1, k2, v) VALUES (1, 1, 5)"); + execute("INSERT INTO %s (k1, k2, v) VALUES (2, 0, 7)"); + execute("INSERT INTO %s (k1, k2, v) VALUES (2, 1, 8)"); + execute("INSERT INTO %s (k1, k2, v) VALUES (3, 0, 1)"); + + assertRows(execute("SELECT * FROM %s WHERE k2 = 0 AND v >= 2 ALLOW FILTERING"), + row(2, 0, 7), + row(0, 0, 3), + row(1, 0, 4)); + } + + /** + * Test for CASSANDRA-6612, + * migrated from cql_tests.py:TestCQL.bug_6612_test() + */ + @Test + public void testSelectCountOnIndexedColumn() throws Throwable + { + createTable("CREATE TABLE %s (username text, session_id text, app_name text, account text, last_access timestamp, created_on timestamp, PRIMARY KEY (username, session_id, app_name, account))"); + + createIndex("create index ON %s (app_name)"); + createIndex("create index ON %s (last_access)"); + + assertRows(execute("select count(*) from %s where app_name='foo' and account='bar' and last_access > 4 allow filtering"), row(0L)); + + execute("insert into %s (username, session_id, app_name, account, last_access, created_on) values ('toto', 'foo', 'foo', 'bar', 12, 13)"); + + assertRows(execute("select count(*) from %s where app_name='foo' and account='bar' and last_access > 4 allow filtering"), row(1L)); + } + + /** + * Test for CASSANDRA-5732, Can not query secondary index + * migrated from cql_tests.py:TestCQL.bug_5732_test(), + * which was executing with a row cache size of 100 MB + * and restarting the node, here we just cleanup the cache. + */ + @Test + public void testCanQuerySecondaryIndex() throws Throwable + { + String tableName = createTable("CREATE TABLE %s (k int PRIMARY KEY, v int,)"); + + execute("ALTER TABLE %s WITH CACHING='ALL'"); + execute("INSERT INTO %s (k,v) VALUES (0,0)"); + execute("INSERT INTO %s (k,v) VALUES (1,1)"); + + createIndex("CREATE INDEX testindex on %s (v)"); + assertTrue(waitForIndex(keyspace(), tableName, "testindex")); + + assertRows(execute("SELECT k FROM %s WHERE v = 0"), row(0)); + cleanupCache(); + assertRows(execute("SELECT k FROM %s WHERE v = 0"), row(0)); + } + + // CASSANDRA-8280/8081 + // reject updates with indexed values where value > 64k + @Test + public void testIndexOnCompositeValueOver64k() throws Throwable + { + createTable("CREATE TABLE %s(a int, b int, c blob, PRIMARY KEY (a))"); + createIndex("CREATE INDEX ON %s(c)"); + failInsert("INSERT INTO %s (a, b, c) VALUES (0, 0, ?)", ByteBuffer.allocate(TOO_BIG)); + } + + @Test + public void testIndexOnClusteringColumnInsertPartitionKeyAndClusteringsOver64k() throws Throwable + { + createTable("CREATE TABLE %s(a blob, b blob, c blob, d int, PRIMARY KEY (a, b, c))"); + createIndex("CREATE INDEX ON %s(b)"); + + // CompositeIndexOnClusteringKey creates index entries composed of the + // PK plus all of the non-indexed clustering columns from the primary row + // so we should reject where len(a) + len(c) > 65560 as this will form the + // total clustering in the index table + ByteBuffer a = ByteBuffer.allocate(100); + ByteBuffer b = ByteBuffer.allocate(10); + ByteBuffer c = ByteBuffer.allocate(FBUtilities.MAX_UNSIGNED_SHORT - 99); + + failInsert("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, 0)", a, b, c); + } + + @Test + public void testCompactTableWithValueOver64k() throws Throwable + { + createTable("CREATE TABLE %s(a int, b blob, PRIMARY KEY (a)) WITH COMPACT STORAGE"); + createIndex("CREATE INDEX ON %s(b)"); + failInsert("INSERT INTO %s (a, b) VALUES (0, ?)", ByteBuffer.allocate(TOO_BIG)); + } + + @Test + public void testIndexOnCollectionValueInsertPartitionKeyAndCollectionKeyOver64k() throws Throwable + { + createTable("CREATE TABLE %s(a blob , b map, PRIMARY KEY (a))"); + createIndex("CREATE INDEX ON %s(b)"); + + // A collection key > 64k by itself will be rejected from + // the primary table. + // To test index validation we need to ensure that + // len(b) < 64k, but len(a) + len(b) > 64k as that will + // form the clustering in the index table + ByteBuffer a = ByteBuffer.allocate(100); + ByteBuffer b = ByteBuffer.allocate(FBUtilities.MAX_UNSIGNED_SHORT - 100); + + failInsert("UPDATE %s SET b[?] = 0 WHERE a = ?", b, a); + } + + @Test + public void testIndexOnCollectionKeyInsertPartitionKeyAndClusteringOver64k() throws Throwable + { + createTable("CREATE TABLE %s(a blob, b blob, c map, PRIMARY KEY (a, b))"); + createIndex("CREATE INDEX ON %s(KEYS(c))"); + + // Basically the same as the case with non-collection clustering + // CompositeIndexOnCollectionKeyy creates index entries composed of the + // PK plus all of the clustering columns from the primary row, except the + // collection element - which becomes the partition key in the index table + ByteBuffer a = ByteBuffer.allocate(100); + ByteBuffer b = ByteBuffer.allocate(FBUtilities.MAX_UNSIGNED_SHORT - 100); + ByteBuffer c = ByteBuffer.allocate(10); + + failInsert("UPDATE %s SET c[?] = 0 WHERE a = ? and b = ?", c, a, b); + } + + @Test + public void testIndexOnPartitionKeyInsertValueOver64k() throws Throwable + { + createTable("CREATE TABLE %s(a int, b int, c blob, PRIMARY KEY ((a, b)))"); + createIndex("CREATE INDEX ON %s(a)"); + succeedInsert("INSERT INTO %s (a, b, c) VALUES (0, 0, ?)", ByteBuffer.allocate(TOO_BIG)); + } + + @Test + public void testIndexOnClusteringColumnInsertValueOver64k() throws Throwable + { + createTable("CREATE TABLE %s(a int, b int, c blob, PRIMARY KEY (a, b))"); + createIndex("CREATE INDEX ON %s(b)"); + succeedInsert("INSERT INTO %s (a, b, c) VALUES (0, 0, ?)", ByteBuffer.allocate(TOO_BIG)); + } + + @Test + public void testIndexOnFullCollectionEntryInsertCollectionValueOver64k() throws Throwable + { + createTable("CREATE TABLE %s(a int, b frozen>, PRIMARY KEY (a))"); + createIndex("CREATE INDEX ON %s(full(b))"); + Map map = new HashMap(); + map.put(0, ByteBuffer.allocate(1024 * 65)); + failInsert("INSERT INTO %s (a, b) VALUES (0, ?)", map); + } + + public void failInsert(String insertCQL, Object...args) throws Throwable + { + try + { + execute(insertCQL, args); + fail("Expected statement to fail validation"); + } + catch (Exception e) + { + // as expected + } + } + + public void succeedInsert(String insertCQL, Object...args) throws Throwable + { + execute(insertCQL, args); + flush(); + } + + /** + * Migrated from cql_tests.py:TestCQL.clustering_indexing_test() + */ + @Test + public void testIndexesOnClustering() throws Throwable + { + createTable("CREATE TABLE %s ( id1 int, id2 int, author text, time bigint, v1 text, v2 text, PRIMARY KEY ((id1, id2), author, time))"); + + createIndex("CREATE INDEX ON %s (time)"); + execute("CREATE INDEX ON %s (id2)"); + + execute("INSERT INTO %s (id1, id2, author, time, v1, v2) VALUES(0, 0, 'bob', 0, 'A', 'A')"); + execute("INSERT INTO %s (id1, id2, author, time, v1, v2) VALUES(0, 0, 'bob', 1, 'B', 'B')"); + execute("INSERT INTO %s (id1, id2, author, time, v1, v2) VALUES(0, 1, 'bob', 2, 'C', 'C')"); + execute("INSERT INTO %s (id1, id2, author, time, v1, v2) VALUES(0, 0, 'tom', 0, 'D', 'D')"); + execute("INSERT INTO %s (id1, id2, author, time, v1, v2) VALUES(0, 1, 'tom', 1, 'E', 'E')"); + + assertRows(execute("SELECT v1 FROM %s WHERE time = 1"), + row("B"), row("E")); + + assertRows(execute("SELECT v1 FROM %s WHERE id2 = 1"), + row("C"), row("E")); + + assertRows(execute("SELECT v1 FROM %s WHERE id1 = 0 AND id2 = 0 AND author = 'bob' AND time = 0"), + row("A")); + + // Test for CASSANDRA-8206 + execute("UPDATE %s SET v2 = null WHERE id1 = 0 AND id2 = 0 AND author = 'bob' AND time = 1"); + + assertRows(execute("SELECT v1 FROM %s WHERE id2 = 0"), + row("A"), row("B"), row("D")); + + assertRows(execute("SELECT v1 FROM %s WHERE time = 1"), + row("B"), row("E")); + } + + /** + * Migrated from cql_tests.py:TestCQL.invalid_clustering_indexing_test() + */ + @Test + public void testIndexesOnClusteringInvalid() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY ((a, b))) WITH COMPACT STORAGE"); + assertInvalid("CREATE INDEX ON %s (a)"); + assertInvalid("CREATE INDEX ON %s (b)"); + + createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY (a, b)) WITH COMPACT STORAGE"); + assertInvalid("CREATE INDEX ON %s (a)"); + assertInvalid("CREATE INDEX ON %s (b)"); + assertInvalid("CREATE INDEX ON %s (c)"); + + createTable("CREATE TABLE %s (a int, b int, c int static , PRIMARY KEY (a, b))"); + assertInvalid("CREATE INDEX ON %s (c)"); + } + +} diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/StaticColumnsTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/StaticColumnsTest.java new file mode 100644 index 0000000000..cef6f1f326 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/StaticColumnsTest.java @@ -0,0 +1,271 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.cql3.validation.entities; + +import java.util.Arrays; + +import org.junit.Test; + +import org.apache.cassandra.cql3.CQLTester; + +import static junit.framework.Assert.assertNull; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class StaticColumnsTest extends CQLTester +{ + + /** + * Migrated from cql_tests.py:TestCQL.static_columns_test() + */ + @Test + public void testStaticColumns() throws Throwable + { + createTable("CREATE TABLE %s ( k int, p int, s int static, v int, PRIMARY KEY (k, p))"); + + execute("INSERT INTO %s(k, s) VALUES (0, 42)"); + + assertRows(execute("SELECT * FROM %s"), row(0, null, 42, null)); + + // Check that writetime works (//7081) -- we can't predict the exact value easily so + // we just check that it's non zero + Object[][] row = getRows(execute("SELECT s, writetime(s) FROM %s WHERE k=0")); + assertEquals(42, row[0][0]); + assertTrue((Long)row[0][1] > 0); + + execute("INSERT INTO %s (k, p, s, v) VALUES (0, 0, 12, 0)"); + execute("INSERT INTO %s (k, p, s, v) VALUES (0, 1, 24, 1)"); + + // Check the static columns in indeed "static" + assertRows(execute("SELECT * FROM %s"), row(0, 0, 24, 0), row(0, 1, 24, 1)); + + // Check we do correctly get the static column value with a SELECT *, even + // if we're only slicing part of the partition + assertRows(execute("SELECT * FROM %s WHERE k=0 AND p=0"), row(0, 0, 24, 0)); + assertRows(execute("SELECT * FROM %s WHERE k=0 AND p=1"), row(0, 1, 24, 1)); + + // Test for IN on the clustering key (//6769) + assertRows(execute("SELECT * FROM %s WHERE k=0 AND p IN (0, 1)"), row(0, 0, 24, 0), row(0, 1, 24, 1)); + + // Check things still work if we don't select the static column. We also want + // this to not request the static columns internally at all, though that part + // require debugging to assert + assertRows(execute("SELECT p, v FROM %s WHERE k=0 AND p=1"), row(1, 1)); + + // Check selecting only a static column with distinct only yield one value + // (as we only query the static columns) + assertRows(execute("SELECT DISTINCT s FROM %s WHERE k=0"), row(24)); + // But without DISTINCT, we still get one result per row + assertRows(execute("SELECT s FROM %s WHERE k=0"),row(24),row(24)); + // but that querying other columns does correctly yield the full partition + assertRows(execute("SELECT s, v FROM %s WHERE k=0"),row(24, 0),row(24, 1)); + assertRows(execute("SELECT s, v FROM %s WHERE k=0 AND p=1"),row(24, 1)); + assertRows(execute("SELECT p, s FROM %s WHERE k=0 AND p=1"), row(1, 24)); + assertRows(execute("SELECT k, p, s FROM %s WHERE k=0 AND p=1"),row(0, 1, 24)); + + // Check that deleting a row don't implicitely deletes statics + execute("DELETE FROM %s WHERE k=0 AND p=0"); + assertRows(execute("SELECT * FROM %s"),row(0, 1, 24, 1)); + + // But that explicitely deleting the static column does remove it + execute("DELETE s FROM %s WHERE k=0"); + assertRows(execute("SELECT * FROM %s"), row(0, 1, null, 1)); + + // Check we can add a static column ... + execute("ALTER TABLE %s ADD s2 int static"); + assertRows(execute("SELECT * FROM %s"), row(0, 1, null, null, 1)); + execute("INSERT INTO %s (k, p, s2, v) VALUES(0, 2, 42, 2)"); + assertRows(execute("SELECT * FROM %s"), row(0, 1, null, 42, 1), row(0, 2, null, 42, 2)); + // ... and that we can drop it + execute("ALTER TABLE %s DROP s2"); + assertRows(execute("SELECT * FROM %s"), row(0, 1, null, 1), row(0, 2, null, 2)); + } + + /** + * Migrated from cql_tests.py:TestCQL.static_columns_with_2i_test() + */ + @Test + public void testStaticColumnsWithSecondaryIndex() throws Throwable + { + createTable(" CREATE TABLE %s (k int, p int, s int static, v int, PRIMARY KEY (k, p) ) "); + + createIndex("CREATE INDEX ON %s (v)"); + + execute("INSERT INTO %s (k, p, s, v) VALUES (0, 0, 42, 1)"); + execute("INSERT INTO %s (k, p, v) VALUES (0, 1, 1)"); + execute("INSERT INTO %s (k, p, v) VALUES (0, 2, 2)"); + + assertRows(execute("SELECT * FROM %s WHERE v = 1"), row(0, 0, 42, 1), row(0, 1, 42, 1)); + assertRows(execute("SELECT p, s FROM %s WHERE v = 1"), row(0, 42), row(1, 42)); + assertRows(execute("SELECT p FROM %s WHERE v = 1"), row(0), row(1)); + // We don't support that + assertInvalid("SELECT s FROM %s WHERE v = 1"); + } + + /** + * Migrated from cql_tests.py:TestCQL.static_columns_with_distinct_test() + */ + @Test + public void testStaticColumnsWithDistinct() throws Throwable + { + createTable("CREATE TABLE %s( k int, p int, s int static, PRIMARY KEY (k, p) ) "); + + execute("INSERT INTO %s (k, p) VALUES (1, 1)"); + execute("INSERT INTO %s (k, p) VALUES (1, 2)"); + + assertRows(execute("SELECT k, s FROM %s"), row(1, null), row(1, null)); + assertRows(execute("SELECT DISTINCT k, s FROM %s"), row(1, null)); + + Object[][] rows = getRows(execute("SELECT DISTINCT s FROM %s WHERE k=1")); + assertNull(rows[0][0]); + + assertEmpty(execute("SELECT DISTINCT s FROM %s WHERE k=2")); + + execute("INSERT INTO %s (k, p, s) VALUES (2, 1, 3)"); + execute("INSERT INTO %s (k, p) VALUES (2, 2)"); + + assertRows(execute("SELECT k, s FROM %s"), row(1, null), row(1, null), row(2, 3), row(2, 3)); + assertRows(execute("SELECT DISTINCT k, s FROM %s"), row(1, null), row(2, 3)); + rows = getRows(execute("SELECT DISTINCT s FROM %s WHERE k=1")); + assertNull(rows[0][0]); + assertRows(execute("SELECT DISTINCT s FROM %s WHERE k=2"), row(3)); + + assertInvalid("SELECT DISTINCT s FROM %s"); + + // paging to test for CASSANDRA-8108 + execute("TRUNCATE %s"); + for (int i = 0; i < 10; i++) + for (int j = 0; j < 10; j++) + execute("INSERT INTO %s (k, p, s) VALUES (?, ?, ?)", i, j, i); + + rows = getRows(execute("SELECT DISTINCT k, s FROM %s")); + checkDistinctRows(rows, true, 0, 10, 0, 10); + + String keys = "0, 1, 2, 3, 4, 5, 6, 7, 8, 9"; + rows = getRows(execute("SELECT DISTINCT k, s FROM %s WHERE k IN (" + keys + ")")); + checkDistinctRows(rows, false, 0, 10, 0, 10); + + // additional testing for CASSANRA-8087 + createTable("CREATE TABLE %s( k int, c1 int, c2 int, s1 int static, s2 int static, PRIMARY KEY (k, c1, c2))"); + + for (int i = 0; i < 10; i++) + for (int j = 0; j < 5; j++) + for (int k = 0; k < 5; k++) + execute("INSERT INTO %s (k, c1, c2, s1, s2) VALUES (?, ?, ?, ?, ?)", i, j, k, i, i + 1); + + rows = getRows(execute("SELECT DISTINCT k, s1 FROM %s")); + checkDistinctRows(rows, true, 0, 10, 0, 10); + + rows = getRows(execute("SELECT DISTINCT k, s2 FROM %s")); + checkDistinctRows(rows, true, 0, 10, 1, 11); + + rows = getRows(execute("SELECT DISTINCT k, s1 FROM %s LIMIT 10")); + checkDistinctRows(rows, true, 0, 10, 0, 10); + + rows = getRows(execute("SELECT DISTINCT k, s1 FROM %s WHERE k IN (" + keys + ")")); + checkDistinctRows(rows, false, 0, 10, 0, 10); + + rows = getRows(execute("SELECT DISTINCT k, s2 FROM %s WHERE k IN (" + keys + ")")); + checkDistinctRows(rows, false, 0, 10, 1, 11); + + rows = getRows(execute("SELECT DISTINCT k, s1 FROM %s WHERE k IN (" + keys + ")")); + checkDistinctRows(rows, true, 0, 10, 0, 10); + } + + void checkDistinctRows(Object[][] rows, boolean sort, int... ranges) + { + assertTrue(ranges.length % 2 == 0); + + int numdim = ranges.length / 2; + int[] from = new int[numdim]; + int[] to = new int[numdim]; + + for (int i = 0, j = 0; i < ranges.length && j < numdim; i+= 2, j++) + { + from[j] = ranges[i]; + to[j] = ranges[i+1]; + } + + //sort the rows + for (int i = 0; i < numdim; i++) + { + int[] vals = new int[rows.length]; + for (int j = 0; j < rows.length; j++) + vals[j] = (Integer)rows[j][i]; + + if (sort) + Arrays.sort(vals); + + for (int j = from[i]; j < to[i]; j++) + assertEquals(j, vals[j - from[i]]); + } + } + + /** + * Test LIMIT when static columns are present (#6956), + * migrated from cql_tests.py:TestCQL.static_with_limit_test() + */ + @Test + public void testStaticColumnsWithLimit() throws Throwable + { + createTable(" CREATE TABLE %s (k int, s int static, v int, PRIMARY KEY (k, v))"); + + execute("INSERT INTO %s (k, s) VALUES(0, 42)"); + for (int i = 0; i < 4; i++) + execute("INSERT INTO %s(k, v) VALUES(0, ?)", i); + + assertRows(execute("SELECT * FROM %s WHERE k = 0 LIMIT 1"), + row(0, 0, 42)); + assertRows(execute("SELECT * FROM %s WHERE k = 0 LIMIT 2"), + row(0, 0, 42), + row(0, 1, 42)); + assertRows(execute("SELECT * FROM %s WHERE k = 0 LIMIT 3"), + row(0, 0, 42), + row(0, 1, 42), + row(0, 2, 42)); + } + + /** + * Test for bug of #7455, + * migrated from cql_tests.py:TestCQL.static_with_empty_clustering_test() + */ + @Test + public void testStaticColumnsWithEmptyClustering() throws Throwable + { + createTable("CREATE TABLE %s (pkey text, ckey text, value text, static_value text static, PRIMARY KEY(pkey, ckey))"); + + execute("INSERT INTO %s (pkey, static_value) VALUES ('partition1', 'static value')"); + execute("INSERT INTO %s (pkey, ckey, value) VALUES('partition1', '', 'value')"); + + assertRows(execute("SELECT * FROM %s"), + row("partition1", "", "static value", "value")); + } + + /** + * Migrated from cql_tests.py:TestCQL.alter_clustering_and_static_test() + */ + @Test + public void testAlterClusteringAndStatic() throws Throwable + { + createTable("CREATE TABLE %s (bar int, PRIMARY KEY (bar))"); + + // We shouldn 't allow static when there is not clustering columns + assertInvalid("ALTER TABLE %s ADD bar2 text static"); + } +} diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/TimestampTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/TimestampTest.java new file mode 100644 index 0000000000..3e70cd06e5 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/TimestampTest.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cassandra.cql3.validation.entities; + +import org.junit.Test; + +import junit.framework.Assert; +import org.apache.cassandra.cql3.CQLTester; + +import static junit.framework.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +public class TimestampTest extends CQLTester +{ + @Test + public void testNegativeTimestamps() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, v int)"); + + execute("INSERT INTO %s (k, v) VALUES (?, ?) USING TIMESTAMP ?", 1, 1, -42L); + assertRows(execute("SELECT writetime(v) FROM %s WHERE k = ?", 1), + row(-42L) + ); + + assertInvalid("INSERT INTO %s (k, v) VALUES (?, ?) USING TIMESTAMP ?", 2, 2, Long.MIN_VALUE); + } + + /** + * Test timestmp and ttl + * migrated from cql_tests.py:TestCQL.timestamp_and_ttl_test() + */ + @Test + public void testTimestampTTL() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, c text, d text)"); + + execute("INSERT INTO %s (k, c) VALUES (1, 'test')"); + execute("INSERT INTO %s (k, c) VALUES (2, 'test') USING TTL 400"); + + Object[][] res = getRows(execute("SELECT k, c, writetime(c), ttl(c) FROM %s")); + Assert.assertEquals(2, res.length); + + for (Object[] r : res) + { + assertTrue(r[2] instanceof Integer || r[2] instanceof Long); + if (r[0].equals(1)) + assertNull(r[3]); + else + assertTrue(r[3] instanceof Integer || r[2] instanceof Long); + } + + + // wrap writetime(), ttl() in other functions (test for CASSANDRA-8451) + res = getRows(execute("SELECT k, c, blobAsBigint(bigintAsBlob(writetime(c))), ttl(c) FROM %s")); + Assert.assertEquals(2, res.length); + + for (Object[] r : res) + { + assertTrue(r[2] instanceof Integer || r[2] instanceof Long); + if (r[0].equals(1)) + assertNull(r[3]); + else + assertTrue(r[3] instanceof Integer || r[2] instanceof Long); + } + + res = getRows(execute("SELECT k, c, writetime(c), blobAsInt(intAsBlob(ttl(c))) FROM %s")); + Assert.assertEquals(2, res.length); + + + for (Object[] r : res) + { + assertTrue(r[2] instanceof Integer || r[2] instanceof Long); + if (r[0].equals(1)) + assertNull(r[3]); + else + assertTrue(r[3] instanceof Integer || r[2] instanceof Long); + } + + assertInvalid("SELECT k, c, writetime(k) FROM %s"); + + assertRows(execute("SELECT k, d, writetime(d) FROM %s WHERE k = 1"), + row(1, null, null)); + } + + /** + * Migrated from cql_tests.py:TestCQL.invalid_custom_timestamp_test() + */ + @Test + public void testInvalidCustomTimestamp() throws Throwable + { + // Conditional updates + createTable("CREATE TABLE %s (k int, v int, PRIMARY KEY (k, v))"); + + execute("BEGIN BATCH " + + "INSERT INTO %1$s (k, v) VALUES(0, 0) IF NOT EXISTS; " + + "INSERT INTO %1$s (k, v) VALUES(0, 1) IF NOT EXISTS; " + + "APPLY BATCH"); + + assertInvalid("BEGIN BATCH " + + "INSERT INTO %1$s (k, v) VALUES(0, 2) IF NOT EXISTS USING TIMESTAMP 1; " + + "INSERT INTO %1$s (k, v) VALUES(0, 3) IF NOT EXISTS; " + + "APPLY BATCH"); + assertInvalid("BEGIN BATCH " + + "USING TIMESTAMP 1 INSERT INTO %1$s (k, v) VALUES(0, 4) IF NOT EXISTS; " + + "INSERT INTO %1$s (k, v) VALUES(0, 1) IF NOT EXISTS; " + + "APPLY BATCH"); + + execute("INSERT INTO %s (k, v) VALUES(1, 0) IF NOT EXISTS"); + assertInvalid("INSERT INTO %s (k, v) VALUES(1, 1) IF NOT EXISTS USING TIMESTAMP 5"); + + // Counters + createTable("CREATE TABLE %s (k int PRIMARY KEY, c counter)"); + + execute("UPDATE %s SET c = c + 1 WHERE k = 0"); + assertInvalid("UPDATE %s USING TIMESTAMP 10 SET c = c + 1 WHERE k = 0"); + + execute("BEGIN COUNTER BATCH " + + "UPDATE %1$s SET c = c + 1 WHERE k = 0; " + + "UPDATE %1$s SET c = c + 1 WHERE k = 0; " + + "APPLY BATCH"); + + assertInvalid("BEGIN COUNTER BATCH " + + "UPDATE %1$s USING TIMESTAMP 3 SET c = c + 1 WHERE k = 0; " + + "UPDATE %1$s SET c = c + 1 WHERE k = 0; " + + "APPLY BATCH"); + + assertInvalid("BEGIN COUNTER BATCH " + + "USING TIMESTAMP 3 UPDATE %1$s SET c = c + 1 WHERE k = 0; " + + "UPDATE %1$s SET c = c + 1 WHERE k = 0; " + + "APPLY BATCH"); + } + + @Test + public void testInsertTimestampWithUnset() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, i int)"); + execute("INSERT INTO %s (k, i) VALUES (1, 1) USING TIMESTAMP ?", unset()); // treat as 'now' + } + +} diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/TimeuuidTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/TimeuuidTest.java new file mode 100644 index 0000000000..0f1f8f04f0 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/TimeuuidTest.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.cql3.validation.entities; + +import java.util.Date; +import java.util.UUID; + +import org.junit.Test; + +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.exceptions.SyntaxException; +import org.apache.cassandra.utils.UUIDGen; + +import static org.junit.Assert.assertEquals; + +public class TimeuuidTest extends CQLTester +{ + /** + * Migrated from cql_tests.py:TestCQL.timeuuid_test() + */ + @Test + public void testTimeuuid() throws Throwable + { + createTable("CREATE TABLE %s (k int, t timeuuid, PRIMARY KEY(k, t))"); + + assertInvalidThrow(SyntaxException.class, "INSERT INTO %s (k, t) VALUES (0, 2012-11-07 18:18:22-0800)"); + + for (int i = 0; i < 4; i++) + execute("INSERT INTO %s (k, t) VALUES (0, now())"); + + Object[][] rows = getRows(execute("SELECT * FROM %s")); + assertEquals(4, rows.length); + + assertRowCount(execute("SELECT * FROM %s WHERE k = 0 AND t >= ?", rows[0][1]), 4); + + assertEmpty(execute("SELECT * FROM %s WHERE k = 0 AND t < ?", rows[0][1])); + + assertRowCount(execute("SELECT * FROM %s WHERE k = 0 AND t > ? AND t <= ?", rows[0][1], rows[2][1]), 2); + + assertRowCount(execute("SELECT * FROM %s WHERE k = 0 AND t = ?", rows[0][1]), 1); + + assertInvalid("SELECT dateOf(k) FROM %s WHERE k = 0 AND t = ?", rows[0][1]); + + for (int i = 0; i < 4; i++) + { + long timestamp = UUIDGen.unixTimestamp((UUID) rows[i][1]); + assertRows(execute("SELECT dateOf(t), unixTimestampOf(t) FROM %s WHERE k = 0 AND t = ?", rows[i][1]), + row(new Date(timestamp), timestamp)); + } + + assertEmpty(execute("SELECT t FROM %s WHERE k = 0 AND t > maxTimeuuid(1234567) AND t < minTimeuuid('2012-11-07 18:18:22-0800')")); + } + + /** + * Test for 5386, + * migrated from cql_tests.py:TestCQL.function_and_reverse_type_test() + */ + @Test + public void testDescClusteringOnTimeuuid() throws Throwable + { + createTable("CREATE TABLE %s (k int, c timeuuid, v int, PRIMARY KEY (k, c)) WITH CLUSTERING ORDER BY (c DESC)"); + + execute("INSERT INTO %s (k, c, v) VALUES (0, now(), 0)"); + } +} diff --git a/test/unit/org/apache/cassandra/cql3/TupleTypeTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/TupleTypeTest.java similarity index 59% rename from test/unit/org/apache/cassandra/cql3/TupleTypeTest.java rename to test/unit/org/apache/cassandra/cql3/validation/entities/TupleTypeTest.java index 48f0caf34b..362756b5fa 100644 --- a/test/unit/org/apache/cassandra/cql3/TupleTypeTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/TupleTypeTest.java @@ -15,10 +15,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.entities; import org.junit.Test; +import org.apache.cassandra.cql3.CQLTester; + public class TupleTypeTest extends CQLTester { @Test @@ -31,21 +33,20 @@ public class TupleTypeTest extends CQLTester execute("INSERT INTO %s (k, t) VALUES (?, ?)", 0, tuple(3, "foo", 3.4)); execute("INSERT INTO %s (k, t) VALUES (?, ?)", 1, tuple(8, "bar", 0.2)); - assertAllRows( - row(0, tuple(3, "foo", 3.4)), - row(1, tuple(8, "bar", 0.2)) + assertAllRows(row(1, tuple(8, "bar", 0.2)), + row(0, tuple(3, "foo", 3.4)) ); // nulls execute("INSERT INTO %s (k, t) VALUES (?, ?)", 2, tuple(5, null, 3.4)); assertRows(execute("SELECT * FROM %s WHERE k=?", 2), - row(2, tuple(5, null, 3.4)) + row(2, tuple(5, null, 3.4)) ); // incomplete tuple execute("INSERT INTO %s (k, t) VALUES (?, ?)", 3, tuple(5, "bar")); assertRows(execute("SELECT * FROM %s WHERE k=?", 3), - row(3, tuple(5, "bar")) + row(3, tuple(5, "bar")) ); } } @@ -58,8 +59,8 @@ public class TupleTypeTest extends CQLTester execute("INSERT INTO %s (k, t) VALUES (?, ?)", 0, tuple(3, tuple("foo", 3.4))); execute("INSERT INTO %s (k, t) VALUES (?, ?)", 1, tuple(8, tuple("bar", 0.2))); assertAllRows( - row(0, tuple(3, tuple("foo", 3.4))), - row(1, tuple(8, tuple("bar", 0.2))) + row(1, tuple(8, tuple("bar", 0.2))), + row(0, tuple(3, tuple("foo", 3.4))) ); } @@ -105,10 +106,66 @@ public class TupleTypeTest extends CQLTester createTable("CREATE TABLE %s (k int PRIMARY KEY, t tuple)"); // invalid positional field substitution assertInvalidMessage("Invalid unset value for tuple field number 1", - "INSERT INTO %s (k, t) VALUES(0, (3, ?, 2.1))", unset()); + "INSERT INTO %s (k, t) VALUES(0, (3, ?, 2.1))", unset()); createIndex("CREATE INDEX tuple_index ON %s (t)"); // select using unset assertInvalidMessage("Invalid unset value for tuple field number 0", "SELECT * FROM %s WHERE k = ? and t = (?,?,?)", unset(), unset(), unset(), unset()); } + + /** + * Test the syntax introduced by #4851, + * migrated from cql_tests.py:TestCQL.tuple_notation_test() + */ + @Test + public void testTupleNotation() throws Throwable + { + createTable("CREATE TABLE %s (k int, v1 int, v2 int, v3 int, PRIMARY KEY (k, v1, v2, v3))"); + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + for (int k = 0; k < 2; k++) + execute("INSERT INTO %s (k, v1, v2, v3) VALUES (0, ?, ?, ?)", i, j, k); + + assertRows(execute("SELECT v1, v2, v3 FROM %s WHERE k = 0"), + row(0, 0, 0), + row(0, 0, 1), + row(0, 1, 0), + row(0, 1, 1), + row(1, 0, 0), + row(1, 0, 1), + row(1, 1, 0), + row(1, 1, 1)); + + assertRows(execute("SELECT v1, v2, v3 FROM %s WHERE k = 0 AND (v1, v2, v3) >= (1, 0, 1)"), + row(1, 0, 1), + row(1, 1, 0), + row(1, 1, 1)); + assertRows(execute("SELECT v1, v2, v3 FROM %s WHERE k = 0 AND (v1, v2) >= (1, 1)"), + row(1, 1, 0), + row(1, 1, 1)); + + assertRows(execute("SELECT v1, v2, v3 FROM %s WHERE k = 0 AND (v1, v2) > (0, 1) AND (v1, v2, v3) <= (1, 1, 0)"), + row(1, 0, 0), + row(1, 0, 1), + row(1, 1, 0)); + + assertInvalid("SELECT v1, v2, v3 FROM %s WHERE k = 0 AND (v1, v3) > (1, 0)"); + } + + /** + * Test for CASSANDRA-8062, + * migrated from cql_tests.py:TestCQL.test_v2_protocol_IN_with_tuples() + */ + @Test + public void testSelectInStatementWithTuples() throws Throwable + { // TODO - the dtest was using v2 protocol + createTable("CREATE TABLE %s (k int, c1 int, c2 text, PRIMARY KEY (k, c1, c2))"); + execute("INSERT INTO %s (k, c1, c2) VALUES (0, 0, 'a')"); + execute("INSERT INTO %s (k, c1, c2) VALUES (0, 0, 'b')"); + execute("INSERT INTO %s (k, c1, c2) VALUES (0, 0, 'c')"); + + assertRows(execute("SELECT * FROM %s WHERE k=0 AND (c1, c2) IN ((0, 'b'), (0, 'c'))"), + row(0, 0, "b"), + row(0, 0, "c")); + } } diff --git a/test/unit/org/apache/cassandra/cql3/TypeTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/TypeTest.java similarity index 96% rename from test/unit/org/apache/cassandra/cql3/TypeTest.java rename to test/unit/org/apache/cassandra/cql3/validation/entities/TypeTest.java index 0605554060..f3aa22be8a 100644 --- a/test/unit/org/apache/cassandra/cql3/TypeTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/TypeTest.java @@ -15,7 +15,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.entities; + +import org.apache.cassandra.cql3.UntypedResultSet; +import org.apache.cassandra.cql3.CQLTester; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/test/unit/org/apache/cassandra/cql3/UFAuthTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFAuthTest.java similarity index 99% rename from test/unit/org/apache/cassandra/cql3/UFAuthTest.java rename to test/unit/org/apache/cassandra/cql3/validation/entities/UFAuthTest.java index 2c36bd1b9d..498f0dd8e5 100644 --- a/test/unit/org/apache/cassandra/cql3/UFAuthTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFAuthTest.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.entities; import java.lang.reflect.Field; import java.util.*; @@ -30,11 +30,15 @@ import org.slf4j.LoggerFactory; import org.apache.cassandra.auth.*; import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.cql3.Attributes; +import org.apache.cassandra.cql3.CQLStatement; +import org.apache.cassandra.cql3.QueryProcessor; import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.functions.FunctionName; import org.apache.cassandra.cql3.functions.Functions; import org.apache.cassandra.cql3.statements.BatchStatement; import org.apache.cassandra.cql3.statements.ModificationStatement; +import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.exceptions.*; import org.apache.cassandra.service.ClientState; import org.apache.cassandra.utils.Pair; diff --git a/test/unit/org/apache/cassandra/cql3/UFIdentificationTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFIdentificationTest.java similarity index 98% rename from test/unit/org/apache/cassandra/cql3/UFIdentificationTest.java rename to test/unit/org/apache/cassandra/cql3/validation/entities/UFIdentificationTest.java index 703bd9a290..28b8afcf2a 100644 --- a/test/unit/org/apache/cassandra/cql3/UFIdentificationTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFIdentificationTest.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.entities; import java.util.*; @@ -25,9 +25,13 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; +import org.apache.cassandra.cql3.Attributes; +import org.apache.cassandra.cql3.CQLStatement; +import org.apache.cassandra.cql3.QueryProcessor; import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.statements.BatchStatement; import org.apache.cassandra.cql3.statements.ModificationStatement; +import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.service.ClientState; import static org.junit.Assert.assertTrue; @@ -322,7 +326,7 @@ public class UFIdentificationTest extends CQLTester private ModificationStatement modificationStatement(String cql) { - return (ModificationStatement)QueryProcessor.getStatement(cql, ClientState.forInternalCalls()).statement; + return (ModificationStatement) QueryProcessor.getStatement(cql, ClientState.forInternalCalls()).statement; } private void assertFunctions(String cql, String... function) diff --git a/test/unit/org/apache/cassandra/cql3/UFTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java similarity index 99% rename from test/unit/org/apache/cassandra/cql3/UFTest.java rename to test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java index 40f2dd310e..2e7c2f1ac1 100644 --- a/test/unit/org/apache/cassandra/cql3/UFTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.entities; import java.math.BigDecimal; import java.math.BigInteger; @@ -31,14 +31,20 @@ import java.util.TreeSet; import java.util.UUID; import org.junit.Assert; +import org.junit.BeforeClass; import org.junit.Test; import com.datastax.driver.core.*; import com.datastax.driver.core.exceptions.InvalidQueryException; +import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.cql3.QueryProcessor; +import org.apache.cassandra.cql3.UntypedResultSet; import org.apache.cassandra.cql3.functions.FunctionName; import org.apache.cassandra.cql3.functions.Functions; import org.apache.cassandra.cql3.functions.UDFunction; +import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.db.marshal.CollectionType; +import org.apache.cassandra.dht.ByteOrderedPartitioner; import org.apache.cassandra.exceptions.FunctionExecutionException; import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.service.ClientState; @@ -50,6 +56,11 @@ import org.apache.cassandra.utils.UUIDGen; public class UFTest extends CQLTester { + @BeforeClass + public static void setUp() + { + DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance); + } @Test public void testSchemaChange() throws Throwable @@ -140,8 +151,8 @@ public class UFTest extends CQLTester // should be unaffected. ResultMessage.Prepared preparedSelect1 = QueryProcessor.prepare( - String.format("SELECT key, %s(d) FROM %s.%s", fSin, KEYSPACE, currentTable()), - ClientState.forInternalCalls(), false); + String.format("SELECT key, %s(d) FROM %s.%s", fSin, KEYSPACE, currentTable()), + ClientState.forInternalCalls(), false); ResultMessage.Prepared preparedSelect2 = QueryProcessor.prepare( String.format("SELECT key FROM %s.%s", KEYSPACE, currentTable()), ClientState.forInternalCalls(), false); diff --git a/test/unit/org/apache/cassandra/cql3/UserTypesTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UserTypesTest.java similarity index 81% rename from test/unit/org/apache/cassandra/cql3/UserTypesTest.java rename to test/unit/org/apache/cassandra/cql3/validation/entities/UserTypesTest.java index bfd3e9f318..7274cd4357 100644 --- a/test/unit/org/apache/cassandra/cql3/UserTypesTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UserTypesTest.java @@ -15,12 +15,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.entities; +import java.util.UUID; + +import org.junit.BeforeClass; import org.junit.Test; +import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.dht.ByteOrderedPartitioner; + public class UserTypesTest extends CQLTester { + @BeforeClass + public static void setUpClass() + { + DatabaseDescriptor.setPartitioner(new ByteOrderedPartitioner()); + } + @Test public void testInvalidField() throws Throwable { @@ -66,7 +79,7 @@ public class UserTypesTest extends CQLTester flush(); assertRows(execute("SELECT v.x FROM %s WHERE k = ? AND v = {x:?}", 1, -104.99251), - row(-104.99251) + row(-104.99251) ); } @@ -121,10 +134,10 @@ public class UserTypesTest extends CQLTester createTable("CREATE TABLE %s (k int PRIMARY KEY, v frozen<" + myType + ">, z frozen<" + myOtherType + ">)"); assertInvalidMessage("Invalid unset value for field 'y' of user defined type " + myType, - "INSERT INTO %s (k, v) VALUES (10, {x:?, y:?})", 1, unset()); + "INSERT INTO %s (k, v) VALUES (10, {x:?, y:?})", 1, unset()); assertInvalidMessage("Invalid unset value for field 'y' of user defined type " + myType, - "INSERT INTO %s (k, v, z) VALUES (10, {x:?, y:?}, {a:{x: ?, y: ?}})", 1, 1, 1, unset()); + "INSERT INTO %s (k, v, z) VALUES (10, {x:?, y:?}, {a:{x: ?, y: ?}})", 1, 1, 1, unset()); } @Test @@ -331,4 +344,61 @@ public class UserTypesTest extends CQLTester row(3, 3, null), row(null, 4, null)); } + + /** + * Migrated from cql_tests.py:TestCQL.user_types_test() + */ + @Test + public void testUserTypes() throws Throwable + { + UUID userID_1 = UUID.fromString("550e8400-e29b-41d4-a716-446655440000"); + + String addressType = createType("CREATE TYPE %s (street text, city text, zip_code int, phones set)"); + + String nameType = createType("CREATE TYPE %s (firstname text, lastname text)"); + + createTable("CREATE TABLE %s (id uuid PRIMARY KEY, name frozen < " + nameType + " >, addresses map < text, frozen < " + addressType + " >> )"); + + execute("INSERT INTO %s (id, name) VALUES(?, { firstname: 'Paul', lastname: 'smith' } )", userID_1); + + assertRows(execute("SELECT name.firstname FROM %s WHERE id = ?", userID_1), row("Paul")); + + execute("UPDATE %s SET addresses = addresses + { 'home': { street: '...', city:'SF', zip_code:94102, phones:{ } } } WHERE id = ?", userID_1); + + // TODO: deserialize the value here and check it 's right. + execute("SELECT addresses FROM %s WHERE id = ? ", userID_1); + } + + /** + * Test user type test that does a little more nesting, + * migrated from cql_tests.py:TestCQL.more_user_types_test() + */ + @Test + public void testNestedUserTypes() throws Throwable + { + String type1 = createType("CREATE TYPE %s ( s set, m map, l list)"); + + String type2 = createType("CREATE TYPE %s ( s set < frozen < " + type1 + " >>,)"); + + createTable("CREATE TABLE %s (id int PRIMARY KEY, val frozen<" + type2 + ">)"); + + execute("INSERT INTO %s (id, val) VALUES (0, { s : {{ s : {'foo', 'bar'}, m : { 'foo' : 'bar' }, l : ['foo', 'bar']} }})"); + + // TODO: check result once we have an easy way to do it. For now we just check it doesn't crash + execute("SELECT * FROM %s"); + } + + /** + * Migrated from cql_tests.py:TestCQL.add_field_to_udt_test() + */ + @Test + public void testAddFieldToUdt() throws Throwable + { + String typeName = createType("CREATE TYPE %s (fooint int, fooset set )"); + createTable("CREATE TABLE %s (key int PRIMARY KEY, data frozen <" + typeName + ">)"); + + execute("INSERT INTO %s (key, data) VALUES (1, {fooint: 1, fooset: {'2'}})"); + execute("ALTER TYPE " + keyspace() + "." + typeName + " ADD foomap map "); + execute("INSERT INTO %s (key, data) VALUES (1, {fooint: 1, fooset: {'2'}, foomap: {3 : 'bar'}})"); + } } diff --git a/test/unit/org/apache/cassandra/cql3/CrcCheckChanceTest.java b/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/CrcCheckChanceTest.java similarity index 98% rename from test/unit/org/apache/cassandra/cql3/CrcCheckChanceTest.java rename to test/unit/org/apache/cassandra/cql3/validation/miscellaneous/CrcCheckChanceTest.java index ac3ffbc425..98d7d7021a 100644 --- a/test/unit/org/apache/cassandra/cql3/CrcCheckChanceTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/CrcCheckChanceTest.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.miscellaneous; import java.util.List; import java.util.concurrent.ExecutionException; @@ -23,6 +23,7 @@ import java.util.concurrent.Future; import junit.framework.Assert; import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.db.ColumnFamilyStore; import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.db.compaction.CompactionInterruptedException; diff --git a/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/OverflowTest.java b/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/OverflowTest.java new file mode 100644 index 0000000000..5b4359942a --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/OverflowTest.java @@ -0,0 +1,331 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cassandra.cql3.validation.miscellaneous; + +import java.math.BigInteger; + +import org.junit.Test; + +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNull; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.exceptions.SyntaxException; +import org.apache.cassandra.utils.ByteBufferUtil; + +/** + * Any tests that do not fit in any other category, + * migrated from python dtests, CASSANDRA-9160 + **/ +public class OverflowTest extends CQLTester +{ + /** + * Test support for nulls + * migrated from cql_tests.py:TestCQL.null_support_test() + */ + @Test + public void testNullSupport() throws Throwable + { + createTable("CREATE TABLE %s (k int, c int, v1 int, v2 set, PRIMARY KEY (k, c))"); + + execute("INSERT INTO %s (k, c, v1, v2) VALUES (0, 0, null, {'1', '2'})"); + execute("INSERT INTO %s (k, c, v1) VALUES (0, 1, 1)"); + + assertRows(execute("SELECT * FROM %s"), + row(0, 0, null, set("1", "2")), + row(0, 1, 1, null)); + + execute("INSERT INTO %s (k, c, v1) VALUES (0, 1, null)"); + execute("INSERT INTO %s (k, c, v2) VALUES (0, 0, null)"); + + assertRows(execute("SELECT * FROM %s"), + row(0, 0, null, null), + row(0, 1, null, null)); + + assertInvalid("INSERT INTO %s (k, c, v2) VALUES (0, 2, {1, null})"); + assertInvalid("SELECT * FROM %s WHERE k = null"); + assertInvalid("INSERT INTO %s (k, c, v2) VALUES (0, 0, { 'foo', 'bar', null })"); + } + + /** + * Test reserved keywords + * migrated from cql_tests.py:TestCQL.reserved_keyword_test() + */ + @Test + public void testReservedKeywords() throws Throwable + { + createTable("CREATE TABLE %s (key text PRIMARY KEY, count counter)"); + + String tableName = createTableName(); + assertInvalidThrow(SyntaxException.class, String.format("CREATE TABLE %s.%s (select text PRIMARY KEY, x int)", keyspace(), tableName)); + } + + /** + * Test identifiers + * migrated from cql_tests.py:TestCQL.identifier_test() + */ + @Test + public void testIdentifiers() throws Throwable + { + createTable("CREATE TABLE %s (key_23 int PRIMARY KEY, CoLuMn int)"); + + execute("INSERT INTO %s (Key_23, Column) VALUES (0, 0)"); + execute("INSERT INTO %s (KEY_23, COLUMN) VALUES (0, 0)"); + + assertInvalid("INSERT INTO %s (key_23, column, column) VALUES (0, 0, 0)"); + assertInvalid("INSERT INTO %s (key_23, column, COLUMN) VALUES (0, 0, 0)"); + assertInvalid("INSERT INTO %s (key_23, key_23, column) VALUES (0, 0, 0)"); + assertInvalid("INSERT INTO %s (key_23, KEY_23, column) VALUES (0, 0, 0)"); + + String tableName = createTableName(); + assertInvalidThrow(SyntaxException.class, String.format("CREATE TABLE %s.%s (select int PRIMARY KEY, column int)", keyspace(), tableName)); + } + + /** + * Test table options + * migrated from cql_tests.py:TestCQL.table_options_test() + */ + @Test + public void testTableOptions() throws Throwable + { + createTable("CREATE TABLE %s ( k int PRIMARY KEY, c int ) WITH " + + "comment = 'My comment' " + + "AND read_repair_chance = 0.5 " + + "AND dclocal_read_repair_chance = 0.5 " + + "AND gc_grace_seconds = 4 " + + "AND bloom_filter_fp_chance = 0.01 " + + "AND compaction = { 'class' : 'LeveledCompactionStrategy', 'sstable_size_in_mb' : 10 } " + + "AND compression = { 'sstable_compression' : '' } " + + "AND caching = 'all' "); + + execute("ALTER TABLE %s WITH " + + "comment = 'other comment' " + + "AND read_repair_chance = 0.3 " + + "AND dclocal_read_repair_chance = 0.3 " + + "AND gc_grace_seconds = 100 " + + "AND bloom_filter_fp_chance = 0.1 " + + "AND compaction = { 'class': 'SizeTieredCompactionStrategy', 'min_sstable_size' : 42 } " + + "AND compression = { 'sstable_compression' : 'SnappyCompressor' } " + + "AND caching = 'rows_only' "); + } + + /** + * Migrated from cql_tests.py:TestCQL.unescaped_string_test() + */ + @Test + public void testUnescapedString() throws Throwable + { + createTable("CREATE TABLE %s ( k text PRIMARY KEY, c text, )"); + + //The \ in this query string is not forwarded to cassandra. + //The ' is being escaped in python, but only ' is forwarded + //over the wire instead of \'. + assertInvalidThrow(SyntaxException.class, "INSERT INTO %s (k, c) VALUES ('foo', 'CQL is cassandra\'s best friend')"); + } + + /** + * Migrated from cql_tests.py:TestCQL.boolean_test() + */ + @Test + public void testBoolean() throws Throwable + { + createTable("CREATE TABLE %s (k boolean PRIMARY KEY, b boolean)"); + + execute("INSERT INTO %s (k, b) VALUES (true, false)"); + assertRows(execute("SELECT * FROM %s WHERE k = true"), + row(true, false)); + } + + /** + * Migrated from cql_tests.py:TestCQL.float_with_exponent_test() + */ + @Test + public void testFloatWithExponent() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, d double, f float)"); + + execute("INSERT INTO %s (k, d, f) VALUES (0, 3E+10, 3.4E3)"); + execute("INSERT INTO %s (k, d, f) VALUES (1, 3.E10, -23.44E-3)"); + execute("INSERT INTO %s (k, d, f) VALUES (2, 3, -2)"); + } + + /** + * Test regression from #5189, + * migrated from cql_tests.py:TestCQL.compact_metadata_test() + */ + @Test + public void testCompactMetadata() throws Throwable + { + createTable("CREATE TABLE %s (id int primary key, i int ) WITH COMPACT STORAGE"); + + execute("INSERT INTO %s (id, i) VALUES (1, 2)"); + assertRows(execute("SELECT * FROM %s"), + row(1, 2)); + } + + /** + * Migrated from cql_tests.py:TestCQL.conversion_functions_test() + */ + @Test + public void testConversionFunctions() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, i varint, b blob)"); + + execute("INSERT INTO %s (k, i, b) VALUES (0, blobAsVarint(bigintAsBlob(3)), textAsBlob('foobar'))"); + assertRows(execute("SELECT i, blobAsText(b) FROM %s WHERE k = 0"), + row(BigInteger.valueOf(3), "foobar")); + } + + /** + * Migrated from cql_tests.py:TestCQL.empty_blob_test() + */ + @Test + public void testEmptyBlob() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, b blob)"); + execute("INSERT INTO %s (k, b) VALUES (0, 0x)"); + + assertRows(execute("SELECT * FROM %s"), + row(0, ByteBufferUtil.bytes(""))); + } + + private Object[][] fill() throws Throwable + { + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + execute("INSERT INTO %s (k1, k2, v) VALUES (?, ?, ?)", i, j, i + j); + + return getRows(execute("SELECT * FROM %s")); + } + + /** + * Migrated from cql_tests.py:TestCQL.empty_in_test() + */ + @Test + public void testEmpty() throws Throwable + { + createTable("CREATE TABLE %s (k1 int, k2 int, v int, PRIMARY KEY (k1, k2))"); + + // Inserts a few rows to make sure we don 't actually query something + Object[][] rows = fill(); + + // Test empty IN() in SELECT + assertEmpty(execute("SELECT v FROM %s WHERE k1 IN ()")); + assertEmpty(execute("SELECT v FROM %s WHERE k1 = 0 AND k2 IN ()")); + + // Test empty IN() in DELETE + execute("DELETE FROM %s WHERE k1 IN ()"); + assertArrayEquals(rows, getRows(execute("SELECT * FROM %s"))); + + // Test empty IN() in UPDATE + execute("UPDATE %s SET v = 3 WHERE k1 IN () AND k2 = 2"); + assertArrayEquals(rows, getRows(execute("SELECT * FROM %s"))); + + // Same test, but for compact + createTable("CREATE TABLE %s (k1 int, k2 int, v int, PRIMARY KEY (k1, k2)) WITH COMPACT STORAGE"); + + rows = fill(); + + assertEmpty(execute("SELECT v FROM %s WHERE k1 IN ()")); + assertEmpty(execute("SELECT v FROM %s WHERE k1 = 0 AND k2 IN ()")); + + // Test empty IN() in DELETE + execute("DELETE FROM %s WHERE k1 IN ()"); + assertArrayEquals(rows, getRows(execute("SELECT * FROM %s"))); + + // Test empty IN() in UPDATE + execute("UPDATE %s SET v = 3 WHERE k1 IN () AND k2 = 2"); + assertArrayEquals(rows, getRows(execute("SELECT * FROM %s"))); + } + + /** + * Migrated from cql_tests.py:TestCQL.function_with_null_test() + */ + @Test + public void testFunctionWithNull() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, t timeuuid,)"); + + execute("INSERT INTO %s (k) VALUES (0)"); + Object[][] rows = getRows(execute("SELECT dateOf(t) FROM %s WHERE k=0")); + assertNull(rows[0][0]); + } + + /** + * Migrated from cql_tests.py:TestCQL.column_name_validation_test() + */ + @Test + public void testColumnNameValidation() throws Throwable + { + createTable("CREATE TABLE %s (k text, c int, v timeuuid, PRIMARY KEY (k, c))"); + + assertInvalid("INSERT INTO %s (k, c) VALUES ('', 0)"); + + // Insert a value that don't fit 'int' + assertInvalid("INSERT INTO %s (k, c) VALUES (0, 10000000000)"); + + // Insert a non-version 1 uuid + assertInvalid("INSERT INTO %s (k, c, v) VALUES (0, 0, 550e8400-e29b-41d4-a716-446655440000)"); + } + + /** + * Migrated from cql_tests.py:TestCQL.nan_infinity_test() + */ + @Test + public void testNanInfinityValues() throws Throwable + { + createTable("CREATE TABLE %s (f float PRIMARY KEY)"); + + execute("INSERT INTO %s (f) VALUES (NaN)"); + execute("INSERT INTO %s (f) VALUES (-NaN)"); + execute("INSERT INTO %s (f) VALUES (Infinity)"); + execute("INSERT INTO %s (f) VALUES (-Infinity)"); + + Object[][] selected = getRows(execute("SELECT * FROM %s")); + + // selected should be[[nan],[inf],[-inf]], + // but assert element - wise because NaN!=NaN + assertEquals(3, selected.length); + assertEquals(1, selected[0].length); + assertTrue(Float.isNaN((Float) selected[0][0])); + + assertTrue(Float.isInfinite((Float) selected[1][0])); //inf + assertTrue(((Float) selected[1][0]) > 0); + + assertTrue(Float.isInfinite((Float) selected[2][0])); //-inf + assertTrue(((Float) selected[2][0]) < 0); + } + + /** + * Migrated from cql_tests.py:TestCQL.blobAs_functions_test() + */ + @Test + public void testBlobAsFunction() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, v int)"); + + // A blob that is not 4 bytes should be rejected + assertInvalid("INSERT INTO %s (k, v) VALUES (0, blobAsInt(0x01))"); + + execute("INSERT INTO %s (k, v) VALUES (0, blobAsInt(0x00000001))"); + assertRows(execute("select v from %s where k=0"), row(1)); + } +} \ No newline at end of file diff --git a/test/unit/org/apache/cassandra/cql3/PgStringTest.java b/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/PgStringTest.java similarity index 97% rename from test/unit/org/apache/cassandra/cql3/PgStringTest.java rename to test/unit/org/apache/cassandra/cql3/validation/miscellaneous/PgStringTest.java index 0a9d70272d..0d03b94cdf 100644 --- a/test/unit/org/apache/cassandra/cql3/PgStringTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/PgStringTest.java @@ -15,10 +15,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.miscellaneous; import org.junit.Test; +import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.exceptions.SyntaxException; public class PgStringTest extends CQLTester diff --git a/test/unit/org/apache/cassandra/cql3/RoleSyntaxTest.java b/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/RoleSyntaxTest.java similarity index 95% rename from test/unit/org/apache/cassandra/cql3/RoleSyntaxTest.java rename to test/unit/org/apache/cassandra/cql3/validation/miscellaneous/RoleSyntaxTest.java index 02bfe613e4..9dfa47b85a 100644 --- a/test/unit/org/apache/cassandra/cql3/RoleSyntaxTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/RoleSyntaxTest.java @@ -15,10 +15,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.miscellaneous; import org.junit.Test; +import org.apache.cassandra.cql3.CQLTester; + public class RoleSyntaxTest extends CQLTester { @Test diff --git a/test/unit/org/apache/cassandra/cql3/SSTableMetadataTrackingTest.java b/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/SSTableMetadataTrackingTest.java similarity index 98% rename from test/unit/org/apache/cassandra/cql3/SSTableMetadataTrackingTest.java rename to test/unit/org/apache/cassandra/cql3/validation/miscellaneous/SSTableMetadataTrackingTest.java index 7c3965f7ff..2a2ca7bc27 100644 --- a/test/unit/org/apache/cassandra/cql3/SSTableMetadataTrackingTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/SSTableMetadataTrackingTest.java @@ -15,10 +15,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.miscellaneous; import org.junit.Test; +import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.db.ColumnFamilyStore; import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.io.sstable.metadata.StatsMetadata; diff --git a/test/unit/org/apache/cassandra/cql3/SliceQueryFilterWithTombstonesTest.java b/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/TombstonesTest.java similarity index 97% rename from test/unit/org/apache/cassandra/cql3/SliceQueryFilterWithTombstonesTest.java rename to test/unit/org/apache/cassandra/cql3/validation/miscellaneous/TombstonesTest.java index a3f7197a8b..5980372cf6 100644 --- a/test/unit/org/apache/cassandra/cql3/SliceQueryFilterWithTombstonesTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/TombstonesTest.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.miscellaneous; import java.util.concurrent.TimeUnit; @@ -25,6 +25,7 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.db.filter.TombstoneOverwhelmingException; import static junit.framework.Assert.assertTrue; @@ -33,7 +34,7 @@ import static junit.framework.Assert.fail; /** * Test that TombstoneOverwhelmingException gets thrown when it should be and doesn't when it shouldn't be. */ -public class SliceQueryFilterWithTombstonesTest extends CQLTester +public class TombstonesTest extends CQLTester { static final int ORIGINAL_THRESHOLD = DatabaseDescriptor.getTombstoneFailureThreshold(); static final int THRESHOLD = 100; diff --git a/test/unit/org/apache/cassandra/cql3/AggregationTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/AggregationTest.java similarity index 99% rename from test/unit/org/apache/cassandra/cql3/AggregationTest.java rename to test/unit/org/apache/cassandra/cql3/validation/operations/AggregationTest.java index 38c4759fc4..3f6fddae13 100644 --- a/test/unit/org/apache/cassandra/cql3/AggregationTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/AggregationTest.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.operations; import java.math.BigDecimal; import java.text.SimpleDateFormat; @@ -27,8 +27,10 @@ import org.apache.commons.lang3.time.DateUtils; import org.junit.Assert; import org.junit.Test; +import org.apache.cassandra.cql3.QueryProcessor; import org.apache.cassandra.cql3.functions.Functions; import org.apache.cassandra.cql3.functions.UDAggregate; +import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.exceptions.FunctionExecutionException; import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.serializers.Int32Serializer; diff --git a/test/unit/org/apache/cassandra/cql3/AlterTableTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java similarity index 55% rename from test/unit/org/apache/cassandra/cql3/AlterTableTest.java rename to test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java index 4540f3c4f0..95380f4a2f 100644 --- a/test/unit/org/apache/cassandra/cql3/AlterTableTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java @@ -15,15 +15,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.operations; +import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.db.ColumnFamilyStore; import org.apache.cassandra.db.Keyspace; +import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.cassandra.exceptions.SyntaxException; + import org.junit.Test; import static org.junit.Assert.assertEquals; -public class AlterTableTest extends CQLTester +public class AlterTest extends CQLTester { @Test public void testAddList() throws Throwable @@ -110,4 +114,90 @@ public class AlterTableTest extends CQLTester assertEquals(256, cfs.metadata.getMinIndexInterval()); assertEquals(512, cfs.metadata.getMaxIndexInterval()); } + + /** + * Migrated from cql_tests.py:TestCQL.create_alter_options_test() + */ + @Test + public void testCreateAlterKeyspaces() throws Throwable + { + assertInvalidThrow(SyntaxException.class, "CREATE KEYSPACE ks1"); + assertInvalidThrow(ConfigurationException.class, "CREATE KEYSPACE ks1 WITH replication= { 'replication_factor' : 1 }"); + + execute("CREATE KEYSPACE ks1 WITH replication={ 'class' : 'SimpleStrategy', 'replication_factor' : 1 }"); + execute("CREATE KEYSPACE ks2 WITH replication={ 'class' : 'SimpleStrategy', 'replication_factor' : 1 } AND durable_writes=false"); + + assertRows(execute("SELECT keyspace_name, durable_writes FROM system.schema_keyspaces"), + row("ks1", true), + row(KEYSPACE, true), + row(KEYSPACE_PER_TEST, true), + row("ks2", false)); + + execute("ALTER KEYSPACE ks1 WITH replication = { 'class' : 'NetworkTopologyStrategy', 'dc1' : 1 } AND durable_writes=False"); + execute("ALTER KEYSPACE ks2 WITH durable_writes=true"); + + assertRows(execute("SELECT keyspace_name, durable_writes, strategy_class FROM system.schema_keyspaces"), + row("ks1", false, "org.apache.cassandra.locator.NetworkTopologyStrategy"), + row(KEYSPACE, true, "org.apache.cassandra.locator.SimpleStrategy"), + row(KEYSPACE_PER_TEST, true, "org.apache.cassandra.locator.SimpleStrategy"), + row("ks2", true, "org.apache.cassandra.locator.SimpleStrategy")); + + execute("USE ks1"); + + assertInvalidThrow(ConfigurationException.class, "CREATE TABLE cf1 (a int PRIMARY KEY, b int) WITH compaction = { 'min_threshold' : 4 }"); + + execute("CREATE TABLE cf1 (a int PRIMARY KEY, b int) WITH compaction = { 'class' : 'SizeTieredCompactionStrategy', 'min_threshold' : 7 }"); + assertRows(execute("SELECT columnfamily_name, min_compaction_threshold FROM system.schema_columnfamilies WHERE keyspace_name='ks1'"), + row("cf1", 7)); + + // clean-up + execute("DROP KEYSPACE ks1"); + execute("DROP KEYSPACE ks2"); + } + + /** + * Test for bug of 5232, + * migrated from cql_tests.py:TestCQL.alter_bug_test() + */ + @Test + public void testAlterStatementWithAdd() throws Throwable + { + createTable("CREATE TABLE %s (id int PRIMARY KEY, t text)"); + + execute("UPDATE %s SET t = '111' WHERE id = 1"); + + execute("ALTER TABLE %s ADD l list"); + assertRows(execute("SELECT * FROM %s"), + row(1, null, "111")); + + execute("ALTER TABLE %s ADD m map"); + assertRows(execute("SELECT * FROM %s"), + row(1, null, null, "111")); + } + + /** + * Test for 7744, + * migrated from cql_tests.py:TestCQL.downgrade_to_compact_bug_test() + */ + @Test + public void testDowngradeToCompact() throws Throwable + { + createTable("create table %s (k int primary key, v set)"); + execute("insert into %s (k, v) VALUES (0, {'f'})"); + flush(); + execute("alter table %s drop v"); + execute("alter table %s add v int"); + } + + @Test + // tests CASSANDRA-9565 + public void testDoubleWith() throws Throwable + { + String[] stmts = new String[] { "ALTER KEYSPACE WITH WITH DURABLE_WRITES = true", + "ALTER KEYSPACE ks WITH WITH DURABLE_WRITES = true" }; + + for (String stmt : stmts) { + assertInvalidSyntaxMessage("no viable alternative at input 'WITH'", stmt); + } + } } diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/BatchTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/BatchTest.java new file mode 100644 index 0000000000..14478457fb --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/BatchTest.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.cql3.validation.operations; + +import org.junit.Test; + +import org.apache.cassandra.cql3.CQLTester; + +public class BatchTest extends CQLTester +{ + /** + * Test batch statements + * migrated from cql_tests.py:TestCQL.batch_test() + */ + @Test + public void testBatch() throws Throwable + { + createTable("CREATE TABLE %s (userid text PRIMARY KEY, name text, password text)"); + + String query = "BEGIN BATCH\n" + + "INSERT INTO %1$s (userid, password, name) VALUES ('user2', 'ch@ngem3b', 'second user');\n" + + "UPDATE %1$s SET password = 'ps22dhds' WHERE userid = 'user3';\n" + + "INSERT INTO %1$s (userid, password) VALUES ('user4', 'ch@ngem3c');\n" + + "DELETE name FROM %1$s WHERE userid = 'user1';\n" + + "APPLY BATCH;"; + + execute(query); + } + + /** + * Migrated from cql_tests.py:TestCQL.batch_and_list_test() + */ + @Test + public void testBatchAndList() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, l list)"); + + execute("BEGIN BATCH " + + "UPDATE %1$s SET l = l +[ 1 ] WHERE k = 0; " + + "UPDATE %1$s SET l = l + [ 2 ] WHERE k = 0; " + + "UPDATE %1$s SET l = l + [ 3 ] WHERE k = 0; " + + "APPLY BATCH"); + + assertRows(execute("SELECT l FROM %s WHERE k = 0"), + row(list(1, 2, 3))); + + execute("BEGIN BATCH " + + "UPDATE %1$s SET l =[ 1 ] + l WHERE k = 1; " + + "UPDATE %1$s SET l = [ 2 ] + l WHERE k = 1; " + + "UPDATE %1$s SET l = [ 3 ] + l WHERE k = 1; " + + "APPLY BATCH "); + + assertRows(execute("SELECT l FROM %s WHERE k = 1"), + row(list(3, 2, 1))); + } + + /** + * Migrated from cql_tests.py:TestCQL.bug_6115_test() + */ + @Test + public void testBatchDeleteInsert() throws Throwable + { + createTable("CREATE TABLE %s (k int, v int, PRIMARY KEY (k, v))"); + + execute("INSERT INTO %s (k, v) VALUES (0, 1)"); + execute("BEGIN BATCH DELETE FROM %1$s WHERE k=0 AND v=1; INSERT INTO %1$s (k, v) VALUES (0, 2); APPLY BATCH"); + + assertRows(execute("SELECT * FROM %s"), + row(0, 2)); + } + + @Test + public void testBatchWithUnset() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, s text, i int)"); + + // test batch and update + String qualifiedTable = keyspace() + "." + currentTable(); + execute("BEGIN BATCH " + + "INSERT INTO %s (k, s, i) VALUES (100, 'batchtext', 7); " + + "INSERT INTO " + qualifiedTable + " (k, s, i) VALUES (111, 'batchtext', 7); " + + "UPDATE " + qualifiedTable + " SET s=?, i=? WHERE k = 100; " + + "UPDATE " + qualifiedTable + " SET s=?, i=? WHERE k=111; " + + "APPLY BATCH;", null, unset(), unset(), null); + assertRows(execute("SELECT k, s, i FROM %s where k in (100,111)"), + row(100, null, 7), + row(111, "batchtext", null) + ); + } +} diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/CreateTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/CreateTest.java new file mode 100644 index 0000000000..f3d98ff5ff --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/CreateTest.java @@ -0,0 +1,498 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.cql3.validation.operations; + +import java.nio.ByteBuffer; +import java.util.Collection; +import java.util.Collections; +import java.util.UUID; + +import org.junit.Assert; +import org.junit.Test; + +import org.apache.cassandra.config.CFMetaData; +import org.apache.cassandra.config.Schema; +import org.apache.cassandra.config.TriggerDefinition; +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.db.ColumnFamily; +import org.apache.cassandra.db.Mutation; +import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.cassandra.exceptions.SyntaxException; +import org.apache.cassandra.triggers.ITrigger; +import org.apache.cassandra.utils.ByteBufferUtil; + +import static junit.framework.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class CreateTest extends CQLTester +{ + @Test + public void testCQL3PartitionKeyOnlyTable() + { + createTable("CREATE TABLE %s (id text PRIMARY KEY);"); + assertFalse(currentTableMetadata().isThriftCompatible()); + } + + @Test + public void testCreateTableWithSmallintColumns() throws Throwable + { + createTable("CREATE TABLE %s (a text, b smallint, c smallint, primary key (a, b));"); + execute("INSERT INTO %s (a, b, c) VALUES ('1', 1, 2)"); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", "2", Short.MAX_VALUE, Short.MIN_VALUE); + + assertRows(execute("SELECT * FROM %s"), + row("2", Short.MAX_VALUE, Short.MIN_VALUE), + row("1", (short) 1, (short) 2)); + + assertInvalidMessage("Expected 2 bytes for a smallint (4)", + "INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", "3", 1, 2); + assertInvalidMessage("Expected 2 bytes for a smallint (0)", + "INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", "3", (short) 1, ByteBufferUtil.EMPTY_BYTE_BUFFER); + } + + @Test + public void testCreateTinyintColumns() throws Throwable + { + createTable("CREATE TABLE %s (a text, b tinyint, c tinyint, primary key (a, b));"); + execute("INSERT INTO %s (a, b, c) VALUES ('1', 1, 2)"); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", "2", Byte.MAX_VALUE, Byte.MIN_VALUE); + + assertRows(execute("SELECT * FROM %s"), + row("2", Byte.MAX_VALUE, Byte.MIN_VALUE), + row("1", (byte) 1, (byte) 2)); + + assertInvalidMessage("Expected 1 byte for a tinyint (4)", + "INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", "3", 1, 2); + + assertInvalidMessage("Expected 1 byte for a tinyint (0)", + "INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", "3", (byte) 1, ByteBufferUtil.EMPTY_BYTE_BUFFER); + } + + /** + * Creation and basic operations on a static table, + * migrated from cql_tests.py:TestCQL.static_cf_test() + */ + @Test + public void testStaticTable() throws Throwable + { + createTable("CREATE TABLE %s (userid uuid PRIMARY KEY, firstname text, lastname text, age int)"); + + UUID id1 = UUID.fromString("550e8400-e29b-41d4-a716-446655440000"); + UUID id2 = UUID.fromString("f47ac10b-58cc-4372-a567-0e02b2c3d479"); + + execute("INSERT INTO %s (userid, firstname, lastname, age) VALUES (?, ?, ?, ?)", id1, "Frodo", "Baggins", 32); + execute("UPDATE %s SET firstname = ?, lastname = ?, age = ? WHERE userid = ?", "Samwise", "Gamgee", 33, id2); + + assertRows(execute("SELECT firstname, lastname FROM %s WHERE userid = ?", id1), + row("Frodo", "Baggins")); + + assertRows(execute("SELECT * FROM %s WHERE userid = ?", id1), + row(id1, 32, "Frodo", "Baggins")); + + assertRows(execute("SELECT * FROM %s"), + row(id2, 33, "Samwise", "Gamgee"), + row(id1, 32, "Frodo", "Baggins") + ); + + String batch = "BEGIN BATCH " + + "INSERT INTO %1$s (userid, age) VALUES (?, ?) " + + "UPDATE %1$s SET age = ? WHERE userid = ? " + + "DELETE firstname, lastname FROM %1$s WHERE userid = ? " + + "DELETE firstname, lastname FROM %1$s WHERE userid = ? " + + "APPLY BATCH"; + + execute(batch, id1, 36, 37, id2, id1, id2); + + assertRows(execute("SELECT * FROM %s"), + row(id2, 37, null, null), + row(id1, 36, null, null)); + } + + /** + * Creation and basic operations on a static table with compact storage, + * migrated from cql_tests.py:TestCQL.noncomposite_static_cf_test() + */ + @Test + public void testDenseStaticTable() throws Throwable + { + createTable("CREATE TABLE %s (userid uuid PRIMARY KEY, firstname text, lastname text, age int) WITH COMPACT STORAGE"); + + UUID id1 = UUID.fromString("550e8400-e29b-41d4-a716-446655440000"); + UUID id2 = UUID.fromString("f47ac10b-58cc-4372-a567-0e02b2c3d479"); + + execute("INSERT INTO %s (userid, firstname, lastname, age) VALUES (?, ?, ?, ?)", id1, "Frodo", "Baggins", 32); + execute("UPDATE %s SET firstname = ?, lastname = ?, age = ? WHERE userid = ?", "Samwise", "Gamgee", 33, id2); + + assertRows(execute("SELECT firstname, lastname FROM %s WHERE userid = ?", id1), + row("Frodo", "Baggins")); + + assertRows(execute("SELECT * FROM %s WHERE userid = ?", id1), + row(id1, 32, "Frodo", "Baggins")); + + assertRows(execute("SELECT * FROM %s"), + row(id2, 33, "Samwise", "Gamgee"), + row(id1, 32, "Frodo", "Baggins") + ); + + String batch = "BEGIN BATCH " + + "INSERT INTO %1$s (userid, age) VALUES (?, ?) " + + "UPDATE %1$s SET age = ? WHERE userid = ? " + + "DELETE firstname, lastname FROM %1$s WHERE userid = ? " + + "DELETE firstname, lastname FROM %1$s WHERE userid = ? " + + "APPLY BATCH"; + + execute(batch, id1, 36, 37, id2, id1, id2); + + assertRows(execute("SELECT * FROM %s"), + row(id2, 37, null, null), + row(id1, 36, null, null)); + } + + /** + * Creation and basic operations on a non-composite table with compact storage, + * migrated from cql_tests.py:TestCQL.dynamic_cf_test() + */ + @Test + public void testDenseNonCompositeTable() throws Throwable + { + createTable("CREATE TABLE %s (userid uuid, url text, time bigint, PRIMARY KEY (userid, url)) WITH COMPACT STORAGE"); + + UUID id1 = UUID.fromString("550e8400-e29b-41d4-a716-446655440000"); + UUID id2 = UUID.fromString("f47ac10b-58cc-4372-a567-0e02b2c3d479"); + UUID id3 = UUID.fromString("810e8500-e29b-41d4-a716-446655440000"); + + execute("INSERT INTO %s (userid, url, time) VALUES (?, ?, ?)", id1, "http://foo.bar", 42L); + execute("INSERT INTO %s (userid, url, time) VALUES (?, ?, ?)", id1, "http://foo-2.bar", 24L); + execute("INSERT INTO %s (userid, url, time) VALUES (?, ?, ?)", id1, "http://bar.bar", 128L); + execute("UPDATE %s SET time = 24 WHERE userid = ? and url = 'http://bar.foo'", id2); + execute("UPDATE %s SET time = 12 WHERE userid IN (?, ?) and url = 'http://foo-3'", id2, id1); + + assertRows(execute("SELECT url, time FROM %s WHERE userid = ?", id1), + row("http://bar.bar", 128L), + row("http://foo-2.bar", 24L), + row("http://foo-3", 12L), + row("http://foo.bar", 42L)); + + assertRows(execute("SELECT * FROM %s WHERE userid = ?", id2), + row(id2, "http://bar.foo", 24L), + row(id2, "http://foo-3", 12L)); + + assertRows(execute("SELECT time FROM %s"), + row(24L), // id2 + row(12L), + row(128L), // id1 + row(24L), + row(12L), + row(42L) + ); + + // Check we don't allow empty values for url since this is the full underlying cell name (#6152) + assertInvalid("INSERT INTO %s (userid, url, time) VALUES (?, '', 42)", id3); + } + + /** + * Creation and basic operations on a composite table with compact storage, + * migrated from cql_tests.py:TestCQL.dense_cf_test() + */ + @Test + public void testDenseCompositeTable() throws Throwable + { + createTable("CREATE TABLE %s (userid uuid, ip text, port int, time bigint, PRIMARY KEY (userid, ip, port)) WITH COMPACT STORAGE"); + + UUID id1 = UUID.fromString("550e8400-e29b-41d4-a716-446655440000"); + UUID id2 = UUID.fromString("f47ac10b-58cc-4372-a567-0e02b2c3d479"); + + execute("INSERT INTO %s (userid, ip, port, time) VALUES (?, '192.168.0.1', 80, 42)", id1); + execute("INSERT INTO %s (userid, ip, port, time) VALUES (?, '192.168.0.2', 80, 24)", id1); + execute("INSERT INTO %s (userid, ip, port, time) VALUES (?, '192.168.0.2', 90, 42)", id1); + execute("UPDATE %s SET time = 24 WHERE userid = ? AND ip = '192.168.0.2' AND port = 80", id2); + + // we don't have to include all of the clustering columns (see CASSANDRA-7990) + execute("INSERT INTO %s (userid, ip, time) VALUES (?, '192.168.0.3', 42)", id2); + execute("UPDATE %s SET time = 42 WHERE userid = ? AND ip = '192.168.0.4'", id2); + + assertRows(execute("SELECT ip, port, time FROM %s WHERE userid = ?", id1), + row("192.168.0.1", 80, 42L), + row("192.168.0.2", 80, 24L), + row("192.168.0.2", 90, 42L)); + + assertRows(execute("SELECT ip, port, time FROM %s WHERE userid = ? and ip >= '192.168.0.2'", id1), + row("192.168.0.2", 80, 24L), + row("192.168.0.2", 90, 42L)); + + assertRows(execute("SELECT ip, port, time FROM %s WHERE userid = ? and ip = '192.168.0.2'", id1), + row("192.168.0.2", 80, 24L), + row("192.168.0.2", 90, 42L)); + + assertEmpty(execute("SELECT ip, port, time FROM %s WHERE userid = ? and ip > '192.168.0.2'", id1)); + + assertRows(execute("SELECT ip, port, time FROM %s WHERE userid = ? AND ip = '192.168.0.3'", id2), + row("192.168.0.3", null, 42L)); + + assertRows(execute("SELECT ip, port, time FROM %s WHERE userid = ? AND ip = '192.168.0.4'", id2), + row("192.168.0.4", null, 42L)); + + execute("DELETE time FROM %s WHERE userid = ? AND ip = '192.168.0.2' AND port = 80", id1); + + assertRowCount(execute("SELECT * FROM %s WHERE userid = ?", id1), 2); + + execute("DELETE FROM %s WHERE userid = ?", id1); + assertEmpty(execute("SELECT * FROM %s WHERE userid = ?", id1)); + + execute("DELETE FROM %s WHERE userid = ? AND ip = '192.168.0.3'", id2); + assertEmpty(execute("SELECT * FROM %s WHERE userid = ? AND ip = '192.168.0.3'", id2)); + } + + /** + * Creation and basic operations on a composite table, + * migrated from cql_tests.py:TestCQL.sparse_cf_test() + */ + @Test + public void testSparseCompositeTable() throws Throwable + { + createTable("CREATE TABLE %s (userid uuid, posted_month int, posted_day int, body text, posted_by text, PRIMARY KEY (userid, posted_month, posted_day))"); + + UUID id1 = UUID.fromString("550e8400-e29b-41d4-a716-446655440000"); + UUID id2 = UUID.fromString("f47ac10b-58cc-4372-a567-0e02b2c3d479"); + + execute("INSERT INTO %s (userid, posted_month, posted_day, body, posted_by) VALUES (?, 1, 12, 'Something else', 'Frodo Baggins')", id1); + execute("INSERT INTO %s (userid, posted_month, posted_day, body, posted_by) VALUES (?, 1, 24, 'Something something', 'Frodo Baggins')", id1); + execute("UPDATE %s SET body = 'Yo Froddo', posted_by = 'Samwise Gamgee' WHERE userid = ? AND posted_month = 1 AND posted_day = 3", id2); + execute("UPDATE %s SET body = 'Yet one more message' WHERE userid = ? AND posted_month = 1 and posted_day = 30", id1); + + assertRows(execute("SELECT body, posted_by FROM %s WHERE userid = ? AND posted_month = 1 AND posted_day = 24", id1), + row("Something something", "Frodo Baggins")); + + assertRows(execute("SELECT posted_day, body, posted_by FROM %s WHERE userid = ? AND posted_month = 1 AND posted_day > 12", id1), + row(24, "Something something", "Frodo Baggins"), + row(30, "Yet one more message", null)); + + assertRows(execute("SELECT posted_day, body, posted_by FROM %s WHERE userid = ? AND posted_month = 1", id1), + row(12, "Something else", "Frodo Baggins"), + row(24, "Something something", "Frodo Baggins"), + row(30, "Yet one more message", null)); + } + + /** + * Check invalid create table statements, + * migrated from cql_tests.py:TestCQL.create_invalid_test() + */ + @Test + public void testInvalidCreateTableStatements() throws Throwable + { + assertInvalidThrow(SyntaxException.class, "CREATE TABLE test ()"); + + assertInvalid("CREATE TABLE test (c1 text, c2 text, c3 text)"); + assertInvalid("CREATE TABLE test (key1 text PRIMARY KEY, key2 text PRIMARY KEY)"); + + assertInvalid("CREATE TABLE test (key text PRIMARY KEY, key int)"); + assertInvalid("CREATE TABLE test (key text PRIMARY KEY, c int, c text)"); + + assertInvalid("CREATE TABLE test (key text, key2 text, c int, d text, PRIMARY KEY (key, key2)) WITH COMPACT STORAGE"); + } + + /** + * Check obsolete properties from CQL2 are rejected + * migrated from cql_tests.py:TestCQL.invalid_old_property_test() + */ + @Test + public void testObsoleteTableProperties() throws Throwable + { + assertInvalidThrow(SyntaxException.class, "CREATE TABLE test (foo text PRIMARY KEY, c int) WITH default_validation=timestamp"); + + createTable("CREATE TABLE %s (foo text PRIMARY KEY, c int)"); + assertInvalidThrow(SyntaxException.class, "ALTER TABLE %s WITH default_validation=int"); + } + + /** + * Test create and drop keyspace + * migrated from cql_tests.py:TestCQL.keyspace_test() + */ + @Test + public void testKeyspace() throws Throwable + { + assertInvalidThrow(SyntaxException.class, "CREATE KEYSPACE %s testXYZ "); + + execute("CREATE KEYSPACE testXYZ WITH replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }"); + + assertInvalid( + "CREATE KEYSPACE My_much_much_too_long_identifier_that_should_not_work WITH replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }"); + + execute("DROP KEYSPACE testXYZ"); + assertInvalidThrow(ConfigurationException.class, "DROP KEYSPACE non_existing"); + + execute("CREATE KEYSPACE testXYZ WITH replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }"); + + // clean-up + execute("DROP KEYSPACE testXYZ"); + } + + /** + * Test create and drop table + * migrated from cql_tests.py:TestCQL.table_test() + */ + @Test + public void testTable() throws Throwable + { + String table1 = createTable(" CREATE TABLE %s (k int PRIMARY KEY, c int)"); + createTable(" CREATE TABLE %s (k int, name int, value int, PRIMARY KEY(k, name)) WITH COMPACT STORAGE "); + createTable(" CREATE TABLE %s (k int, c int, PRIMARY KEY (k),)"); + + String table4 = createTableName(); + + // repeated column + assertInvalidMessage("Multiple definition of identifier k", String.format("CREATE TABLE %s (k int PRIMARY KEY, c int, k text)", table4)); + + // compact storage limitations + assertInvalidThrow(SyntaxException.class, + String.format("CREATE TABLE %s (k int, name, int, c1 int, c2 int, PRIMARY KEY(k, name)) WITH COMPACT STORAGE", table4)); + + execute(String.format("DROP TABLE %s.%s", keyspace(), table1)); + + createTable(String.format("CREATE TABLE %s.%s ( k int PRIMARY KEY, c1 int, c2 int, ) ", keyspace(), table1)); + } + + /** + * Test truncate statement, + * migrated from cql_tests.py:TestCQL.table_test(). + */ + @Test + public void testTruncate() throws Throwable + { + createTable(" CREATE TABLE %s (k int, name int, value int, PRIMARY KEY(k, name)) WITH COMPACT STORAGE "); + execute("TRUNCATE %s"); + } + + /** + * Migrated from cql_tests.py:TestCQL.multiordering_validation_test() + */ + @Test + public void testMultiOrderingValidation() throws Throwable + { + String tableName = KEYSPACE + "." + createTableName(); + assertInvalid(String.format("CREATE TABLE test (k int, c1 int, c2 int, PRIMARY KEY (k, c1, c2)) WITH CLUSTERING ORDER BY (c2 DESC)", tableName)); + + tableName = KEYSPACE + "." + createTableName(); + assertInvalid(String.format("CREATE TABLE test (k int, c1 int, c2 int, PRIMARY KEY (k, c1, c2)) WITH CLUSTERING ORDER BY (c2 ASC, c1 DESC)", tableName)); + + tableName = KEYSPACE + "." + createTableName(); + assertInvalid(String.format("CREATE TABLE test (k int, c1 int, c2 int, PRIMARY KEY (k, c1, c2)) WITH CLUSTERING ORDER BY (c1 DESC, c2 DESC, c3 DESC)", tableName)); + + createTable("CREATE TABLE %s (k int, c1 int, c2 int, PRIMARY KEY (k, c1, c2)) WITH CLUSTERING ORDER BY (c1 DESC, c2 DESC)"); + createTable("CREATE TABLE %s (k int, c1 int, c2 int, PRIMARY KEY (k, c1, c2)) WITH CLUSTERING ORDER BY (c1 ASC, c2 DESC)"); + } + + @Test + public void testCreateTrigger() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY (a))"); + execute("CREATE TRIGGER trigger_1 ON %s USING '" + TestTrigger.class.getName() + "'"); + assertTriggerExists("trigger_1", TestTrigger.class); + execute("CREATE TRIGGER trigger_2 ON %s USING '" + TestTrigger.class.getName() + "'"); + assertTriggerExists("trigger_2", TestTrigger.class); + assertInvalid("CREATE TRIGGER trigger_1 ON %s USING '" + TestTrigger.class.getName() + "'"); + execute("CREATE TRIGGER \"Trigger 3\" ON %s USING '" + TestTrigger.class.getName() + "'"); + assertTriggerExists("Trigger 3", TestTrigger.class); + } + + @Test + public void testCreateTriggerIfNotExists() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY (a, b))"); + + execute("CREATE TRIGGER IF NOT EXISTS trigger_1 ON %s USING '" + TestTrigger.class.getName() + "'"); + assertTriggerExists("trigger_1", TestTrigger.class); + + execute("CREATE TRIGGER IF NOT EXISTS trigger_1 ON %s USING '" + TestTrigger.class.getName() + "'"); + assertTriggerExists("trigger_1", TestTrigger.class); + } + + @Test + public void testDropTrigger() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY (a))"); + + execute("CREATE TRIGGER trigger_1 ON %s USING '" + TestTrigger.class.getName() + "'"); + assertTriggerExists("trigger_1", TestTrigger.class); + + execute("DROP TRIGGER trigger_1 ON %s"); + assertTriggerDoesNotExists("trigger_1", TestTrigger.class); + + execute("CREATE TRIGGER trigger_1 ON %s USING '" + TestTrigger.class.getName() + "'"); + assertTriggerExists("trigger_1", TestTrigger.class); + + assertInvalid("DROP TRIGGER trigger_2 ON %s"); + + execute("CREATE TRIGGER \"Trigger 3\" ON %s USING '" + TestTrigger.class.getName() + "'"); + assertTriggerExists("Trigger 3", TestTrigger.class); + + execute("DROP TRIGGER \"Trigger 3\" ON %s"); + assertTriggerDoesNotExists("Trigger 3", TestTrigger.class); + } + + @Test + public void testDropTriggerIfExists() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY (a))"); + + execute("DROP TRIGGER IF EXISTS trigger_1 ON %s"); + assertTriggerDoesNotExists("trigger_1", TestTrigger.class); + + execute("CREATE TRIGGER trigger_1 ON %s USING '" + TestTrigger.class.getName() + "'"); + assertTriggerExists("trigger_1", TestTrigger.class); + + execute("DROP TRIGGER IF EXISTS trigger_1 ON %s"); + assertTriggerDoesNotExists("trigger_1", TestTrigger.class); + } + + @Test + // tests CASSANDRA-9565 + public void testDoubleWith() throws Throwable + { + String[] stmts = new String[] { "CREATE KEYSPACE WITH WITH DURABLE_WRITES = true", + "CREATE KEYSPACE ks WITH WITH DURABLE_WRITES = true" }; + + for (String stmt : stmts) { + assertInvalidSyntaxMessage("no viable alternative at input 'WITH'", stmt); + } + } + + private void assertTriggerExists(String name, Class clazz) + { + CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), currentTable()).copy(); + assertTrue("the trigger does not exist", cfm.containsTriggerDefinition(TriggerDefinition.create(name, + clazz.getName()))); + } + + private void assertTriggerDoesNotExists(String name, Class clazz) + { + CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), currentTable()).copy(); + Assert.assertFalse("the trigger exists", cfm.containsTriggerDefinition(TriggerDefinition.create(name, + clazz.getName()))); + } + + public static class TestTrigger implements ITrigger + { + public TestTrigger() { } + public Collection augment(ByteBuffer key, ColumnFamily update) + { + return Collections.emptyList(); + } + } +} diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java new file mode 100644 index 0000000000..476ec83ed5 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java @@ -0,0 +1,329 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.cql3.validation.operations; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.junit.Test; + +import org.apache.cassandra.cql3.CQLTester; + +import static org.junit.Assert.assertEquals; + +public class DeleteTest extends CQLTester +{ + /** Test for cassandra 8558 */ + @Test + public void testRangeDeletion() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY (a, b, c))"); + + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 1, 1, 1); + flush(); + execute("DELETE FROM %s WHERE a=? AND b=?", 1, 1); + flush(); + assertEmpty(execute("SELECT * FROM %s WHERE a=? AND b=? AND c=?", 1, 1, 1)); + } + + /** + * Test simple deletion and in particular check for #4193 bug + * migrated from cql_tests.py:TestCQL.deletion_test() + */ + @Test + public void testDeletion() throws Throwable + { + createTable("CREATE TABLE %s (username varchar, id int, name varchar, stuff varchar, PRIMARY KEY(username, id))"); + + execute("INSERT INTO %s (username, id, name, stuff) VALUES (?, ?, ?, ?)", "abc", 2, "rst", "some value"); + execute("INSERT INTO %s (username, id, name, stuff) VALUES (?, ?, ?, ?)", "abc", 4, "xyz", "some other value"); + + assertRows(execute("SELECT * FROM %s"), + row("abc", 2, "rst", "some value"), + row("abc", 4, "xyz", "some other value")); + + execute("DELETE FROM %s WHERE username='abc' AND id=2"); + + assertRows(execute("SELECT * FROM %s"), + row("abc", 4, "xyz", "some other value")); + + createTable("CREATE TABLE %s (username varchar, id int, name varchar, stuff varchar, PRIMARY KEY(username, id, name)) WITH COMPACT STORAGE"); + + execute("INSERT INTO %s (username, id, name, stuff) VALUES (?, ?, ?, ?)", "abc", 2, "rst", "some value"); + execute("INSERT INTO %s (username, id, name, stuff) VALUES (?, ?, ?, ?)", "abc", 4, "xyz", "some other value"); + + assertRows(execute("SELECT * FROM %s"), + row("abc", 2, "rst", "some value"), + row("abc", 4, "xyz", "some other value")); + + execute("DELETE FROM %s WHERE username='abc' AND id=2"); + + assertRows(execute("SELECT * FROM %s"), + row("abc", 4, "xyz", "some other value")); + } + + /** + * Test deletion by 'composite prefix' (range tombstones) + * migrated from cql_tests.py:TestCQL.range_tombstones_test() + */ + @Test + public void testDeleteByCompositePrefix() throws Throwable + { // This test used 3 nodes just to make sure RowMutation are correctly serialized + + createTable("CREATE TABLE %s ( k int, c1 int, c2 int, v1 int, v2 int, PRIMARY KEY (k, c1, c2))"); + + int numRows = 5; + int col1 = 2; + int col2 = 2; + int cpr = col1 * col2; + + for (int i = 0; i < numRows; i++) + for (int j = 0; j < col1; j++) + for (int k = 0; k < col2; k++) + { + int n = (i * cpr) + (j * col2) + k; + execute("INSERT INTO %s (k, c1, c2, v1, v2) VALUES (?, ?, ?, ?, ?)", i, j, k, n, n); + } + + for (int i = 0; i < numRows; i++) + { + Object[][] rows = getRows(execute("SELECT v1, v2 FROM %s where k = ?", i)); + for (int x = i * cpr; x < (i + 1) * cpr; x++) + { + assertEquals(x, rows[x - i * cpr][0]); + assertEquals(x, rows[x - i * cpr][1]); + } + } + + for (int i = 0; i < numRows; i++) + execute("DELETE FROM %s WHERE k = ? AND c1 = 0", i); + + for (int i = 0; i < numRows; i++) + { + Object[][] rows = getRows(execute("SELECT v1, v2 FROM %s WHERE k = ?", i)); + for (int x = i * cpr + col1; x < (i + 1) * cpr; x++) + { + assertEquals(x, rows[x - i * cpr - col1][0]); + assertEquals(x, rows[x - i * cpr - col1][1]); + } + } + + for (int i = 0; i < numRows; i++) + { + Object[][] rows = getRows(execute("SELECT v1, v2 FROM %s WHERE k = ?", i)); + for (int x = i * cpr + col1; x < (i + 1) * cpr; x++) + { + assertEquals(x, rows[x - i * cpr - col1][0]); + assertEquals(x, rows[x - i * cpr - col1][1]); + } + } + } + + /** + * Test deletion by 'composite prefix' (range tombstones) with compaction + * migrated from cql_tests.py:TestCQL.range_tombstones_compaction_test() + */ + @Test + public void testDeleteByCompositePrefixWithCompaction() throws Throwable + { + createTable("CREATE TABLE %s (k int, c1 int, c2 int, v1 text, PRIMARY KEY (k, c1, c2))"); + + for (int c1 = 0; c1 < 4; c1++) + for (int c2 = 0; c2 < 2; c2++) + execute("INSERT INTO %s (k, c1, c2, v1) VALUES (0, ?, ?, ?)", c1, c2, String.format("%d%d", c1, c2)); + + flush(); + + execute("DELETE FROM %s WHERE k = 0 AND c1 = 1"); + + flush(); + compact(); + + Object[][] rows = getRows(execute("SELECT v1 FROM %s WHERE k = 0")); + + int idx = 0; + for (int c1 = 0; c1 < 4; c1++) + for (int c2 = 0; c2 < 2; c2++) + if (c1 != 1) + assertEquals(String.format("%d%d", c1, c2), rows[idx++][0]); + } + + /** + * Test deletion of rows + * migrated from cql_tests.py:TestCQL.delete_row_test() + */ + @Test + public void testRowDeletion() throws Throwable + { + createTable("CREATE TABLE %s (k int, c1 int, c2 int, v1 int, v2 int, PRIMARY KEY (k, c1, c2))"); + + execute("INSERT INTO %s (k, c1, c2, v1, v2) VALUES (?, ?, ?, ?, ?)", 0, 0, 0, 0, 0); + execute("INSERT INTO %s (k, c1, c2, v1, v2) VALUES (?, ?, ?, ?, ?)", 0, 0, 1, 1, 1); + execute("INSERT INTO %s (k, c1, c2, v1, v2) VALUES (?, ?, ?, ?, ?)", 0, 0, 2, 2, 2); + execute("INSERT INTO %s (k, c1, c2, v1, v2) VALUES (?, ?, ?, ?, ?)", 0, 1, 0, 3, 3); + + execute("DELETE FROM %s WHERE k = 0 AND c1 = 0 AND c2 = 0"); + + assertRowCount(execute("SELECT * FROM %s"), 3); + } + + /** + * Check the semantic of CQL row existence (part of #4361), + * migrated from cql_tests.py:TestCQL.row_existence_test() + */ + @Test + public void testRowExistence() throws Throwable + { + createTable("CREATE TABLE %s (k int, c int, v1 int, v2 int, PRIMARY KEY (k, c))"); + + execute("INSERT INTO %s (k, c, v1, v2) VALUES (1, 1, 1, 1)"); + assertRows(execute("SELECT * FROM %s"), + row(1, 1, 1, 1)); + + assertInvalid("DELETE c FROM %s WHERE k = 1 AND c = 1"); + + execute("DELETE v2 FROM %s WHERE k = 1 AND c = 1"); + assertRows(execute("SELECT * FROM %s"), + row(1, 1, 1, null)); + + execute("DELETE v1 FROM %s WHERE k = 1 AND c = 1"); + assertRows(execute("SELECT * FROM %s"), + row(1, 1, null, null)); + + execute("DELETE FROM %s WHERE k = 1 AND c = 1"); + assertEmpty(execute("SELECT * FROM %s")); + + execute("INSERT INTO %s (k, c) VALUES (2, 2)"); + assertRows(execute("SELECT * FROM %s"), + row(2, 2, null, null)); + } + + /** + * Migrated from cql_tests.py:TestCQL.remove_range_slice_test() + */ + @Test + public void testRemoveRangeSlice() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, v int)"); + + for (int i = 0; i < 3; i++) + execute("INSERT INTO %s (k, v) VALUES (?, ?)", i, i); + + execute("DELETE FROM %s WHERE k = 1"); + assertRows(execute("SELECT * FROM %s"), + row(0, 0), + row(2, 2)); + } + + /** + * Test deletions + * migrated from cql_tests.py:TestCQL.no_range_ghost_test() + */ + @Test + public void testNoRangeGhost() throws Throwable + { + createTable("CREATE TABLE %s ( k int PRIMARY KEY, v int ) "); + + for (int k = 0; k < 5; k++) + execute("INSERT INTO %s (k, v) VALUES (?, 0)", k); + + Object[][] rows = getRows(execute("SELECT k FROM %s")); + + int[] ordered = sortIntRows(rows); + for (int k = 0; k < 5; k++) + assertEquals(k, ordered[k]); + + execute("DELETE FROM %s WHERE k=2"); + + rows = getRows(execute("SELECT k FROM %s")); + ordered = sortIntRows(rows); + + int idx = 0; + for (int k = 0; k < 5; k++) + if (k != 2) + assertEquals(k, ordered[idx++]); + + // Example from #3505 + createTable("CREATE TABLE %s ( KEY varchar PRIMARY KEY, password varchar, gender varchar, birth_year bigint)"); + execute("INSERT INTO %s (KEY, password) VALUES ('user1', 'ch@ngem3a')"); + execute("UPDATE %s SET gender = 'm', birth_year = 1980 WHERE KEY = 'user1'"); + + assertRows(execute("SELECT * FROM %s WHERE KEY='user1'"), + row("user1", 1980L, "m", "ch@ngem3a")); + + execute("TRUNCATE %s"); + assertEmpty(execute("SELECT * FROM %s")); + + assertEmpty(execute("SELECT * FROM %s WHERE KEY='user1'")); + } + + private int[] sortIntRows(Object[][] rows) + { + int[] ret = new int[rows.length]; + for (int i = 0; i < ret.length; i++) + ret[i] = rows[i][0] == null ? Integer.MIN_VALUE : (Integer) rows[i][0]; + Arrays.sort(ret); + return ret; + } + + /** + * Migrated from cql_tests.py:TestCQL.range_with_deletes_test() + */ + @Test + public void testRandomDeletions() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, v int,)"); + + int nb_keys = 30; + int nb_deletes = 5; + + List deletions = new ArrayList<>(nb_keys); + for (int i = 0; i < nb_keys; i++) + { + execute("INSERT INTO %s (k, v) VALUES (?, ?)", i, i); + deletions.add(i); + } + + Collections.shuffle(deletions); + + for (int i = 0; i < nb_deletes; i++) + execute("DELETE FROM %s WHERE k = ?", deletions.get(i)); + + assertRowCount(execute("SELECT * FROM %s LIMIT ?", (nb_keys / 2)), nb_keys / 2); + } + + /** + * Test for CASSANDRA-8558, deleted row still can be selected out + * migrated from cql_tests.py:TestCQL.bug_8558_test() + */ + @Test + public void testDeletedRowCannotBeSelected() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c text,primary key(a,b))"); + execute("INSERT INTO %s (a,b,c) VALUES(1,1,'1')"); + flush(); + + execute("DELETE FROM %s where a=1 and b=1"); + flush(); + + assertEmpty(execute("select * from %s where a=1 and b=1")); + } +} diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/InsertTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/InsertTest.java new file mode 100644 index 0000000000..6e9d2121f3 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/InsertTest.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.cql3.validation.operations; + +import org.junit.Test; + +import org.apache.cassandra.cql3.CQLTester; + +public class InsertTest extends CQLTester +{ + @Test + public void testInsertWithUnset() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, s text, i int)"); + + // insert using nulls + execute("INSERT INTO %s (k, s, i) VALUES (10, ?, ?)", "text", 10); + execute("INSERT INTO %s (k, s, i) VALUES (10, ?, ?)", null, null); + assertRows(execute("SELECT s, i FROM %s WHERE k = 10"), + row(null, null) // sending null deletes the data + ); + // insert using UNSET + execute("INSERT INTO %s (k, s, i) VALUES (11, ?, ?)", "text", 10); + execute("INSERT INTO %s (k, s, i) VALUES (11, ?, ?)", unset(), unset()); + assertRows(execute("SELECT s, i FROM %s WHERE k=11"), + row("text", 10) // unset columns does not delete the existing data + ); + + assertInvalidMessage("Invalid unset value for column k", "UPDATE %s SET i = 0 WHERE k = ?", unset()); + assertInvalidMessage("Invalid unset value for column k", "DELETE FROM %s WHERE k = ?", unset()); + assertInvalidMessage("Invalid unset value for argument in call to function blobasint", "SELECT * FROM %s WHERE k = blobAsInt(?)", unset()); + } + + @Test + public void testInsertTtlWithUnset() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, i int)"); + execute("INSERT INTO %s (k, i) VALUES (1, 1) USING TTL ?", unset()); // treat as 'unlimited' + assertRows(execute("SELECT ttl(i) FROM %s"), + row(new Object[]{ null }) + ); + } +} diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfCondition.java b/test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfCondition.java new file mode 100644 index 0000000000..662fbf4f01 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfCondition.java @@ -0,0 +1,861 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.cql3.validation.operations; + +import org.junit.Test; + +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.exceptions.InvalidRequestException; +import org.apache.cassandra.exceptions.SyntaxException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class InsertUpdateIfCondition extends CQLTester +{ + /** + * Migrated from cql_tests.py:TestCQL.cas_simple_test() + */ + @Test + public void testSimpleCas() throws Throwable + { + createTable("CREATE TABLE %s (tkn int, consumed boolean, PRIMARY KEY (tkn))"); + + for (int i = 0; i < 10; i++) + { + execute("INSERT INTO %s (tkn, consumed) VALUES (?, FALSE)", i); + + assertRows(execute("UPDATE %s SET consumed = TRUE WHERE tkn = ? IF consumed = FALSE", i), row(true)); + assertRows(execute("UPDATE %s SET consumed = TRUE WHERE tkn = ? IF consumed = FALSE", i), row(false, true)); + } + } + + /** + * Migrated from cql_tests.py:TestCQL.conditional_update_test() + */ + @Test + public void testConditionalUpdate() throws Throwable + { + createTable(" CREATE TABLE %s (k int PRIMARY KEY, v1 int, v2 text, v3 int)"); + + // Shouldn't apply + assertRows(execute("UPDATE %s SET v1 = 3, v2 = 'bar' WHERE k = 0 IF v1 = 4"), row(false)); + assertRows(execute("UPDATE %s SET v1 = 3, v2 = 'bar' WHERE k = 0 IF EXISTS"), row(false)); + + // Should apply + assertRows(execute("INSERT INTO %s (k, v1, v2) VALUES (0, 2, 'foo') IF NOT EXISTS"), row(true)); + + // Shouldn't apply + assertRows(execute("INSERT INTO %s (k, v1, v2) VALUES (0, 5, 'bar') IF NOT EXISTS"), row(false, 0, 2, "foo", null)); + assertRows(execute("SELECT * FROM %s"), row(0, 2, "foo", null)); + + // Shouldn't apply + assertRows(execute("UPDATE %s SET v1 = 3, v2 = 'bar' WHERE k = 0 IF v1 = 4"), row(false, 2)); + assertRows(execute("SELECT * FROM %s"), row(0, 2, "foo", null)); + + // Should apply (note: we want v2 before v1 in the statement order to exercise #5786) + assertRows(execute("UPDATE %s SET v2 = 'bar', v1 = 3 WHERE k = 0 IF v1 = 2"), row(true)); + assertRows(execute("UPDATE %s SET v2 = 'bar', v1 = 3 WHERE k = 0 IF EXISTS"), row(true)); + assertRows(execute("SELECT * FROM %s"), row(0, 3, "bar", null)); + + // Shouldn't apply, only one condition is ok + assertRows(execute("UPDATE %s SET v1 = 5, v2 = 'foobar' WHERE k = 0 IF v1 = 3 AND v2 = 'foo'"), row(false, 3, "bar")); + assertRows(execute("SELECT * FROM %s"), row(0, 3, "bar", null)); + + // Should apply + assertRows(execute("UPDATE %s SET v1 = 5, v2 = 'foobar' WHERE k = 0 IF v1 = 3 AND v2 = 'bar'"), row(true)); + assertRows(execute("SELECT * FROM %s"), row(0, 5, "foobar", null)); + + // Shouldn't apply + assertRows(execute("DELETE v2 FROM %s WHERE k = 0 IF v1 = 3"), row(false, 5)); + assertRows(execute("SELECT * FROM %s"), row(0, 5, "foobar", null)); + + // Shouldn't apply + assertRows(execute("DELETE v2 FROM %s WHERE k = 0 IF v1 = null"), row(false, 5)); + assertRows(execute("SELECT * FROM %s"), row(0, 5, "foobar", null)); + + // Should apply + assertRows(execute("DELETE v2 FROM %s WHERE k = 0 IF v1 = 5"), row(true)); + assertRows(execute("SELECT * FROM %s"), row(0, 5, null, null)); + + // Shouln't apply + assertRows(execute("DELETE v1 FROM %s WHERE k = 0 IF v3 = 4"), row(false, null)); + + // Should apply + assertRows(execute("DELETE v1 FROM %s WHERE k = 0 IF v3 = null"), row(true)); + assertRows(execute("SELECT * FROM %s"), row(0, null, null, null)); + + // Should apply + assertRows(execute("DELETE FROM %s WHERE k = 0 IF v1 = null"), row(true)); + assertEmpty(execute("SELECT * FROM %s")); + + // Shouldn't apply + assertRows(execute("UPDATE %s SET v1 = 3, v2 = 'bar' WHERE k = 0 IF EXISTS"), row(false)); + + // Should apply + assertRows(execute("DELETE FROM %s WHERE k = 0 IF v1 IN (null)"), row(true)); + } + + /** + * Migrated from cql_tests.py:TestCQL.non_eq_conditional_update_test() + */ + @Test + public void testNonEqConditionalUpdate() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, v1 int, v2 text, v3 int)"); + + // non-EQ conditions + execute("INSERT INTO %s (k, v1, v2) VALUES (0, 2, 'foo')"); + + assertRows(execute("UPDATE %s SET v2 = 'bar' WHERE k = 0 IF v1 < 3"), row(true)); + assertRows(execute("UPDATE %s SET v2 = 'bar' WHERE k = 0 IF v1 <= 3"), row(true)); + assertRows(execute("UPDATE %s SET v2 = 'bar' WHERE k = 0 IF v1 > 1"), row(true)); + assertRows(execute("UPDATE %s SET v2 = 'bar' WHERE k = 0 IF v1 >= 1"), row(true)); + assertRows(execute("UPDATE %s SET v2 = 'bar' WHERE k = 0 IF v1 != 1"), row(true)); + assertRows(execute("UPDATE %s SET v2 = 'bar' WHERE k = 0 IF v1 != 2"), row(false, 2)); + assertRows(execute("UPDATE %s SET v2 = 'bar' WHERE k = 0 IF v1 IN (0, 1, 2)"), row(true)); + assertRows(execute("UPDATE %s SET v2 = 'bar' WHERE k = 0 IF v1 IN (142, 276)"), row(false, 2)); + assertRows(execute("UPDATE %s SET v2 = 'bar' WHERE k = 0 IF v1 IN ()"), row(false, 2)); + } + + /** + * Migrated from cql_tests.py:TestCQL.conditional_delete_test() + */ + @Test + public void testConditionalDelete() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, v1 int,)"); + + assertRows(execute("DELETE FROM %s WHERE k=1 IF EXISTS"), row(false)); + + execute("INSERT INTO %s (k, v1) VALUES (1, 2)"); + assertRows(execute("DELETE FROM %s WHERE k=1 IF EXISTS"), row(true)); + assertEmpty(execute("SELECT * FROM %s WHERE k=1")); + assertRows(execute("DELETE FROM %s WHERE k=1 IF EXISTS"), row(false)); + + execute("UPDATE %s USING TTL 1 SET v1=2 WHERE k=1"); + Thread.sleep(1001); + assertRows(execute("DELETE FROM %s WHERE k=1 IF EXISTS"), row(false)); + assertEmpty(execute("SELECT * FROM %s WHERE k=1")); + + execute("INSERT INTO %s (k, v1) VALUES (2, 2) USING TTL 1"); + Thread.sleep(1001); + assertRows(execute("DELETE FROM %s WHERE k=2 IF EXISTS"), row(false)); + assertEmpty(execute("SELECT * FROM %s WHERE k=2")); + + execute("INSERT INTO %s (k, v1) VALUES (3, 2)"); + assertRows(execute("DELETE v1 FROM %s WHERE k=3 IF EXISTS"), row(true)); + assertRows(execute("SELECT * FROM %s WHERE k=3"), row(3, null)); + assertRows(execute("DELETE v1 FROM %s WHERE k=3 IF EXISTS"), row(true)); + assertRows(execute("DELETE FROM %s WHERE k=3 IF EXISTS"), row(true)); + + // static columns + createTable("CREATE TABLE %s (k text, s text static, i int, v text, PRIMARY KEY (k, i) )"); + + execute("INSERT INTO %s (k, s, i, v) VALUES ('k', 's', 0, 'v')"); + assertRows(execute("DELETE v FROM %s WHERE k='k' AND i=0 IF EXISTS"), row(true)); + assertRows(execute("DELETE FROM %s WHERE k='k' AND i=0 IF EXISTS"), row(true)); + assertRows(execute("DELETE v FROM %s WHERE k='k' AND i=0 IF EXISTS"), row(false)); + assertRows(execute("DELETE FROM %s WHERE k='k' AND i=0 IF EXISTS"), row(false)); + + // CASSANDRA-6430 + assertInvalid("DELETE FROM %s WHERE k = 'k' IF EXISTS"); + assertInvalid("DELETE FROM %s WHERE k = 'k' IF v = 'foo'"); + assertInvalid("DELETE FROM %s WHERE i = 0 IF EXISTS"); + assertInvalid("DELETE FROM %s WHERE k = 0 AND i > 0 IF EXISTS"); + assertInvalid("DELETE FROM %s WHERE k = 0 AND i > 0 IF v = 'foo'"); + } + + /** + * Migrated from cql_tests.py:TestCQL.static_columns_cas_test() + */ + @Test + public void testStaticColumnsCas() throws Throwable + { + createTable("CREATE TABLE %s (id int, k text, version int static, v text, PRIMARY KEY (id, k))"); + + // Test that INSERT IF NOT EXISTS concerns only the static column if no clustering nor regular columns + // is provided, but concerns the CQL3 row targetted by the clustering columns otherwise + execute("INSERT INTO %s (id, k, v) VALUES (1, 'foo', 'foo')"); + assertRows(execute("INSERT INTO %s (id, k, version) VALUES (1, 'foo', 1) IF NOT EXISTS"), row(false, 1, "foo", null, "foo")); + assertRows(execute("INSERT INTO %s (id, version) VALUES (1, 1) IF NOT EXISTS"), row(true)); + assertRows(execute("SELECT * FROM %s"), row(1, "foo", 1, "foo")); + execute("DELETE FROM %s WHERE id = 1"); + + execute("INSERT INTO %s(id, version) VALUES (0, 0)"); + + assertRows(execute("UPDATE %s SET v='foo', version=1 WHERE id=0 AND k='k1' IF version = 0"), row(true)); + assertRows(execute("SELECT * FROM %s"), row(0, "k1", 1, "foo")); + + assertRows(execute("UPDATE %s SET v='bar', version=1 WHERE id=0 AND k='k2' IF version = 0"), row(false, 1)); + assertRows(execute("SELECT * FROM %s"), row(0, "k1", 1, "foo")); + + assertRows(execute("UPDATE %s SET v='bar', version=2 WHERE id=0 AND k='k2' IF version = 1"), row(true)); + assertRows(execute("SELECT * FROM %s"), row(0, "k1", 2, "foo"), row(0, "k2", 2, "bar")); + + // Testing batches + assertRows(execute("BEGIN BATCH " + + "UPDATE %1$s SET v='foobar' WHERE id=0 AND k='k1'; " + + "UPDATE %1$s SET v='barfoo' WHERE id=0 AND k='k2'; " + + "UPDATE %1$s SET version=3 WHERE id=0 IF version=1; " + + "APPLY BATCH "), + row(false, 0, null, 2)); + + assertRows(execute("BEGIN BATCH " + + "UPDATE %1$s SET v = 'foobar' WHERE id = 0 AND k = 'k1'; " + + "UPDATE %1$s SET v = 'barfoo' WHERE id = 0 AND k = 'k2'; " + + "UPDATE %1$s SET version = 3 WHERE id = 0 IF version = 2; " + + "APPLY BATCH "), + row(true)); + + assertRows(execute("SELECT * FROM %s"), + row(0, "k1", 3, "foobar"), + row(0, "k2", 3, "barfoo")); + + assertRows(execute("BEGIN BATCH " + + "UPDATE %1$s SET version = 4 WHERE id = 0 IF version = 3; " + + "UPDATE %1$s SET v='row1' WHERE id=0 AND k='k1' IF v='foo'; " + + "UPDATE %1$s SET v='row2' WHERE id=0 AND k='k2' IF v='bar'; " + + "APPLY BATCH "), + row(false, 0, "k1", 3, "foobar"), + row(false, 0, "k2", 3, "barfoo")); + + assertRows(execute("BEGIN BATCH " + + "UPDATE %1$s SET version = 4 WHERE id = 0 IF version = 3; " + + "UPDATE %1$s SET v='row1' WHERE id = 0 AND k='k1' IF v='foobar'; " + + "UPDATE %1$s SET v='row2' WHERE id = 0 AND k='k2' IF v='barfoo'; " + + "APPLY BATCH "), + row(true)); + + assertRows(execute("SELECT * FROM %s"), + row(0, "k1", 4, "row1"), + row(0, "k2", 4, "row2")); + + assertInvalid("BEGIN BATCH " + + "UPDATE %1$s SET version=5 WHERE id=0 IF version=4; " + + "UPDATE %1$s SET v='row1' WHERE id=0 AND k='k1'; " + + "UPDATE %1$s SET v='row2' WHERE id=1 AND k='k2'; " + + "APPLY BATCH "); + + assertRows(execute("BEGIN BATCH " + + "INSERT INTO %1$s (id, k, v) VALUES (1, 'k1', 'val1') IF NOT EXISTS; " + + "INSERT INTO %1$s (id, k, v) VALUES (1, 'k2', 'val2') IF NOT EXISTS; " + + "APPLY BATCH "), + row(true)); + + assertRows(execute("SELECT * FROM %s WHERE id=1"), + row(1, "k1", null, "val1"), + row(1, "k2", null, "val2")); + + assertRows(execute("INSERT INTO %s (id, k, v) VALUES (1, 'k2', 'val2') IF NOT EXISTS"), row(false, 1, "k2", null, "val2")); + + assertRows(execute("BEGIN BATCH " + + "INSERT INTO %1$s (id, k, v) VALUES (1, 'k2', 'val2') IF NOT EXISTS; " + + "INSERT INTO %1$s (id, k, v) VALUES (1, 'k3', 'val3') IF NOT EXISTS; " + + "APPLY BATCH"), + row(false, 1, "k2", null, "val2")); + + assertRows(execute("BEGIN BATCH " + + "UPDATE %1$s SET v = 'newVal' WHERE id = 1 AND k = 'k2' IF v = 'val0'; " + + "INSERT INTO %1$s (id, k, v) VALUES (1, 'k3', 'val3') IF NOT EXISTS; " + + "APPLY BATCH"), + row(false, 1, "k2", null, "val2")); + + assertRows(execute("SELECT * FROM %s WHERE id=1"), + row(1, "k1", null, "val1"), + row(1, "k2", null, "val2")); + + assertRows(execute("BEGIN BATCH " + + "UPDATE %1$s SET v = 'newVal' WHERE id = 1 AND k = 'k2' IF v = 'val2'; " + + "INSERT INTO %1$s (id, k, v, version) VALUES(1, 'k3', 'val3', 1) IF NOT EXISTS; " + + "APPLY BATCH"), + row(true)); + + assertRows(execute("SELECT * FROM %s WHERE id=1"), + row(1, "k1", 1, "val1"), + row(1, "k2", 1, "newVal"), + row(1, "k3", 1, "val3")); + + assertRows(execute("BEGIN BATCH " + + "UPDATE %1$s SET v = 'newVal1' WHERE id = 1 AND k = 'k2' IF v = 'val2'; " + + "UPDATE %1$s SET v = 'newVal2' WHERE id = 1 AND k = 'k2' IF v = 'val3'; " + + "APPLY BATCH"), + row(false, 1, "k2", "newVal")); + } + + /** + * Migrated from cql_tests.py:TestCQL.bug_6069_test() + */ + @Test + public void testInsertSetIfNotExists() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, s set)"); + + assertRows(execute("INSERT INTO %s (k, s) VALUES (0, {1, 2, 3}) IF NOT EXISTS"), + row(true)); + assertRows(execute("SELECT * FROM %s "), row(0, set(1, 2, 3))); + } + + /** + * Migrated from cql_tests.py:TestCQL.cas_and_ttl_test() + */ + @Test + public void testCasAndTTL() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, v int, lock boolean)"); + + execute("INSERT INTO %s (k, v, lock) VALUES (0, 0, false)"); + execute("UPDATE %s USING TTL 1 SET lock=true WHERE k=0"); + + Thread.sleep(1001); + assertRows(execute("UPDATE %s SET v = 1 WHERE k = 0 IF lock = null"), + row(true)); + } + + /** + * Test for CAS with compact storage table, and #6813 in particular, + * migrated from cql_tests.py:TestCQL.cas_and_compact_test() + */ + @Test + public void testCompactStorage() throws Throwable + { + createTable("CREATE TABLE %s (partition text, key text, owner text, PRIMARY KEY (partition, key) ) WITH COMPACT STORAGE"); + + execute("INSERT INTO %s (partition, key, owner) VALUES ('a', 'b', null)"); + assertRows(execute("UPDATE %s SET owner='z' WHERE partition='a' AND key='b' IF owner=null"), row(true)); + + assertRows(execute("UPDATE %s SET owner='b' WHERE partition='a' AND key='b' IF owner='a'"), row(false, "z")); + assertRows(execute("UPDATE %s SET owner='b' WHERE partition='a' AND key='b' IF owner='z'"), row(true)); + + assertRows(execute("INSERT INTO %s (partition, key, owner) VALUES ('a', 'c', 'x') IF NOT EXISTS"), row(true)); + } + + /** + * Migrated from cql_tests.py:TestCQL.whole_list_conditional_test() + */ + @Test + public void testWholeList() throws Throwable + { + for (boolean frozen : new boolean[] {false, true}) + { + createTable(String.format("CREATE TABLE %%s (k int PRIMARY KEY, l %s)", + frozen + ? "frozen>" + : "list")); + + execute("INSERT INTO %s(k, l) VALUES (0, ['foo', 'bar', 'foobar'])"); + + check_applies_list("l = ['foo', 'bar', 'foobar']"); + check_applies_list("l != ['baz']"); + check_applies_list("l > ['a']"); + check_applies_list("l >= ['a']"); + check_applies_list("l < ['z']"); + check_applies_list("l <= ['z']"); + check_applies_list("l IN (null, ['foo', 'bar', 'foobar'], ['a'])"); + + // multiple conditions + check_applies_list("l > ['aaa', 'bbb'] AND l > ['aaa']"); + check_applies_list("l != null AND l IN (['foo', 'bar', 'foobar'])"); + + // should not apply + check_does_not_apply_list("l = ['baz']"); + check_does_not_apply_list("l != ['foo', 'bar', 'foobar']"); + check_does_not_apply_list("l > ['z']"); + check_does_not_apply_list("l >= ['z']"); + check_does_not_apply_list("l < ['a']"); + check_does_not_apply_list("l <= ['a']"); + check_does_not_apply_list("l IN (['a'], null)"); + check_does_not_apply_list("l IN ()"); + + // multiple conditions + check_does_not_apply_list("l IN () AND l IN (['foo', 'bar', 'foobar'])"); + check_does_not_apply_list("l > ['zzz'] AND l < ['zzz']"); + + check_invalid_list("l = [null]", InvalidRequestException.class); + check_invalid_list("l < null", InvalidRequestException.class); + check_invalid_list("l <= null", InvalidRequestException.class); + check_invalid_list("l > null", InvalidRequestException.class); + check_invalid_list("l >= null", InvalidRequestException.class); + check_invalid_list("l IN null", SyntaxException.class); + check_invalid_list("l IN 367", SyntaxException.class); + check_invalid_list("l CONTAINS KEY 123", SyntaxException.class); + + // not supported yet + check_invalid_list("m CONTAINS 'bar'", SyntaxException.class); + } + } + + void check_applies_list(String condition) throws Throwable + { + assertRows(execute("UPDATE %s SET l = ['foo', 'bar', 'foobar'] WHERE k=0 IF " + condition), row(true)); + assertRows(execute("SELECT * FROM %s"), row(0, list("foo", "bar", "foobar"))); + } + + void check_does_not_apply_list(String condition) throws Throwable + { + assertRows(execute("UPDATE %s SET l = ['foo', 'bar', 'foobar'] WHERE k=0 IF " + condition), + row(false, list("foo", "bar", "foobar"))); + assertRows(execute("SELECT * FROM %s"), row(0, list("foo", "bar", "foobar"))); + } + + void check_invalid_list(String condition, Class expected) throws Throwable + { + assertInvalidThrow(expected, "UPDATE %s SET l = ['foo', 'bar', 'foobar'] WHERE k=0 IF " + condition); + assertRows(execute("SELECT * FROM %s"), row(0, list("foo", "bar", "foobar"))); + } + + /** + * Migrated from cql_tests.py:TestCQL.list_item_conditional_test() + */ + @Test + public void testListItem() throws Throwable + { + for (boolean frozen : new boolean[]{ false, true }) + { + createTable(String.format("CREATE TABLE %%s (k int PRIMARY KEY, l %s)", + frozen + ? "frozen>" + : "list")); + + execute("INSERT INTO %s(k, l) VALUES (0, ['foo', 'bar', 'foobar'])"); + + assertInvalid("DELETE FROM %s WHERE k=0 IF l[null] = 'foobar'"); + assertInvalid("DELETE FROM %s WHERE k=0 IF l[-2] = 'foobar'"); + + assertRows(execute("DELETE FROM %s WHERE k=0 IF l[1] = null"), row(false, list("foo", "bar", "foobar"))); + assertRows(execute("DELETE FROM %s WHERE k=0 IF l[1] = 'foobar'"), row(false, list("foo", "bar", "foobar"))); + assertRows(execute("SELECT * FROM %s"), row(0, list("foo", "bar", "foobar"))); + + assertRows(execute("DELETE FROM %s WHERE k=0 IF l[1] = 'bar'"), row(true)); + assertEmpty(execute("SELECT * FROM %s")); + } + } + + /** + * Test expanded functionality from CASSANDRA-6839, + * migrated from cql_tests.py:TestCQL.expanded_list_item_conditional_test() + */ + @Test + public void testExpandedListItem() throws Throwable + { + for (boolean frozen : new boolean[] {false, true}) + { + createTable(String.format("CREATE TABLE %%s (k int PRIMARY KEY, l %s)", + frozen + ? "frozen>" + : "list")); + + execute("INSERT INTO %s (k, l) VALUES (0, ['foo', 'bar', 'foobar'])"); + + check_applies_list("l[1] < 'zzz'"); + check_applies_list("l[1] <= 'bar'"); + check_applies_list("l[1] > 'aaa'"); + check_applies_list("l[1] >= 'bar'"); + check_applies_list("l[1] != 'xxx'"); + check_applies_list("l[1] != null"); + check_applies_list("l[1] IN (null, 'xxx', 'bar')"); + check_applies_list("l[1] > 'aaa' AND l[1] < 'zzz'"); + + // check beyond end of list + check_applies_list("l[3] = null"); + check_applies_list("l[3] IN (null, 'xxx', 'bar')"); + + check_does_not_apply_list("l[1] < 'aaa'"); + check_does_not_apply_list("l[1] <= 'aaa'"); + check_does_not_apply_list("l[1] > 'zzz'"); + check_does_not_apply_list("l[1] >= 'zzz'"); + check_does_not_apply_list("l[1] != 'bar'"); + check_does_not_apply_list("l[1] IN (null, 'xxx')"); + check_does_not_apply_list("l[1] IN ()"); + check_does_not_apply_list("l[1] != null AND l[1] IN ()"); + + // check beyond end of list + check_does_not_apply_list("l[3] != null"); + check_does_not_apply_list("l[3] = 'xxx'"); + + check_invalid_list("l[1] < null", InvalidRequestException.class); + check_invalid_list("l[1] <= null", InvalidRequestException.class); + check_invalid_list("l[1] > null", InvalidRequestException.class); + check_invalid_list("l[1] >= null", InvalidRequestException.class); + check_invalid_list("l[1] IN null", SyntaxException.class); + check_invalid_list("l[1] IN 367", SyntaxException.class); + check_invalid_list("l[1] IN (1, 2, 3)", InvalidRequestException.class); + check_invalid_list("l[1] CONTAINS 367", SyntaxException.class); + check_invalid_list("l[1] CONTAINS KEY 367", SyntaxException.class); + check_invalid_list("l[null] = null", InvalidRequestException.class); + } + } + + /** + * Migrated from cql_tests.py:TestCQL.whole_set_conditional_test() + */ + @Test + public void testWholeSet() throws Throwable + { + for (boolean frozen : new boolean[] {false, true}) + { + createTable(String.format("CREATE TABLE %%s (k int PRIMARY KEY, s %s)", + frozen + ? "frozen>" + : "set")); + + execute("INSERT INTO %s (k, s) VALUES (0, {'bar', 'foo'})"); + + check_applies_set("s = {'bar', 'foo'}"); + check_applies_set("s = {'foo', 'bar'}"); + check_applies_set("s != {'baz'}"); + check_applies_set("s > {'a'}"); + check_applies_set("s >= {'a'}"); + check_applies_set("s < {'z'}"); + check_applies_set("s <= {'z'}"); + check_applies_set("s IN (null, {'bar', 'foo'}, {'a'})"); + + // multiple conditions + check_applies_set("s > {'a'} AND s < {'z'}"); + check_applies_set("s IN (null, {'bar', 'foo'}, {'a'}) AND s IN ({'a'}, {'bar', 'foo'}, null)"); + + // should not apply + check_does_not_apply_set("s = {'baz'}"); + check_does_not_apply_set("s != {'bar', 'foo'}"); + check_does_not_apply_set("s > {'z'}"); + check_does_not_apply_set("s >= {'z'}"); + check_does_not_apply_set("s < {'a'}"); + check_does_not_apply_set("s <= {'a'}"); + check_does_not_apply_set("s IN ({'a'}, null)"); + check_does_not_apply_set("s IN ()"); + check_does_not_apply_set("s != null AND s IN ()"); + + check_invalid_set("s = {null}", InvalidRequestException.class); + check_invalid_set("s < null", InvalidRequestException.class); + check_invalid_set("s <= null", InvalidRequestException.class); + check_invalid_set("s > null", InvalidRequestException.class); + check_invalid_set("s >= null", InvalidRequestException.class); + check_invalid_set("s IN null", SyntaxException.class); + check_invalid_set("s IN 367", SyntaxException.class); + check_invalid_set("s CONTAINS KEY 123", SyntaxException.class); + + // element access is not allow for sets + check_invalid_set("s['foo'] = 'foobar'", InvalidRequestException.class); + + // not supported yet + check_invalid_set("m CONTAINS 'bar'", SyntaxException.class); + } + } + + void check_applies_set(String condition) throws Throwable + { + assertRows(execute("UPDATE %s SET s = {'bar', 'foo'} WHERE k=0 IF " + condition), row(true)); + assertRows(execute("SELECT * FROM %s"), row(0, set("bar", "foo"))); + } + + void check_does_not_apply_set(String condition) throws Throwable + { + assertRows(execute("UPDATE %s SET s = {'bar', 'foo'} WHERE k=0 IF " + condition), row(false, set("bar", "foo"))); + assertRows(execute("SELECT * FROM %s"), row(0, set("bar", "foo"))); + } + + void check_invalid_set(String condition, Class expected) throws Throwable + { + assertInvalidThrow(expected, "UPDATE %s SET s = {'bar', 'foo'} WHERE k=0 IF " + condition); + assertRows(execute("SELECT * FROM %s"), row(0, set("bar", "foo"))); + } + + /** + * Migrated from cql_tests.py:TestCQL.whole_map_conditional_test() + */ + @Test + public void testWholeMap() throws Throwable + { + for (boolean frozen : new boolean[] {false, true}) + { + createTable(String.format("CREATE TABLE %%s (k int PRIMARY KEY, m %s)", + frozen + ? "frozen>" + : "map")); + + execute("INSERT INTO %s (k, m) VALUES (0, {'foo' : 'bar'})"); + + check_applies_map("m = {'foo': 'bar'}"); + check_applies_map("m > {'a': 'a'}"); + check_applies_map("m >= {'a': 'a'}"); + check_applies_map("m < {'z': 'z'}"); + check_applies_map("m <= {'z': 'z'}"); + check_applies_map("m != {'a': 'a'}"); + check_applies_map("m IN (null, {'a': 'a'}, {'foo': 'bar'})"); + + // multiple conditions + check_applies_map("m > {'a': 'a'} AND m < {'z': 'z'}"); + check_applies_map("m != null AND m IN (null, {'a': 'a'}, {'foo': 'bar'})"); + + // should not apply + check_does_not_apply_map("m = {'a': 'a'}"); + check_does_not_apply_map("m > {'z': 'z'}"); + check_does_not_apply_map("m >= {'z': 'z'}"); + check_does_not_apply_map("m < {'a': 'a'}"); + check_does_not_apply_map("m <= {'a': 'a'}"); + check_does_not_apply_map("m != {'foo': 'bar'}"); + check_does_not_apply_map("m IN ({'a': 'a'}, null)"); + check_does_not_apply_map("m IN ()"); + check_does_not_apply_map("m = null AND m != null"); + + check_invalid_map("m = {null: null}", InvalidRequestException.class); + check_invalid_map("m = {'a': null}", InvalidRequestException.class); + check_invalid_map("m = {null: 'a'}", InvalidRequestException.class); + check_invalid_map("m < null", InvalidRequestException.class); + check_invalid_map("m IN null", SyntaxException.class); + + // not supported yet + check_invalid_map("m CONTAINS 'bar'", SyntaxException.class); + check_invalid_map("m CONTAINS KEY 'foo'", SyntaxException.class); + check_invalid_map("m CONTAINS null", SyntaxException.class); + check_invalid_map("m CONTAINS KEY null", SyntaxException.class); + } + } + + /** + * Migrated from cql_tests.py:TestCQL.map_item_conditional_test() + */ + @Test + public void testMapItem() throws Throwable + { + for (boolean frozen : new boolean[]{ false, true }) + { + createTable(String.format("CREATE TABLE %%s (k int PRIMARY KEY, m %s)", + frozen + ? "frozen>" + : "map")); + + execute("INSERT INTO %s (k, m) VALUES (0, {'foo' : 'bar'})"); + assertInvalid("DELETE FROM %s WHERE k=0 IF m[null] = 'foo'"); + assertRows(execute("DELETE FROM %s WHERE k=0 IF m['foo'] = 'foo'"), row(false, map("foo", "bar"))); + assertRows(execute("DELETE FROM %s WHERE k=0 IF m['foo'] = null"), row(false, map("foo", "bar"))); + assertRows(execute("SELECT * FROM %s"), row(0, map("foo", "bar"))); + + assertRows(execute("DELETE FROM %s WHERE k=0 IF m['foo'] = 'bar'"), row(true)); + assertEmpty(execute("SELECT * FROM %s")); + + execute("INSERT INTO %s(k, m) VALUES (1, null)"); + if (frozen) + assertInvalid("UPDATE %s set m['foo'] = 'bar', m['bar'] = 'foo' WHERE k = 1 IF m['foo'] IN ('blah', null)"); + else + assertRows(execute("UPDATE %s set m['foo'] = 'bar', m['bar'] = 'foo' WHERE k = 1 IF m['foo'] IN ('blah', null)"), row(true)); + } + } + + /** + * Test expanded functionality from CASSANDRA-6839, + * migrated from cql_tests.py:TestCQL.expanded_map_item_conditional_test() + */ + @Test + public void testExpandedMapItem() throws Throwable + { + for (boolean frozen : new boolean[]{ false, true }) + { + createTable(String.format("CREATE TABLE %%s (k int PRIMARY KEY, m %s)", + frozen + ? "frozen>" + : "map")); + + execute("INSERT INTO %s (k, m) VALUES (0, {'foo' : 'bar'})"); + + check_applies_map("m['xxx'] = null"); + check_applies_map("m['foo'] < 'zzz'"); + check_applies_map("m['foo'] <= 'bar'"); + check_applies_map("m['foo'] > 'aaa'"); + check_applies_map("m['foo'] >= 'bar'"); + check_applies_map("m['foo'] != 'xxx'"); + check_applies_map("m['foo'] != null"); + check_applies_map("m['foo'] IN (null, 'xxx', 'bar')"); + check_applies_map("m['xxx'] IN (null, 'xxx', 'bar')"); // m['xxx'] is not set + + // multiple conditions + check_applies_map("m['foo'] < 'zzz' AND m['foo'] > 'aaa'"); + + check_does_not_apply_map("m['foo'] < 'aaa'"); + check_does_not_apply_map("m['foo'] <= 'aaa'"); + check_does_not_apply_map("m['foo'] > 'zzz'"); + check_does_not_apply_map("m['foo'] >= 'zzz'"); + check_does_not_apply_map("m['foo'] != 'bar'"); + check_does_not_apply_map("m['xxx'] != null"); // m['xxx'] is not set + check_does_not_apply_map("m['foo'] IN (null, 'xxx')"); + check_does_not_apply_map("m['foo'] IN ()"); + check_does_not_apply_map("m['foo'] != null AND m['foo'] = null"); + + check_invalid_map("m['foo'] < null", InvalidRequestException.class); + check_invalid_map("m['foo'] <= null", InvalidRequestException.class); + check_invalid_map("m['foo'] > null", InvalidRequestException.class); + check_invalid_map("m['foo'] >= null", InvalidRequestException.class); + check_invalid_map("m['foo'] IN null", SyntaxException.class); + check_invalid_map("m['foo'] IN 367", SyntaxException.class); + check_invalid_map("m['foo'] IN (1, 2, 3)", InvalidRequestException.class); + check_invalid_map("m['foo'] CONTAINS 367", SyntaxException.class); + check_invalid_map("m['foo'] CONTAINS KEY 367", SyntaxException.class); + check_invalid_map("m[null] = null", InvalidRequestException.class); + } + } + + void check_applies_map(String condition) throws Throwable + { + assertRows(execute("UPDATE %s SET m = {'foo': 'bar'} WHERE k=0 IF " + condition), row(true)); + assertRows(execute("SELECT * FROM %s"), row(0, map("foo", "bar"))); + } + + void check_does_not_apply_map(String condition) throws Throwable + { + assertRows(execute("UPDATE %s SET m = {'foo': 'bar'} WHERE k=0 IF " + condition), row(false, map("foo", "bar"))); + assertRows(execute("SELECT * FROM %s"), row(0, map("foo", "bar"))); + } + + void check_invalid_map(String condition, Class expected) throws Throwable + { + assertInvalidThrow(expected, "UPDATE %s SET m = {'foo': 'bar'} WHERE k=0 IF " + condition); + assertRows(execute("SELECT * FROM %s"), row(0, map("foo", "bar"))); + } + + /** + * Test for 7499, + * migrated from cql_tests.py:TestCQL.cas_and_list_index_test() + */ + @Test + public void testCasAndListIndex() throws Throwable + { + createTable("CREATE TABLE %s ( k int PRIMARY KEY, v text, l list)"); + + execute("INSERT INTO %s (k, v, l) VALUES(0, 'foobar', ['foi', 'bar'])"); + + assertRows(execute("UPDATE %s SET l[0] = 'foo' WHERE k = 0 IF v = 'barfoo'"), row(false, "foobar")); + assertRows(execute("UPDATE %s SET l[0] = 'foo' WHERE k = 0 IF v = 'foobar'"), row(true)); + + assertRows(execute("SELECT * FROM %s"), row(0, list("foo", "bar"), "foobar")); + + } + + /** + * Migrated from cql_tests.py:TestCQL.conditional_ddl_keyspace_test() + */ + @Test + public void testDropCreateKeyspaceIfNotExists() throws Throwable + { + String keyspace = KEYSPACE_PER_TEST; + + dropPerTestKeyspace(); + + // try dropping when doesn't exist + dropPerTestKeyspace(); + + // create and confirm + schemaChange("CREATE KEYSPACE IF NOT EXISTS " + keyspace + " WITH replication = { 'class':'SimpleStrategy', 'replication_factor':1} and durable_writes = true "); + assertRows(execute("select durable_writes from system.schema_keyspaces where keyspace_name = ?", keyspace), row(true)); + + // unsuccessful create since it's already there, confirm settings don't change + schemaChange("CREATE KEYSPACE IF NOT EXISTS " + keyspace + " WITH replication = {'class':'SimpleStrategy', 'replication_factor':1} and durable_writes = false "); + + assertRows(execute("select durable_writes from system.schema_keyspaces where keyspace_name = ?", keyspace), row(true)); + + // drop and confirm + schemaChange("DROP KEYSPACE IF EXISTS " + keyspace); + + assertEmpty(execute("select * from system.schema_keyspaces where keyspace_name = ?", keyspace)); + } + + + /** + * Migrated from cql_tests.py:TestCQL.conditional_ddl_table_test() + */ + @Test + public void testDropCreateTableIfNotExists() throws Throwable + { + String tableName = createTableName(); + String fullTableName = KEYSPACE + "." + tableName; + + // try dropping when doesn't exist + schemaChange("DROP TABLE IF EXISTS " + fullTableName); + + // create and confirm + schemaChange("CREATE TABLE IF NOT EXISTS " + fullTableName + " (id text PRIMARY KEY, value1 blob) with comment = 'foo'"); + + assertRows(execute("select comment from system.schema_columnfamilies where keyspace_name = ? and columnfamily_name = ?", KEYSPACE, tableName), + row("foo")); + + // unsuccessful create since it's already there, confirm settings don't change + schemaChange("CREATE TABLE IF NOT EXISTS " + fullTableName + " (id text PRIMARY KEY, value2 blob)with comment = 'bar'"); + + assertRows(execute("select comment from system.schema_columnfamilies where keyspace_name = ? and columnfamily_name = ?", KEYSPACE, tableName), + row("foo")); + + // drop and confirm + schemaChange("DROP TABLE IF EXISTS " + fullTableName); + + assertEmpty(execute("select * from system.schema_columnfamilies where keyspace_name = ? and columnfamily_name = ?", KEYSPACE, tableName)); + } + + /** + * Migrated from cql_tests.py:TestCQL.conditional_ddl_index_test() + */ + @Test + public void testDropCreateIndexIfNotExists() throws Throwable + { + String tableName = createTable("CREATE TABLE %s (id text PRIMARY KEY, value1 blob, value2 blob)with comment = 'foo'"); + + execute("use " + KEYSPACE); + + // try dropping when doesn't exist + schemaChange("DROP INDEX IF EXISTS myindex"); + + // create and confirm + createIndex("CREATE INDEX IF NOT EXISTS myindex ON %s (value1)"); + + assertTrue(waitForIndex(KEYSPACE, tableName, "myindex")); + + // unsuccessful create since it's already there + execute("CREATE INDEX IF NOT EXISTS myindex ON %s (value1)"); + + // drop and confirm + execute("DROP INDEX IF EXISTS myindex"); + + Object[][] rows = getRows(execute("select index_name from system.\"IndexInfo\" where table_name = ?", tableName)); + assertEquals(0, rows.length); + } + + /** + * Migrated from cql_tests.py:TestCQL.conditional_ddl_type_test() + */ + @Test + public void testDropCreateTypeIfNotExists() throws Throwable + { + execute("use " + KEYSPACE); + + // try dropping when doesn 't exist + execute("DROP TYPE IF EXISTS mytype"); + + // create and confirm + execute("CREATE TYPE IF NOT EXISTS mytype (somefield int)"); + assertRows(execute("SELECT type_name from system.schema_usertypes where keyspace_name = ? and type_name = ?", KEYSPACE, "mytype"), + row("mytype")); + + // unsuccessful create since it 's already there + // TODO: confirm this create attempt doesn't alter type field from int to blob + execute("CREATE TYPE IF NOT EXISTS mytype (somefield blob)"); + + // drop and confirm + execute("DROP TYPE IF EXISTS mytype"); + assertEmpty(execute("SELECT type_name from system.schema_usertypes where keyspace_name = ? and type_name = ?", KEYSPACE, "mytype")); + } +} diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectLimitTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectLimitTest.java new file mode 100644 index 0000000000..275ff04b10 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectLimitTest.java @@ -0,0 +1,112 @@ +package org.apache.cassandra.cql3.validation.operations; + +import org.junit.BeforeClass; +import org.junit.Test; + +import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.dht.ByteOrderedPartitioner; +import org.apache.cassandra.exceptions.InvalidRequestException; + +public class SelectLimitTest extends CQLTester +{ + @BeforeClass + public static void setUp() + { + DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance); + } + + /** + * Test limit across a partition range, requires byte ordered partitioner, + * migrated from cql_tests.py:TestCQL.limit_range_test() + */ + @Test + public void testPartitionRange() throws Throwable + { + createTable("CREATE TABLE %s (userid int, url text, time bigint, PRIMARY KEY (userid, url)) WITH COMPACT STORAGE"); + + for (int i = 0; i < 100; i++) + for (String tld : new String[] { "com", "org", "net" }) + execute("INSERT INTO %s (userid, url, time) VALUES (?, ?, ?)", i, String.format("http://foo.%s", tld), 42L); + + assertRows(execute("SELECT * FROM %s WHERE token(userid) >= token(2) LIMIT 1"), + row(2, "http://foo.com", 42L)); + + assertRows(execute("SELECT * FROM %s WHERE token(userid) > token(2) LIMIT 1"), + row(3, "http://foo.com", 42L)); + } + + /** + * Test limit across a column range, + * migrated from cql_tests.py:TestCQL.limit_multiget_test() + */ + @Test + public void testColumnRange() throws Throwable + { + createTable("CREATE TABLE %s (userid int, url text, time bigint, PRIMARY KEY (userid, url)) WITH COMPACT STORAGE"); + + for (int i = 0; i < 100; i++) + for (String tld : new String[] { "com", "org", "net" }) + execute("INSERT INTO %s (userid, url, time) VALUES (?, ?, ?)", i, String.format("http://foo.%s", tld), 42L); + + // Check that we do limit the output to 1 *and* that we respect query + // order of keys (even though 48 is after 2) + assertRows(execute("SELECT * FROM %s WHERE userid IN (48, 2) LIMIT 1"), + row(2, "http://foo.com", 42L)); + + } + + /** + * Test limit queries on a sparse table, + * migrated from cql_tests.py:TestCQL.limit_sparse_test() + */ + @Test + public void testSparseTable() throws Throwable + { + createTable("CREATE TABLE %s (userid int, url text, day int, month text, year int, PRIMARY KEY (userid, url))"); + + for (int i = 0; i < 100; i++) + for (String tld : new String[] { "com", "org", "net" }) + execute("INSERT INTO %s (userid, url, day, month, year) VALUES (?, ?, 1, 'jan', 2012)", i, String.format("http://foo.%s", tld)); + + assertRowCount(execute("SELECT * FROM %s LIMIT 4"), 4); + + } + + /** + * Check for #7052 bug, + * migrated from cql_tests.py:TestCQL.limit_compact_table() + */ + @Test + public void testLimitInCompactTable() throws Throwable + { + createTable("CREATE TABLE %s (k int, v int, PRIMARY KEY (k, v) ) WITH COMPACT STORAGE "); + + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + execute("INSERT INTO %s(k, v) VALUES (?, ?)", i, j); + + assertRows(execute("SELECT v FROM %s WHERE k=0 AND v > 0 AND v <= 4 LIMIT 2"), + row(1), + row(2)); + assertRows(execute("SELECT v FROM %s WHERE k=0 AND v > -1 AND v <= 4 LIMIT 2"), + row(0), + row(1)); + assertRows(execute("SELECT * FROM %s WHERE k IN (0, 1, 2) AND v > 0 AND v <= 4 LIMIT 2"), + row(0, 1), + row(0, 2)); + assertRows(execute("SELECT * FROM %s WHERE k IN (0, 1, 2) AND v > -1 AND v <= 4 LIMIT 2"), + row(0, 0), + row(0, 1)); + assertRows(execute("SELECT * FROM %s WHERE k IN (0, 1, 2) AND v > 0 AND v <= 4 LIMIT 6"), + row(0, 1), + row(0, 2), + row(0, 3), + row(1, 1), + row(1, 2), + row(1, 3)); + + // strict bound (v > 1) over a range of partitions is not supported for compact storage if limit is provided + assertInvalidThrow(InvalidRequestException.class, "SELECT * FROM %s WHERE v > 1 AND v <= 3 LIMIT 6 ALLOW FILTERING"); + } +} diff --git a/test/unit/org/apache/cassandra/cql3/MultiColumnRelationTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java similarity index 97% rename from test/unit/org/apache/cassandra/cql3/MultiColumnRelationTest.java rename to test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java index b380b1e5c2..552e39eb7a 100644 --- a/test/unit/org/apache/cassandra/cql3/MultiColumnRelationTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java @@ -15,11 +15,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.operations; import org.junit.Test; -public class MultiColumnRelationTest extends CQLTester +import org.apache.cassandra.cql3.CQLTester; + +import static org.junit.Assert.assertEquals; + +public class SelectMultiColumnRelationTest extends CQLTester { @Test public void testSingleClusteringInvalidQueries() throws Throwable @@ -933,4 +937,26 @@ public class MultiColumnRelationTest extends CQLTester assertInvalidMessage("Invalid unset value for in(i,j)", "SELECT * from %s WHERE (i, j) IN ? ALLOW FILTERING", unset()); } -} + + /** + * Check select on tuple relations, see CASSANDRA-8613 + * migrated from cql_tests.py:TestCQL.simple_tuple_query_test() + */ + @Test + public void testSimpleTupleQuery() throws Throwable + { + createTable("create table %s (a int, b int, c int, d int , e int, PRIMARY KEY (a, b, c, d, e))"); + + execute("INSERT INTO %s (a, b, c, d, e) VALUES (0, 2, 0, 0, 0)"); + 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, 0, 0, 0, 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, 2, 2)"); + execute("INSERT INTO %s (a, b, c, d, e) VALUES (0, 0, 3, 3, 3)"); + execute("INSERT INTO %s (a, b, c, d, e) VALUES (0, 0, 1, 1, 1)"); + + assertRows(execute("SELECT * FROM %s WHERE b=0 AND (c, d, e) > (1, 1, 1) ALLOW FILTERING"), + row(0, 0, 2, 2, 2), + row(0, 0, 3, 3, 3)); + } + } diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectOrderByTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectOrderByTest.java new file mode 100644 index 0000000000..e78809530f --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectOrderByTest.java @@ -0,0 +1,504 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cassandra.cql3.validation.operations; + +import org.junit.Test; + +import org.apache.cassandra.cql3.CQLTester; + +import static org.junit.Assert.assertTrue; + +public class SelectOrderByTest extends CQLTester +{ + @Test + public void testNormalSelectionOrderSingleClustering() throws Throwable + { + for (String descOption : new String[]{"", " WITH CLUSTERING ORDER BY (b DESC)"}) + { + createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY (a, b))" + descOption); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, 0, 0); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, 1, 1); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, 2, 2); + + assertRows(execute("SELECT * FROM %s WHERE a=? ORDER BY b ASC", 0), + row(0, 0, 0), + row(0, 1, 1), + row(0, 2, 2) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? ORDER BY b DESC", 0), + row(0, 2, 2), + row(0, 1, 1), + row(0, 0, 0) + ); + + // order by the only column in the selection + assertRows(execute("SELECT b FROM %s WHERE a=? ORDER BY b ASC", 0), + row(0), row(1), row(2)); + + assertRows(execute("SELECT b FROM %s WHERE a=? ORDER BY b DESC", 0), + row(2), row(1), row(0)); + + // order by a column not in the selection + assertRows(execute("SELECT c FROM %s WHERE a=? ORDER BY b ASC", 0), + row(0), row(1), row(2)); + + assertRows(execute("SELECT c FROM %s WHERE a=? ORDER BY b DESC", 0), + row(2), row(1), row(0)); + } + } + + @Test + public void testFunctionSelectionOrderSingleClustering() throws Throwable + { + for (String descOption : new String[]{"", " WITH CLUSTERING ORDER BY (b DESC)"}) + { + createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY (a, b))" + descOption); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, 0, 0); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, 1, 1); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, 2, 2); + + // order by the only column in the selection + assertRows(execute("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY b ASC", 0), + row(0), row(1), row(2)); + + assertRows(execute("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY b DESC", 0), + row(2), row(1), row(0)); + + // order by a column not in the selection + assertRows(execute("SELECT blobAsInt(intAsBlob(c)) FROM %s WHERE a=? ORDER BY b ASC", 0), + row(0), row(1), row(2)); + + assertRows(execute("SELECT blobAsInt(intAsBlob(c)) FROM %s WHERE a=? ORDER BY b DESC", 0), + row(2), row(1), row(0)); + + assertInvalid("SELECT * FROM %s WHERE a=? ORDER BY c ASC", 0); + assertInvalid("SELECT * FROM %s WHERE a=? ORDER BY c DESC", 0); + } + } + + @Test + public void testFieldSelectionOrderSingleClustering() throws Throwable + { + String type = createType("CREATE TYPE %s (a int)"); + + for (String descOption : new String[]{"", " WITH CLUSTERING ORDER BY (b DESC)"}) + { + createTable("CREATE TABLE %s (a int, b int, c frozen<" + type + " >, PRIMARY KEY (a, b))" + descOption); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, {a: ?})", 0, 0, 0); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, {a: ?})", 0, 1, 1); + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, {a: ?})", 0, 2, 2); + + // order by a column not in the selection + assertRows(execute("SELECT c.a FROM %s WHERE a=? ORDER BY b ASC", 0), + row(0), row(1), row(2)); + + assertRows(execute("SELECT c.a FROM %s WHERE a=? ORDER BY b DESC", 0), + row(2), row(1), row(0)); + + assertRows(execute("SELECT blobAsInt(intAsBlob(c.a)) FROM %s WHERE a=? ORDER BY b DESC", 0), + row(2), row(1), row(0)); + dropTable("DROP TABLE %s"); + } + } + + @Test + public void testNormalSelectionOrderMultipleClustering() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY (a, b, c))"); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 0, 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 1, 1); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 2, 2); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 0, 3); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 1, 4); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 2, 5); + + assertRows(execute("SELECT * FROM %s WHERE a=? ORDER BY b ASC", 0), + row(0, 0, 0, 0), + row(0, 0, 1, 1), + row(0, 0, 2, 2), + row(0, 1, 0, 3), + row(0, 1, 1, 4), + row(0, 1, 2, 5) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? ORDER BY b DESC", 0), + row(0, 1, 2, 5), + row(0, 1, 1, 4), + row(0, 1, 0, 3), + row(0, 0, 2, 2), + row(0, 0, 1, 1), + row(0, 0, 0, 0) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? ORDER BY b DESC, c DESC", 0), + row(0, 1, 2, 5), + row(0, 1, 1, 4), + row(0, 1, 0, 3), + row(0, 0, 2, 2), + row(0, 0, 1, 1), + row(0, 0, 0, 0) + ); + + assertInvalid("SELECT * FROM %s WHERE a=? ORDER BY c ASC", 0); + assertInvalid("SELECT * FROM %s WHERE a=? ORDER BY c DESC", 0); + assertInvalid("SELECT * FROM %s WHERE a=? ORDER BY b ASC, c DESC", 0); + assertInvalid("SELECT * FROM %s WHERE a=? ORDER BY b DESC, c ASC", 0); + assertInvalid("SELECT * FROM %s WHERE a=? ORDER BY d ASC", 0); + + // select and order by b + assertRows(execute("SELECT b FROM %s WHERE a=? ORDER BY b ASC", 0), + row(0), row(0), row(0), row(1), row(1), row(1)); + assertRows(execute("SELECT b FROM %s WHERE a=? ORDER BY b DESC", 0), + row(1), row(1), row(1), row(0), row(0), row(0)); + + // select c, order by b + assertRows(execute("SELECT c FROM %s WHERE a=? ORDER BY b ASC", 0), + row(0), row(1), row(2), row(0), row(1), row(2)); + assertRows(execute("SELECT c FROM %s WHERE a=? ORDER BY b DESC", 0), + row(2), row(1), row(0), row(2), row(1), row(0)); + + // select c, order by b, c + assertRows(execute("SELECT c FROM %s WHERE a=? ORDER BY b ASC, c ASC", 0), + row(0), row(1), row(2), row(0), row(1), row(2)); + assertRows(execute("SELECT c FROM %s WHERE a=? ORDER BY b DESC, c DESC", 0), + row(2), row(1), row(0), row(2), row(1), row(0)); + + // select d, order by b, c + assertRows(execute("SELECT d FROM %s WHERE a=? ORDER BY b ASC, c ASC", 0), + row(0), row(1), row(2), row(3), row(4), row(5)); + assertRows(execute("SELECT d FROM %s WHERE a=? ORDER BY b DESC, c DESC", 0), + row(5), row(4), row(3), row(2), row(1), row(0)); + } + + @Test + public void testFunctionSelectionOrderMultipleClustering() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY (a, b, c))"); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 0, 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 1, 1); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 2, 2); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 0, 3); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 1, 4); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 2, 5); + + assertInvalid("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY c ASC", 0); + assertInvalid("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY c DESC", 0); + assertInvalid("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY b ASC, c DESC", 0); + assertInvalid("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY b DESC, c ASC", 0); + assertInvalid("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY d ASC", 0); + + // select and order by b + assertRows(execute("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY b ASC", 0), + row(0), row(0), row(0), row(1), row(1), row(1)); + assertRows(execute("SELECT blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY b DESC", 0), + row(1), row(1), row(1), row(0), row(0), row(0)); + + assertRows(execute("SELECT b, blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY b ASC", 0), + row(0, 0), row(0, 0), row(0, 0), row(1, 1), row(1, 1), row(1, 1)); + assertRows(execute("SELECT b, blobAsInt(intAsBlob(b)) FROM %s WHERE a=? ORDER BY b DESC", 0), + row(1, 1), row(1, 1), row(1, 1), row(0, 0), row(0, 0), row(0, 0)); + + // select c, order by b + assertRows(execute("SELECT blobAsInt(intAsBlob(c)) FROM %s WHERE a=? ORDER BY b ASC", 0), + row(0), row(1), row(2), row(0), row(1), row(2)); + assertRows(execute("SELECT blobAsInt(intAsBlob(c)) FROM %s WHERE a=? ORDER BY b DESC", 0), + row(2), row(1), row(0), row(2), row(1), row(0)); + + // select c, order by b, c + assertRows(execute("SELECT blobAsInt(intAsBlob(c)) FROM %s WHERE a=? ORDER BY b ASC, c ASC", 0), + row(0), row(1), row(2), row(0), row(1), row(2)); + assertRows(execute("SELECT blobAsInt(intAsBlob(c)) FROM %s WHERE a=? ORDER BY b DESC, c DESC", 0), + row(2), row(1), row(0), row(2), row(1), row(0)); + + // select d, order by b, c + assertRows(execute("SELECT blobAsInt(intAsBlob(d)) FROM %s WHERE a=? ORDER BY b ASC, c ASC", 0), + row(0), row(1), row(2), row(3), row(4), row(5)); + assertRows(execute("SELECT blobAsInt(intAsBlob(d)) FROM %s WHERE a=? ORDER BY b DESC, c DESC", 0), + row(5), row(4), row(3), row(2), row(1), row(0)); + + } + + /** + * Check ORDER BY support in SELECT statement + * migrated from cql_tests.py:TestCQL.order_by_test() + */ + @Test + public void testSimpleOrderBy() throws Throwable + { + createTable("CREATE TABLE %s (k int, c int, v int, PRIMARY KEY (k, c)) WITH COMPACT STORAGE"); + + for (int i = 0; i < 10; i++) + execute("INSERT INTO %s (k, c, v) VALUES (0, ?, ?)", i, i); + + assertRows(execute("SELECT v FROM %s WHERE k = 0 ORDER BY c DESC"), + row(9), row(8), row(7), row(6), row(5), row(4), row(3), row(2), row(1), row(0)); + + createTable("CREATE TABLE %s (k int, c1 int, c2 int, v int, PRIMARY KEY (k, c1, c2)) WITH COMPACT STORAGE"); + + for (int i = 0; i < 4; i++) + for (int j = 0; j < 2; j++) + execute("INSERT INTO %s (k, c1, c2, v) VALUES (0, ?, ?, ?)", i, j, i * 2 + j); + + assertInvalid("SELECT v FROM %s WHERE k = 0 ORDER BY c DESC"); + assertInvalid("SELECT v FROM %s WHERE k = 0 ORDER BY c2 DESC"); + assertInvalid("SELECT v FROM %s WHERE k = 0 ORDER BY k DESC"); + + assertRows(execute("SELECT v FROM %s WHERE k = 0 ORDER BY c1 DESC"), + row(7), row(6), row(5), row(4), row(3), row(2), row(1), row(0)); + + assertRows(execute("SELECT v FROM %s WHERE k = 0 ORDER BY c1"), + row(0), row(1), row(2), row(3), row(4), row(5), row(6), row(7)); + } + + /** + * More ORDER BY checks (#4160) + * migrated from cql_tests.py:TestCQL.more_order_by_test() + */ + @Test + public void testMoreOrderBy() throws Throwable + { + createTable("CREATE TABLE %s (row text, number int, string text, PRIMARY KEY(row, number)) WITH COMPACT STORAGE "); + + execute("INSERT INTO %s (row, number, string) VALUES ('row', 1, 'one')"); + execute("INSERT INTO %s (row, number, string) VALUES ('row', 2, 'two')"); + execute("INSERT INTO %s (row, number, string) VALUES ('row', 3, 'three')"); + execute("INSERT INTO %s (row, number, string) VALUES ('row', 4, 'four')"); + + assertRows(execute("SELECT number FROM %s WHERE row='row' AND number < 3 ORDER BY number ASC"), + row(1), row(2)); + + assertRows(execute("SELECT number FROM %s WHERE row='row' AND number >= 3 ORDER BY number ASC"), + row(3), row(4)); + + assertRows(execute("SELECT number FROM %s WHERE row='row' AND number < 3 ORDER BY number DESC"), + row(2), row(1)); + + assertRows(execute("SELECT number FROM %s WHERE row='row' AND number >= 3 ORDER BY number DESC"), + row(4), row(3)); + + assertRows(execute("SELECT number FROM %s WHERE row='row' AND number > 3 ORDER BY number DESC"), + row(4)); + + assertRows(execute("SELECT number FROM %s WHERE row='row' AND number <= 3 ORDER BY number DESC"), + row(3), row(2), row(1)); + } + + /** + * Check we don't allow order by on row key (#4246) + * migrated from cql_tests.py:TestCQL.order_by_validation_test() + */ + @Test + public void testInvalidOrderBy() throws Throwable + { + createTable("CREATE TABLE %s( k1 int, k2 int, v int, PRIMARY KEY (k1, k2))"); + + execute("INSERT INTO %s (k1, k2, v) VALUES (?, ?, ?)", 0, 0, 0); + execute("INSERT INTO %s (k1, k2, v) VALUES (?, ?, ?)", 1, 1, 1); + execute("INSERT INTO %s (k1, k2, v) VALUES (?, ?, ?)", 2, 2, 2); + + assertInvalid("SELECT * FROM %s ORDER BY k2"); + } + + /** + * Check that order-by works with IN (#4327) + * migrated from cql_tests.py:TestCQL.order_by_with_in_test() + */ + @Test + public void testOrderByForInClause() throws Throwable + { + createTable("CREATE TABLE %s (my_id varchar, col1 int, value varchar, PRIMARY KEY (my_id, col1))"); + + execute("INSERT INTO %s (my_id, col1, value) VALUES ( 'key1', 1, 'a')"); + execute("INSERT INTO %s (my_id, col1, value) VALUES ( 'key2', 3, 'c')"); + execute("INSERT INTO %s (my_id, col1, value) VALUES ( 'key3', 2, 'b')"); + execute("INSERT INTO %s (my_id, col1, value) VALUES ( 'key4', 4, 'd')"); + + assertRows(execute("SELECT col1 FROM %s WHERE my_id in('key1', 'key2', 'key3') ORDER BY col1"), + row(1), row(2), row(3)); + + assertRows(execute("SELECT col1, my_id FROM %s WHERE my_id in('key1', 'key2', 'key3') ORDER BY col1"), + row(1, "key1"), row(2, "key3"), row(3, "key2")); + + assertRows(execute("SELECT my_id, col1 FROM %s WHERE my_id in('key1', 'key2', 'key3') ORDER BY col1"), + row("key1", 1), row("key3", 2), row("key2", 3)); + } + + /** + * Test reversed comparators + * migrated from cql_tests.py:TestCQL.reversed_comparator_test() + */ + @Test + public void testReversedComparator() throws Throwable + { + createTable("CREATE TABLE %s (k int, c int, v int, PRIMARY KEY (k, c)) WITH CLUSTERING ORDER BY (c DESC);"); + + for(int i =0; i < 10; i++) + execute("INSERT INTO %s (k, c, v) VALUES (0, ?, ?)", i, i); + + assertRows(execute("SELECT c, v FROM %s WHERE k = 0 ORDER BY c ASC"), + row(0, 0), row(1, 1), row(2, 2), row(3, 3), row(4, 4), + row(5, 5), row(6, 6), row(7, 7), row(8, 8), row(9, 9)); + + assertRows(execute("SELECT c, v FROM %s WHERE k = 0 ORDER BY c DESC"), + row(9, 9), row(8, 8), row(7, 7), row(6, 6), row(5, 5), + row(4, 4), row(3, 3), row(2, 2), row(1, 1), row(0, 0)); + + createTable("CREATE TABLE %s (k int, c1 int, c2 int, v text, PRIMARY KEY (k, c1, c2)) WITH CLUSTERING ORDER BY (c1 ASC, c2 DESC)"); + + for(int i = 0; i < 10; i++) + for(int j = 0; j < 10; j++) + execute("INSERT INTO %s (k, c1, c2, v) VALUES (0, ?, ?, ?)", i, j, String.format("%d%d", i, j)); + + assertInvalid("SELECT c1, c2, v FROM %s WHERE k = 0 ORDER BY c1 ASC, c2 ASC"); + assertInvalid("SELECT c1, c2, v FROM %s WHERE k = 0 ORDER BY c1 DESC, c2 DESC"); + + Object[][] expectedRows = new Object[100][]; + for(int i = 0; i < 10; i++) + for(int j = 9; j >= 0; j--) + expectedRows[i * 10 + (9 - j)] = row(i, j, String.format("%d%d", i, j)); + + assertRows(execute("SELECT c1, c2, v FROM %s WHERE k = 0 ORDER BY c1 ASC"), + expectedRows); + + assertRows(execute("SELECT c1, c2, v FROM %s WHERE k = 0 ORDER BY c1 ASC, c2 DESC"), + expectedRows); + + for(int i = 9; i >= 0; i--) + for(int j = 0; j < 10; j++) + expectedRows[(9 - i) * 10 + j] = row(i, j, String.format("%d%d", i, j)); + + assertRows(execute("SELECT c1, c2, v FROM %s WHERE k = 0 ORDER BY c1 DESC, c2 ASC"), + expectedRows); + + assertInvalid("SELECT c1, c2, v FROM %s WHERE k = 0 ORDER BY c2 DESC, c1 ASC"); + } + + /** + * Migrated from cql_tests.py:TestCQL.multiordering_test() + */ + @Test + public void testMultiordering() throws Throwable + { + createTable("CREATE TABLE %s (k text, c1 int, c2 int, PRIMARY KEY (k, c1, c2) ) WITH CLUSTERING ORDER BY (c1 ASC, c2 DESC)"); + + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + execute("INSERT INTO %s (k, c1, c2) VALUES ('foo', ?, ?)", i, j); + + assertRows(execute("SELECT c1, c2 FROM %s WHERE k = 'foo'"), + row(0, 1), row(0, 0), row(1, 1), row(1, 0)); + + assertRows(execute("SELECT c1, c2 FROM %s WHERE k = 'foo' ORDER BY c1 ASC, c2 DESC"), + row(0, 1), row(0, 0), row(1, 1), row(1, 0)); + + assertRows(execute("SELECT c1, c2 FROM %s WHERE k = 'foo' ORDER BY c1 DESC, c2 ASC"), + row(1, 0), row(1, 1), row(0, 0), row(0, 1)); + + assertInvalid("SELECT c1, c2 FROM %s WHERE k = 'foo' ORDER BY c2 DESC"); + assertInvalid("SELECT c1, c2 FROM %s WHERE k = 'foo' ORDER BY c2 ASC"); + assertInvalid("SELECT c1, c2 FROM %s WHERE k = 'foo' ORDER BY c1 ASC, c2 ASC"); + } + + /** + * Migrated from cql_tests.py:TestCQL.in_with_desc_order_test() + */ + @Test + public void testSelectInStatementWithDesc() throws Throwable + { + createTable("CREATE TABLE %s (k int, c1 int, c2 int, PRIMARY KEY (k, c1, c2))"); + execute("INSERT INTO %s(k, c1, c2) VALUES (0, 0, 0)"); + execute("INSERT INTO %s(k, c1, c2) VALUES (0, 0, 1)"); + execute("INSERT INTO %s(k, c1, c2) VALUES (0, 0, 2)"); + + assertRows(execute("SELECT * FROM %s WHERE k=0 AND c1 = 0 AND c2 IN (2, 0) ORDER BY c1 DESC"), + row(0, 0, 2), + row(0, 0, 0)); + } + + /** + * Test that columns don't need to be selected for ORDER BY when there is a IN (#4911), + * migrated from cql_tests.py:TestCQL.in_order_by_without_selecting_test() + */ + @Test + public void testInOrderByWithoutSelecting() throws Throwable + { + createTable("CREATE TABLE %s (k int, c1 int, c2 int, v int, PRIMARY KEY (k, c1, c2))"); + + execute("INSERT INTO %s (k, c1, c2, v) VALUES (0, 0, 0, 0)"); + execute("INSERT INTO %s (k, c1, c2, v) VALUES (0, 0, 1, 1)"); + execute("INSERT INTO %s (k, c1, c2, v) VALUES (0, 0, 2, 2)"); + execute("INSERT INTO %s (k, c1, c2, v) VALUES (1, 1, 0, 3)"); + execute("INSERT INTO %s (k, c1, c2, v) VALUES (1, 1, 1, 4)"); + execute("INSERT INTO %s (k, c1, c2, v) VALUES (1, 1, 2, 5)"); + + assertRows(execute("SELECT * FROM %s WHERE k=0 AND c1 = 0 AND c2 IN (2, 0)"), + row(0, 0, 0, 0), + row(0, 0, 2, 2)); + assertRows(execute("SELECT * FROM %s WHERE k=0 AND c1 = 0 AND c2 IN (2, 0) ORDER BY c1 ASC, c2 ASC"), + row(0, 0, 0, 0), + row(0, 0, 2, 2)); + + // check that we don 't need to select the column on which we order + assertRows(execute("SELECT v FROM %s WHERE k=0 AND c1 = 0 AND c2 IN (2, 0)"), + row(0), + row(2)); + assertRows(execute("SELECT v FROM %s WHERE k=0 AND c1 = 0 AND c2 IN (2, 0) ORDER BY c1 ASC"), + row(0), + row(2)); + assertRows(execute("SELECT v FROM %s WHERE k=0 AND c1 = 0 AND c2 IN (2, 0) ORDER BY c1 DESC"), + row(2), + row(0)); + + assertRows(execute("SELECT v FROM %s WHERE k IN (1, 0)"), + row(0), + row(1), + row(2), + row(3), + row(4), + row(5)); + + assertRows(execute("SELECT v FROM %s WHERE k IN (1, 0) ORDER BY c1 ASC"), + row(0), + row(1), + row(2), + row(3), + row(4), + row(5)); + + // we should also be able to use functions in the select clause (additional test for CASSANDRA - 8286) + Object[][] results = getRows(execute("SELECT writetime(v) FROM %s WHERE k IN (1, 0) ORDER BY c1 ASC")); + + // since we don 't know the write times, just assert that the order matches the order we expect + assertTrue(isFirstIntSorted(results)); + } + + private boolean isFirstIntSorted(Object[][] rows) + { + for (int i = 1; i < rows.length; i++) + { + Long prev = (Long)rows[i-1][0]; + Long curr = (Long)rows[i][0]; + + if (prev > curr) + return false; + } + + return true; + } +} diff --git a/test/unit/org/apache/cassandra/cql3/SelectWithTokenFunctionTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectOrderedPartitionerTest.java similarity index 53% rename from test/unit/org/apache/cassandra/cql3/SelectWithTokenFunctionTest.java rename to test/unit/org/apache/cassandra/cql3/validation/operations/SelectOrderedPartitionerTest.java index cde4f92c19..5152ba9b41 100644 --- a/test/unit/org/apache/cassandra/cql3/SelectWithTokenFunctionTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectOrderedPartitionerTest.java @@ -1,28 +1,27 @@ -/* - * 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; +package org.apache.cassandra.cql3.validation.operations; import java.util.Arrays; +import org.junit.BeforeClass; import org.junit.Test; -public class SelectWithTokenFunctionTest extends CQLTester +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.dht.ByteOrderedPartitioner; + +/** + * SELECT statement tests that require a ByteOrderedPartitioner + */ +public class SelectOrderedPartitionerTest extends CQLTester { + @BeforeClass + public static void setUp() + { + DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance); + } + @Test public void testTokenFunctionWithSingleColumnPartitionKey() throws Throwable { @@ -230,4 +229,253 @@ public class SelectWithTokenFunctionTest extends CQLTester execute("SELECT * FROM %s WHERE token(a, b) > token(0, 0) AND (c, d) > (0, 0) ALLOW FILTERING;"); execute("SELECT * FROM %s WHERE (c, d) > (0, 0) AND token(a, b) > token(0, 0) ALLOW FILTERING;"); } + + /** + * Test undefined columns + * migrated from cql_tests.py:TestCQL.undefined_column_handling_test() + */ + @Test + public void testUndefinedColumns() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, v1 int, v2 int,)"); + + execute("INSERT INTO %s (k, v1, v2) VALUES (0, 0, 0)"); + execute("INSERT INTO %s (k, v1) VALUES (1, 1)"); + execute("INSERT INTO %s (k, v1, v2) VALUES (2, 2, 2)"); + + Object[][] rows = getRows(execute("SELECT v2 FROM %s")); + assertEquals(0, rows[0][0]); + assertEquals(null, rows[1][0]); + assertEquals(2, rows[2][0]); + + rows = getRows(execute("SELECT v2 FROM %s WHERE k = 1")); + assertEquals(1, rows.length); + assertNull(rows[0][0]); + } + + /** + * Check table with only a PK (#4361), + * migrated from cql_tests.py:TestCQL.only_pk_test() + */ + @Test + public void testPrimaryKeyOnly() throws Throwable + { + createTable("CREATE TABLE %s (k int, c int, PRIMARY KEY (k, c))"); + + for (int k = 0; k < 2; k++) + for (int c = 0; c < 2; c++) + execute("INSERT INTO %s (k, c) VALUES (?, ?)", k, c); + + assertRows(execute("SELECT * FROM %s"), + row(0, 0), + row(0, 1), + row(1, 0), + row(1, 1)); + + // Check for dense tables too + createTable(" CREATE TABLE %s (k int, c int, PRIMARY KEY (k, c)) WITH COMPACT STORAGE"); + + for (int k = 0; k < 2; k++) + for (int c = 0; c < 2; c++) + execute("INSERT INTO %s (k, c) VALUES (?, ?)", k, c); + + assertRows(execute("SELECT * FROM %s"), + row(0, 0), + row(0, 1), + row(1, 0), + row(1, 1)); + } + + /** + * Migrated from cql_tests.py:TestCQL.composite_index_with_pk_test() + */ + @Test + public void testCompositeIndexWithPK() 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)"); + + execute("INSERT INTO %s (blog_id, time1, time2, author, content) VALUES (?, ?, ?, ?, ?)", 1, 0, 0, "foo", "bar1"); + execute("INSERT INTO %s (blog_id, time1, time2, author, content) VALUES (?, ?, ?, ?, ?)", 1, 0, 1, "foo", "bar2"); + execute("INSERT INTO %s (blog_id, time1, time2, author, content) VALUES (?, ?, ?, ?, ?)", 2, 1, 0, "foo", "baz"); + execute("INSERT INTO %s (blog_id, time1, time2, author, content) VALUES (?, ?, ?, ?, ?)", 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")); + + assertInvalid("SELECT content FROM %s WHERE time2 >= 0 AND author='foo'"); + + assertInvalid("SELECT blog_id, content FROM %s WHERE time1 > 0 AND author='foo'"); + assertInvalid("SELECT blog_id, content FROM %s WHERE time1 = 1 AND author='foo'"); + assertInvalid("SELECT blog_id, content FROM %s WHERE time1 = 1 AND time2 = 0 AND author='foo'"); + assertInvalid("SELECT content FROM %s WHERE time1 = 1 AND time2 = 1 AND author='foo'"); + assertInvalid("SELECT content FROM %s WHERE time1 = 1 AND time2 > 0 AND author='foo'"); + } + + /** + * Test for LIMIT bugs from 4579, + * migrated from cql_tests.py:TestCQL.limit_bugs_test() + */ + @Test + public void testLimitBug() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, d int, e int, PRIMARY KEY (a, b))"); + + execute("INSERT INTO %s (a, b, c, d, e) VALUES (1, 1, 1, 1, 1);"); + execute("INSERT INTO %s (a, b, c, d, e) VALUES (2, 2, 2, 2, 2);"); + execute("INSERT INTO %s (a, b, c, d, e) VALUES (3, 3, 3, 3, 3);"); + execute("INSERT INTO %s (a, b, c, d, e) VALUES (4, 4, 4, 4, 4);"); + + assertRows(execute("SELECT * FROM %s"), + row(1, 1, 1, 1, 1), + row(2, 2, 2, 2, 2), + row(3, 3, 3, 3, 3), + row(4, 4, 4, 4, 4)); + + assertRows(execute("SELECT * FROM %s LIMIT 1"), + row(1, 1, 1, 1, 1)); + + assertRows(execute("SELECT * FROM %s LIMIT 2"), + row(1, 1, 1, 1, 1), + row(2, 2, 2, 2, 2)); + + createTable("CREATE TABLE %s (a int primary key, b int, c int,)"); + + execute("INSERT INTO %s (a, b, c) VALUES (1, 1, 1)"); + execute("INSERT INTO %s (a, b, c) VALUES (2, 2, 2)"); + execute("INSERT INTO %s (a, b, c) VALUES (3, 3, 3)"); + execute("INSERT INTO %s (a, b, c) VALUES (4, 4, 4)"); + + assertRows(execute("SELECT * FROM %s"), + row(1, 1, 1), + row(2, 2, 2), + row(3, 3, 3), + row(4, 4, 4)); + + assertRows(execute("SELECT * FROM %s LIMIT 1"), + row(1, 1, 1)); + + assertRows(execute("SELECT * FROM %s LIMIT 2"), + row(1, 1, 1), + row(2, 2, 2)); + + assertRows(execute("SELECT * FROM %s LIMIT 3"), + row(1, 1, 1), + row(2, 2, 2), + row(3, 3, 3)); + + assertRows(execute("SELECT * FROM %s LIMIT 4"), + row(1, 1, 1), + row(2, 2, 2), + row(3, 3, 3), + row(4, 4, 4)); + + assertRows(execute("SELECT * FROM %s LIMIT 5"), + row(1, 1, 1), + row(2, 2, 2), + row(3, 3, 3), + row(4, 4, 4)); + } + + /** + * Test for #4612 bug and more generally order by when multiple C* rows are queried + * migrated from cql_tests.py:TestCQL.order_by_multikey_test() + */ + @Test + public void testOrderByMultikey() throws Throwable + { + createTable("CREATE TABLE %s (my_id varchar, col1 int, col2 int, value varchar, PRIMARY KEY (my_id, col1, col2))"); + + execute("INSERT INTO %s (my_id, col1, col2, value) VALUES ( 'key1', 1, 1, 'a');"); + execute("INSERT INTO %s (my_id, col1, col2, value) VALUES ( 'key2', 3, 3, 'a');"); + execute("INSERT INTO %s (my_id, col1, col2, value) VALUES ( 'key3', 2, 2, 'b');"); + execute("INSERT INTO %s (my_id, col1, col2, value) VALUES ( 'key4', 2, 1, 'b');"); + + assertRows(execute("SELECT col1 FROM %s WHERE my_id in('key1', 'key2', 'key3') ORDER BY col1"), + row(1), row(2), row(3)); + + assertRows(execute("SELECT col1, value, my_id, col2 FROM %s WHERE my_id in('key3', 'key4') ORDER BY col1, col2"), + row(2, "b", "key4", 1), row(2, "b", "key3", 2)); + + assertInvalid("SELECT col1 FROM %s ORDER BY col1"); + assertInvalid("SELECT col1 FROM %s WHERE my_id > 'key1' ORDER BY col1"); + } + + /** + * Migrated from cql_tests.py:TestCQL.composite_index_collections_test() + */ + @Test + public void testIndexOnCompositeWithCollections() throws Throwable + { + createTable("CREATE TABLE %s (blog_id int, time1 int, time2 int, author text, content set, PRIMARY KEY (blog_id, time1, time2))"); + + createIndex("CREATE INDEX ON %s (author)"); + + execute("INSERT INTO %s (blog_id, time1, time2, author, content) VALUES (?, ?, ?, ?, { 'bar1', 'bar2' })", 1, 0, 0, "foo"); + execute("INSERT INTO %s (blog_id, time1, time2, author, content) VALUES (?, ?, ?, ?, { 'bar2', 'bar3' })", 1, 0, 1, "foo"); + execute("INSERT INTO %s (blog_id, time1, time2, author, content) VALUES (?, ?, ?, ?, { 'baz' })", 2, 1, 0, "foo"); + execute("INSERT INTO %s (blog_id, time1, time2, author, content) VALUES (?, ?, ?, ?, { 'qux' })", 3, 0, 1, "gux"); + + assertRows(execute("SELECT blog_id, content FROM %s WHERE author='foo'"), + row(1, set("bar1", "bar2")), + row(1, set("bar2", "bar3")), + row(2, set("baz"))); + } + + /** + * Migrated from cql_tests.py:TestCQL.truncate_clean_cache_test() + */ + @Test + public void testTruncateWithCaching() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, v1 int, v2 int,) WITH CACHING = ALL;"); + + for (int i = 0; i < 3; i++) + execute("INSERT INTO %s (k, v1, v2) VALUES (?, ?, ?)", i, i, i * 2); + + assertRows(execute("SELECT v1, v2 FROM %s WHERE k IN (0, 1, 2)"), + row(0, 0), + row(1, 2), + row(2, 4)); + + execute("TRUNCATE %s"); + + assertEmpty(execute("SELECT v1, v2 FROM %s WHERE k IN (0, 1, 2)")); + } + + /** + * Migrated from cql_tests.py:TestCQL.range_key_ordered_test() + */ + @Test + public void testRangeKey() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY)"); + + execute("INSERT INTO %s (k) VALUES (-1)"); + execute("INSERT INTO %s (k) VALUES ( 0)"); + execute("INSERT INTO %s (k) VALUES ( 1)"); + + assertRows(execute("SELECT * FROM %s"), + row(0), + row(1), + row(-1)); + + assertInvalid("SELECT * FROM %s WHERE k >= -1 AND k < 1"); + } } diff --git a/test/unit/org/apache/cassandra/cql3/SingleColumnRelationTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectSingleColumnRelationTest.java similarity index 99% rename from test/unit/org/apache/cassandra/cql3/SingleColumnRelationTest.java rename to test/unit/org/apache/cassandra/cql3/validation/operations/SelectSingleColumnRelationTest.java index 2b8fbd40be..fd43a517d5 100644 --- a/test/unit/org/apache/cassandra/cql3/SingleColumnRelationTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectSingleColumnRelationTest.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.operations; import java.util.Arrays; @@ -24,7 +24,9 @@ import org.junit.Test; import java.util.ArrayList; import java.util.List; -public class SingleColumnRelationTest extends CQLTester +import org.apache.cassandra.cql3.CQLTester; + +public class SelectSingleColumnRelationTest extends CQLTester { @Test public void testInvalidCollectionEqualityRelation() throws Throwable diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java new file mode 100644 index 0000000000..506bdafc81 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java @@ -0,0 +1,1336 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cassandra.cql3.validation.operations; + +import java.nio.ByteBuffer; +import java.util.UUID; + +import org.junit.Test; + +import junit.framework.Assert; +import org.apache.cassandra.cql3.UntypedResultSet; +import org.apache.cassandra.cql3.CQLTester; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Test column ranges and ordering with static column in table + */ +public class SelectTest extends CQLTester +{ + @Test + public void testSingleClustering() throws Throwable + { + createTable("CREATE TABLE %s (p text, c text, v text, s text static, PRIMARY KEY (p, c))"); + + execute("INSERT INTO %s(p, c, v, s) values (?, ?, ?, ?)", "p1", "k1", "v1", "sv1"); + execute("INSERT INTO %s(p, c, v) values (?, ?, ?)", "p1", "k2", "v2"); + execute("INSERT INTO %s(p, s) values (?, ?)", "p2", "sv2"); + + assertRows(execute("SELECT * FROM %s WHERE p=?", "p1"), + row("p1", "k1", "sv1", "v1"), + row("p1", "k2", "sv1", "v2") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=?", "p2"), + row("p2", null, "sv2", null) + ); + + // Ascending order + + assertRows(execute("SELECT * FROM %s WHERE p=? ORDER BY c ASC", "p1"), + row("p1", "k1", "sv1", "v1"), + row("p1", "k2", "sv1", "v2") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? ORDER BY c ASC", "p2"), + row("p2", null, "sv2", null) + ); + + // Descending order + + assertRows(execute("SELECT * FROM %s WHERE p=? ORDER BY c DESC", "p1"), + row("p1", "k2", "sv1", "v2"), + row("p1", "k1", "sv1", "v1") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? ORDER BY c DESC", "p2"), + row("p2", null, "sv2", null) + ); + + // No order with one relation + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=?", "p1", "k1"), + row("p1", "k1", "sv1", "v1"), + row("p1", "k2", "sv1", "v2") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=?", "p1", "k2"), + row("p1", "k2", "sv1", "v2") + ); + + assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c>=?", "p1", "k3")); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c =?", "p1", "k1"), + row("p1", "k1", "sv1", "v1") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c<=?", "p1", "k1"), + row("p1", "k1", "sv1", "v1") + ); + + assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c<=?", "p1", "k0")); + + // Ascending with one relation + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c ASC", "p1", "k1"), + row("p1", "k1", "sv1", "v1"), + row("p1", "k2", "sv1", "v2") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c ASC", "p1", "k2"), + row("p1", "k2", "sv1", "v2") + ); + + assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c ASC", "p1", "k3")); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c =? ORDER BY c ASC", "p1", "k1"), + row("p1", "k1", "sv1", "v1") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c<=? ORDER BY c ASC", "p1", "k1"), + row("p1", "k1", "sv1", "v1") + ); + + assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c<=? ORDER BY c ASC", "p1", "k0")); + + // Descending with one relation + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c DESC", "p1", "k1"), + row("p1", "k2", "sv1", "v2"), + row("p1", "k1", "sv1", "v1") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c DESC", "p1", "k2"), + row("p1", "k2", "sv1", "v2") + ); + + assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c DESC", "p1", "k3")); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c =? ORDER BY c DESC", "p1", "k1"), + row("p1", "k1", "sv1", "v1") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c<=? ORDER BY c DESC", "p1", "k1"), + row("p1", "k1", "sv1", "v1") + ); + + assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c<=? ORDER BY c DESC", "p1", "k0")); + + // IN + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c IN (?, ?)", "p1", "k1", "k2"), + row("p1", "k1", "sv1", "v1"), + row("p1", "k2", "sv1", "v2") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c IN (?, ?) ORDER BY c ASC", "p1", "k1", "k2"), + row("p1", "k1", "sv1", "v1"), + row("p1", "k2", "sv1", "v2") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c IN (?, ?) ORDER BY c DESC", "p1", "k1", "k2"), + row("p1", "k2", "sv1", "v2"), + row("p1", "k1", "sv1", "v1") + ); + } + + @Test + public void testSingleClusteringReversed() throws Throwable + { + createTable("CREATE TABLE %s (p text, c text, v text, s text static, PRIMARY KEY (p, c)) WITH CLUSTERING ORDER BY (c DESC)"); + + execute("INSERT INTO %s(p, c, v, s) values (?, ?, ?, ?)", "p1", "k1", "v1", "sv1"); + execute("INSERT INTO %s(p, c, v) values (?, ?, ?)", "p1", "k2", "v2"); + execute("INSERT INTO %s(p, s) values (?, ?)", "p2", "sv2"); + + assertRows(execute("SELECT * FROM %s WHERE p=?", "p1"), + row("p1", "k2", "sv1", "v2"), + row("p1", "k1", "sv1", "v1") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=?", "p2"), + row("p2", null, "sv2", null) + ); + + // Ascending order + + assertRows(execute("SELECT * FROM %s WHERE p=? ORDER BY c ASC", "p1"), + row("p1", "k1", "sv1", "v1"), + row("p1", "k2", "sv1", "v2") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? ORDER BY c ASC", "p2"), + row("p2", null, "sv2", null) + ); + + // Descending order + + assertRows(execute("SELECT * FROM %s WHERE p=? ORDER BY c DESC", "p1"), + row("p1", "k2", "sv1", "v2"), + row("p1", "k1", "sv1", "v1") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? ORDER BY c DESC", "p2"), + row("p2", null, "sv2", null) + ); + + // No order with one relation + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=?", "p1", "k1"), + row("p1", "k2", "sv1", "v2"), + row("p1", "k1", "sv1", "v1") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=?", "p1", "k2"), + row("p1", "k2", "sv1", "v2") + ); + + assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c>=?", "p1", "k3")); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c=?", "p1", "k1"), + row("p1", "k1", "sv1", "v1") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c<=?", "p1", "k1"), + row("p1", "k1", "sv1", "v1") + ); + + assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c<=?", "p1", "k0")); + + // Ascending with one relation + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c ASC", "p1", "k1"), + row("p1", "k1", "sv1", "v1"), + row("p1", "k2", "sv1", "v2") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c ASC", "p1", "k2"), + row("p1", "k2", "sv1", "v2") + ); + + assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c ASC", "p1", "k3")); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c=? ORDER BY c ASC", "p1", "k1"), + row("p1", "k1", "sv1", "v1") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c<=? ORDER BY c ASC", "p1", "k1"), + row("p1", "k1", "sv1", "v1") + ); + + assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c<=? ORDER BY c ASC", "p1", "k0")); + + // Descending with one relation + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c DESC", "p1", "k1"), + row("p1", "k2", "sv1", "v2"), + row("p1", "k1", "sv1", "v1") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c DESC", "p1", "k2"), + row("p1", "k2", "sv1", "v2") + ); + + assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c>=? ORDER BY c DESC", "p1", "k3")); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c=? ORDER BY c DESC", "p1", "k1"), + row("p1", "k1", "sv1", "v1") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c<=? ORDER BY c DESC", "p1", "k1"), + row("p1", "k1", "sv1", "v1") + ); + + assertEmpty(execute("SELECT * FROM %s WHERE p=? AND c<=? ORDER BY c DESC", "p1", "k0")); + + // IN + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c IN (?, ?)", "p1", "k1", "k2"), + row("p1", "k2", "sv1", "v2"), + row("p1", "k1", "sv1", "v1") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c IN (?, ?) ORDER BY c ASC", "p1", "k1", "k2"), + row("p1", "k1", "sv1", "v1"), + row("p1", "k2", "sv1", "v2") + ); + + assertRows(execute("SELECT * FROM %s WHERE p=? AND c IN (?, ?) ORDER BY c DESC", "p1", "k1", "k2"), + row("p1", "k2", "sv1", "v2"), + row("p1", "k1", "sv1", "v1") + ); + } + + /** + * Check query with KEY IN clause + * migrated from cql_tests.py:TestCQL.select_key_in_test() + */ + @Test + public void testSelectKeyIn() throws Throwable + { + createTable("CREATE TABLE %s (userid uuid PRIMARY KEY, firstname text, lastname text, age int)"); + + UUID id1 = UUID.fromString("550e8400-e29b-41d4-a716-446655440000"); + UUID id2 = UUID.fromString("f47ac10b-58cc-4372-a567-0e02b2c3d479"); + + execute("INSERT INTO %s (userid, firstname, lastname, age) VALUES (?, 'Frodo', 'Baggins', 32)", id1); + execute("INSERT INTO %s (userid, firstname, lastname, age) VALUES (?, 'Samwise', 'Gamgee', 33)", id2); + + assertRowCount(execute("SELECT firstname, lastname FROM %s WHERE userid IN (?, ?)", id1, id2), 2); + } + + /** + * Check query with KEY IN clause for wide row tables + * migrated from cql_tests.py:TestCQL.in_clause_wide_rows_test() + */ + @Test + public void testSelectKeyInForWideRows() throws Throwable + { + createTable("CREATE TABLE %s (k int, c int, v int, PRIMARY KEY (k, c)) WITH COMPACT STORAGE"); + + for (int i = 0; i < 10; i++) + execute("INSERT INTO %s (k, c, v) VALUES (0, ?, ?)", i, i); + + assertRows(execute("SELECT v FROM %s WHERE k = 0 AND c IN (5, 2, 8)"), + row(2), row(5), row(8)); + + createTable("CREATE TABLE %s (k int, c1 int, c2 int, v int, PRIMARY KEY (k, c1, c2)) WITH COMPACT STORAGE"); + + for (int i = 0; i < 10; i++) + execute("INSERT INTO %s (k, c1, c2, v) VALUES (0, 0, ?, ?)", i, i); + + assertEmpty(execute("SELECT v FROM %s WHERE k = 0 AND c1 IN (5, 2, 8) AND c2 = 3")); + + assertRows(execute("SELECT v FROM %s WHERE k = 0 AND c1 = 0 AND c2 IN (5, 2, 8)"), + row(2), row(5), row(8)); + } + + /** + * Check SELECT respects inclusive and exclusive bounds + * migrated from cql_tests.py:TestCQL.exclusive_slice_test() + */ + @Test + public void testSelectBounds() throws Throwable + { + createTable("CREATE TABLE %s (k int, c int, v int, PRIMARY KEY (k, c)) WITH COMPACT STORAGE"); + + for (int i = 0; i < 10; i++) + execute("INSERT INTO %s (k, c, v) VALUES (0, ?, ?)", i, i); + + assertRowCount(execute("SELECT v FROM %s WHERE k = 0"), 10); + + assertRows(execute("SELECT v FROM %s WHERE k = 0 AND c >= 2 AND c <= 6"), + row(2), row(3), row(4), row(5), row(6)); + + assertRows(execute("SELECT v FROM %s WHERE k = 0 AND c > 2 AND c <= 6"), + row(3), row(4), row(5), row(6)); + + assertRows(execute("SELECT v FROM %s WHERE k = 0 AND c >= 2 AND c < 6"), + row(2), row(3), row(4), row(5)); + + assertRows(execute("SELECT v FROM %s WHERE k = 0 AND c > 2 AND c < 6"), + row(3), row(4), row(5)); + + assertRows(execute("SELECT v FROM %s WHERE k = 0 AND c > 2 AND c <= 6 LIMIT 2"), + row(3), row(4)); + + assertRows(execute("SELECT v FROM %s WHERE k = 0 AND c >= 2 AND c < 6 ORDER BY c DESC LIMIT 2"), + row(5), row(4)); + } + + @Test + public void testSetContains() throws Throwable + { + createTable("CREATE TABLE %s (account text, id int, categories set, PRIMARY KEY (account, id))"); + createIndex("CREATE INDEX ON %s(categories)"); + + execute("INSERT INTO %s (account, id , categories) VALUES (?, ?, ?)", "test", 5, set("lmn")); + + assertEmpty(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ?", "xyz", "lmn")); + + assertRows(execute("SELECT * FROM %s WHERE categories CONTAINS ?", "lmn"), + row("test", 5, set("lmn")) + ); + + assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ?", "test", "lmn"), + row("test", 5, set("lmn")) + ); + + assertRows(execute("SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, "lmn"), + row("test", 5, set("lmn")) + ); + + assertInvalidMessage("Unsupported null value for indexed column categories", + "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, null); + + assertInvalidMessage("Unsupported unset value for indexed column categories", + "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, unset()); + + 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")); + } + + @Test + public void testListContains() throws Throwable + { + createTable("CREATE TABLE %s (account text, id int, categories list, PRIMARY KEY (account, id))"); + createIndex("CREATE INDEX ON %s(categories)"); + + execute("INSERT INTO %s (account, id , categories) VALUES (?, ?, ?)", "test", 5, list("lmn")); + + assertEmpty(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ?", "xyz", "lmn")); + + assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ?;", "test", "lmn"), + row("test", 5, list("lmn")) + ); + + assertRows(execute("SELECT * FROM %s WHERE categories CONTAINS ?", "lmn"), + row("test", 5, list("lmn")) + ); + + assertRows(execute("SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?;", "test", 5, "lmn"), + row("test", 5, list("lmn")) + ); + + assertInvalidMessage("Unsupported null value for indexed column categories", + "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, null); + + assertInvalidMessage("Unsupported unset value for indexed column categories", + "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, unset()); + + 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")); + } + + @Test + public void testListContainsWithFiltering() throws Throwable + { + createTable("CREATE TABLE %s (e int PRIMARY KEY, f list, s int)"); + createIndex("CREATE INDEX ON %s(f)"); + for(int i = 0; i < 3; i++) + { + execute("INSERT INTO %s (e, f, s) VALUES (?, ?, ?)", i, list("Dubai"), 4); + } + for(int i = 3; i < 5; i++) + { + execute("INSERT INTO %s (e, f, s) VALUES (?, ?, ?)", i, list("Dubai"), 3); + } + assertRows(execute("SELECT * FROM %s WHERE f CONTAINS ? AND s=? allow filtering", "Dubai", 3), + row(4, list("Dubai"), 3), + row(3, list("Dubai"), 3)); + } + + @Test + public void testMapKeyContains() throws Throwable + { + createTable("CREATE TABLE %s (account text, id int, categories map, PRIMARY KEY (account, id))"); + createIndex("CREATE INDEX ON %s(keys(categories))"); + + execute("INSERT INTO %s (account, id , categories) VALUES (?, ?, ?)", "test", 5, map("lmn", "foo")); + + assertEmpty(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS KEY ?", "xyz", "lmn")); + + assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS KEY ?", "test", "lmn"), + row("test", 5, map("lmn", "foo")) + ); + assertRows(execute("SELECT * FROM %s WHERE categories CONTAINS KEY ?", "lmn"), + row("test", 5, map("lmn", "foo")) + ); + + assertRows(execute("SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS KEY ?", "test", 5, "lmn"), + row("test", 5, map("lmn", "foo")) + ); + + assertInvalidMessage("Unsupported null value for indexed column categories", + "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS KEY ?", "test", 5, null); + + assertInvalidMessage("Unsupported unset value for indexed column categories", + "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS KEY ?", "test", 5, unset()); + + 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")); + + 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 + public void testMapValueContains() throws Throwable + { + createTable("CREATE TABLE %s (account text, id int, categories map, PRIMARY KEY (account, id))"); + createIndex("CREATE INDEX ON %s(categories)"); + + execute("INSERT INTO %s (account, id , categories) VALUES (?, ?, ?)", "test", 5, map("lmn", "foo")); + + assertEmpty(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ?", "xyz", "foo")); + + assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ?", "test", "foo"), + row("test", 5, map("lmn", "foo")) + ); + + assertRows(execute("SELECT * FROM %s WHERE categories CONTAINS ?", "foo"), + row("test", 5, map("lmn", "foo")) + ); + + assertRows(execute("SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, "foo"), + row("test", 5, map("lmn", "foo")) + ); + + assertInvalidMessage("Unsupported null value for indexed column categories", + "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, null); + + assertInvalidMessage("Unsupported unset value for indexed column categories", + "SELECT * FROM %s WHERE account = ? AND id = ? AND categories CONTAINS ?", "test", 5, unset()); + + 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" + , "test", 5, "foo", "notPresent")); + } + + // See CASSANDRA-7525 + @Test + public void testQueryMultipleIndexTypes() throws Throwable + { + createTable("CREATE TABLE %s (account text, id int, categories map, PRIMARY KEY (account, id))"); + + // create an index on + createIndex("CREATE INDEX id_index ON %s(id)"); + createIndex("CREATE INDEX categories_values_index ON %s(categories)"); + + execute("INSERT INTO %s (account, id , categories) VALUES (?, ?, ?)", "test", 5, map("lmn", "foo")); + + assertRows(execute("SELECT * FROM %s WHERE categories CONTAINS ? AND id = ? ALLOW FILTERING", "foo", 5), + row("test", 5, map("lmn", "foo")) + ); + + assertRows( + execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ? AND id = ? ALLOW FILTERING", "test", "foo", 5), + row("test", 5, map("lmn", "foo")) + ); + } + + // See CASSANDRA-8033 + @Test + public void testFilterForContains() throws Throwable + { + createTable("CREATE TABLE %s (k1 int, k2 int, v set, 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)); + + assertRows(execute("SELECT * FROM %s WHERE k2 = ?", 1), + 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", 1, 7)); + } + + // See CASSANDRA-8073 + @Test + public void testIndexLookupWithClusteringPrefix() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, d set, PRIMARY KEY (a, b, c))"); + createIndex("CREATE INDEX ON %s(d)"); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 0, set(1, 2, 3)); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 1, set(3, 4, 5)); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 0, set(1, 2, 3)); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 1, set(3, 4, 5)); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b=? AND d CONTAINS ?", 0, 1, 3), + row(0, 1, 0, set(1, 2, 3)), + row(0, 1, 1, set(3, 4, 5)) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b=? AND d CONTAINS ?", 0, 1, 2), + row(0, 1, 0, set(1, 2, 3)) + ); + + assertRows(execute("SELECT * FROM %s WHERE a=? AND b=? AND d CONTAINS ?", 0, 1, 5), + row(0, 1, 1, set(3, 4, 5)) + ); + } + + @Test + public void testContainsKeyAndContainsWithIndexOnMapKey() throws Throwable + { + createTable("CREATE TABLE %s (account text, id int, categories map, PRIMARY KEY (account, id))"); + createIndex("CREATE INDEX ON %s(keys(categories))"); + + 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")); + + assertInvalidMessage("No secondary indexes on the restricted columns support the provided operators: 'categories CONTAINS '", + "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")), + row("test", 6, map("lmn", "foo2"))); + assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS KEY ? AND categories CONTAINS ? ALLOW FILTERING", + "test", "lmn", "foo"), + row("test", 5, map("lmn", "foo"))); + assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ? AND categories CONTAINS KEY ? ALLOW FILTERING", + "test", "foo", "lmn"), + row("test", 5, map("lmn", "foo"))); + } + + @Test + public void testContainsKeyAndContainsWithIndexOnMapValue() throws Throwable + { + createTable("CREATE TABLE %s (account text, id int, categories map, PRIMARY KEY (account, id))"); + createIndex("CREATE INDEX ON %s(categories)"); + + 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")); + + assertInvalidMessage("No secondary indexes on the restricted columns support the provided operators: 'categories CONTAINS KEY '", + "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")), + row("test", 6, map("lmn2", "foo"))); + assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS KEY ? AND categories CONTAINS ? ALLOW FILTERING", + "test", "lmn", "foo"), + row("test", 5, map("lmn", "foo"))); + assertRows(execute("SELECT * FROM %s WHERE account = ? AND categories CONTAINS ? AND categories CONTAINS KEY ? ALLOW FILTERING", + "test", "foo", "lmn"), + row("test", 5, map("lmn", "foo"))); + } + + /** + * Test token ranges + * migrated from cql_tests.py:TestCQL.token_range_test() + */ + @Test + public void testTokenRange() throws Throwable + { + createTable(" CREATE TABLE %s (k int PRIMARY KEY, c int, v int)"); + + int c = 100; + for (int i = 0; i < c; i++) + execute("INSERT INTO %s (k, c, v) VALUES (?, ?, ?)", i, i, i); + + Object[][] res = getRows(execute("SELECT k FROM %s")); + assertEquals(c, res.length); + + Object[] inOrder = new Object[res.length]; + for (int i = 0; i < res.length; i++) + inOrder[i] = res[i][0]; + + Long min_token = Long.MIN_VALUE; + + res = getRows(execute(String.format("SELECT k FROM %s.%s WHERE token(k) >= %d", + keyspace(), currentTable(), min_token))); + assertEquals(c, res.length); + + res = getRows(execute(String.format("SELECT k FROM %s.%s WHERE token(k) >= token(%d) AND token(k) < token(%d)", + keyspace(), currentTable(), inOrder[32], inOrder[65]))); + + for (int i = 32; i < 65; i++) + Assert.assertEquals(inOrder[i], res[i - 32][0]); + } + + /** + * Test select count + * migrated from cql_tests.py:TestCQL.count_test() + */ + @Test + public void testSelectCount() throws Throwable + { + createTable(" CREATE TABLE %s (kind text, time int, value1 int, value2 int, PRIMARY KEY(kind, time))"); + + execute("INSERT INTO %s (kind, time, value1, value2) VALUES ('ev1', ?, ?, ?)", 0, 0, 0); + execute("INSERT INTO %s (kind, time, value1, value2) VALUES ('ev1', ?, ?, ?)", 1, 1, 1); + execute("INSERT INTO %s (kind, time, value1) VALUES ('ev1', ?, ?)", 2, 2); + execute("INSERT INTO %s (kind, time, value1, value2) VALUES ('ev1', ?, ?, ?)", 3, 3, 3); + execute("INSERT INTO %s (kind, time, value1) VALUES ('ev1', ?, ?)", 4, 4); + execute("INSERT INTO %s (kind, time, value1, value2) VALUES ('ev2', 0, 0, 0)"); + + assertRows(execute("SELECT COUNT(*) FROM %s WHERE kind = 'ev1'"), + row(5L)); + + assertRows(execute("SELECT COUNT(1) FROM %s WHERE kind IN ('ev1', 'ev2') AND time=0"), + row(2L)); + } + + /** + * Range test query from #4372 + * migrated from cql_tests.py:TestCQL.range_query_test() + */ + @Test + public void testRangeQuery() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, d int, e int, f text, PRIMARY KEY (a, b, c, d, e) )"); + + execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (1, 1, 1, 1, 2, '2')"); + execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (1, 1, 1, 1, 1, '1')"); + execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (1, 1, 1, 2, 1, '1')"); + execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (1, 1, 1, 1, 3, '3')"); + execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (1, 1, 1, 1, 5, '5')"); + + assertRows(execute("SELECT a, b, c, d, e, f FROM %s WHERE a = 1 AND b = 1 AND c = 1 AND d = 1 AND e >= 2"), + row(1, 1, 1, 1, 2, "2"), + row(1, 1, 1, 1, 3, "3"), + row(1, 1, 1, 1, 5, "5")); + } + + /** + * Migrated from cql_tests.py:TestCQL.composite_row_key_test() + */ + @Test + public void testCompositeRowKey() throws Throwable + { + createTable("CREATE TABLE %s (k1 int, k2 int, c int, v int, PRIMARY KEY ((k1, k2), c))"); + + for (int i = 0; i < 4; i++) + execute("INSERT INTO %s (k1, k2, c, v) VALUES (?, ?, ?, ?)", 0, i, i, i); + + assertRows(execute("SELECT * FROM %s"), + row(0, 2, 2, 2), + row(0, 3, 3, 3), + row(0, 0, 0, 0), + row(0, 1, 1, 1)); + + assertRows(execute("SELECT * FROM %s WHERE k1 = 0 and k2 IN (1, 3)"), + row(0, 1, 1, 1), + row(0, 3, 3, 3)); + + assertInvalid("SELECT * FROM %s WHERE k2 = 3"); + + assertRows(execute("SELECT * FROM %s WHERE token(k1, k2) = token(0, 1)"), + row(0, 1, 1, 1)); + + + assertRows(execute("SELECT * FROM %s WHERE token(k1, k2) > ?", Long.MIN_VALUE), + row(0, 2, 2, 2), + row(0, 3, 3, 3), + row(0, 0, 0, 0), + row(0, 1, 1, 1)); + } + + /** + * Test for #4532, NPE when trying to select a slice from a composite table + * migrated from cql_tests.py:TestCQL.bug_4532_test() + */ + @Test + public void testSelectSliceFromComposite() throws Throwable + { + createTable("CREATE TABLE %s (status ascii, ctime bigint, key ascii, nil ascii, PRIMARY KEY (status, ctime, key))"); + + execute("INSERT INTO %s (status,ctime,key,nil) VALUES ('C',12345678,'key1','')"); + execute("INSERT INTO %s (status,ctime,key,nil) VALUES ('C',12345678,'key2','')"); + execute("INSERT INTO %s (status,ctime,key,nil) VALUES ('C',12345679,'key3','')"); + execute("INSERT INTO %s (status,ctime,key,nil) VALUES ('C',12345679,'key4','')"); + execute("INSERT INTO %s (status,ctime,key,nil) VALUES ('C',12345679,'key5','')"); + execute("INSERT INTO %s (status,ctime,key,nil) VALUES ('C',12345680,'key6','')"); + + assertInvalid("SELECT * FROM %s WHERE ctime>=12345679 AND key='key3' AND ctime<=12345680 LIMIT 3;"); + assertInvalid("SELECT * FROM %s WHERE ctime=12345679 AND key='key3' AND ctime<=12345680 LIMIT 3"); + } + + /** + * Test for #4716 bug and more generally for good behavior of ordering, + * migrated from cql_tests.py:TestCQL.reversed_compact_test() + */ + @Test + public void testReverseCompact() throws Throwable + { + createTable("CREATE TABLE %s ( k text, c int, v int, PRIMARY KEY (k, c) ) WITH COMPACT STORAGE AND CLUSTERING ORDER BY (c DESC)"); + + for (int i = 0; i < 10; i++) + execute("INSERT INTO %s (k, c, v) VALUES ('foo', ?, ?)", i, i); + + assertRows(execute("SELECT c FROM %s WHERE c > 2 AND c < 6 AND k = 'foo'"), + row(5), row(4), row(3)); + + assertRows(execute("SELECT c FROM %s WHERE c >= 2 AND c <= 6 AND k = 'foo'"), + row(6), row(5), row(4), row(3), row(2)); + + assertRows(execute("SELECT c FROM %s WHERE c > 2 AND c < 6 AND k = 'foo' ORDER BY c ASC"), + row(3), row(4), row(5)); + + assertRows(execute("SELECT c FROM %s WHERE c >= 2 AND c <= 6 AND k = 'foo' ORDER BY c ASC"), + row(2), row(3), row(4), row(5), row(6)); + + assertRows(execute("SELECT c FROM %s WHERE c > 2 AND c < 6 AND k = 'foo' ORDER BY c DESC"), + row(5), row(4), row(3)); + + assertRows(execute("SELECT c FROM %s WHERE c >= 2 AND c <= 6 AND k = 'foo' ORDER BY c DESC"), + row(6), row(5), row(4), row(3), row(2)); + + createTable("CREATE TABLE %s ( k text, c int, v int, PRIMARY KEY (k, c) ) WITH COMPACT STORAGE"); + + for (int i = 0; i < 10; i++) + execute("INSERT INTO %s(k, c, v) VALUES ('foo', ?, ?)", i, i); + + assertRows(execute("SELECT c FROM %s WHERE c > 2 AND c < 6 AND k = 'foo'"), + row(3), row(4), row(5)); + + assertRows(execute("SELECT c FROM %s WHERE c >= 2 AND c <= 6 AND k = 'foo'"), + row(2), row(3), row(4), row(5), row(6)); + + assertRows(execute("SELECT c FROM %s WHERE c > 2 AND c < 6 AND k = 'foo' ORDER BY c ASC"), + row(3), row(4), row(5)); + + assertRows(execute("SELECT c FROM %s WHERE c >= 2 AND c <= 6 AND k = 'foo' ORDER BY c ASC"), + row(2), row(3), row(4), row(5), row(6)); + + assertRows(execute("SELECT c FROM %s WHERE c > 2 AND c < 6 AND k = 'foo' ORDER BY c DESC"), + row(5), row(4), row(3)); + + assertRows(execute("SELECT c FROM %s WHERE c >= 2 AND c <= 6 AND k = 'foo' ORDER BY c DESC"), + row(6), row(5), row(4), row(3), row(2)); + } + + /** + * Test for the bug from #4760 and #4759, + * migrated from cql_tests.py:TestCQL.reversed_compact_multikey_test() + */ + @Test + public void testReversedCompactMultikey() throws Throwable + { + createTable("CREATE TABLE %s (key text, c1 int, c2 int, value text, PRIMARY KEY(key, c1, c2) ) WITH COMPACT STORAGE AND CLUSTERING ORDER BY(c1 DESC, c2 DESC)"); + + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + execute("INSERT INTO %s (key, c1, c2, value) VALUES ('foo', ?, ?, 'bar')", i, j); + + // Equalities + assertRows(execute("SELECT c1, c2 FROM %s WHERE key='foo' AND c1 = 1"), + row(1, 2), row(1, 1), row(1, 0)); + + assertRows(execute("SELECT c1, c2 FROM %s WHERE key='foo' AND c1 = 1 ORDER BY c1 ASC, c2 ASC"), + row(1, 0), row(1, 1), row(1, 2)); + + assertRows(execute("SELECT c1, c2 FROM %s WHERE key='foo' AND c1 = 1 ORDER BY c1 DESC, c2 DESC"), + row(1, 2), row(1, 1), row(1, 0)); + + // GT + assertRows(execute("SELECT c1, c2 FROM %s WHERE key='foo' AND c1 > 1"), + row(2, 2), row(2, 1), row(2, 0)); + + assertRows(execute("SELECT c1, c2 FROM %s WHERE key='foo' AND c1 > 1 ORDER BY c1 ASC, c2 ASC"), + row(2, 0), row(2, 1), row(2, 2)); + + assertRows(execute("SELECT c1, c2 FROM %s WHERE key='foo' AND c1 > 1 ORDER BY c1 DESC, c2 DESC"), + row(2, 2), row(2, 1), row(2, 0)); + + assertRows(execute("SELECT c1, c2 FROM %s WHERE key='foo' AND c1 >= 1"), + row(2, 2), row(2, 1), row(2, 0), row(1, 2), row(1, 1), row(1, 0)); + + assertRows(execute("SELECT c1, c2 FROM %s WHERE key='foo' AND c1 >= 1 ORDER BY c1 ASC, c2 ASC"), + row(1, 0), row(1, 1), row(1, 2), row(2, 0), row(2, 1), row(2, 2)); + + assertRows(execute("SELECT c1, c2 FROM %s WHERE key='foo' AND c1 >= 1 ORDER BY c1 ASC"), + row(1, 0), row(1, 1), row(1, 2), row(2, 0), row(2, 1), row(2, 2)); + + assertRows(execute("SELECT c1, c2 FROM %s WHERE key='foo' AND c1 >= 1 ORDER BY c1 DESC, c2 DESC"), + row(2, 2), row(2, 1), row(2, 0), row(1, 2), row(1, 1), row(1, 0)); + + // LT + assertRows(execute("SELECT c1, c2 FROM %s WHERE key='foo' AND c1 < 1"), + row(0, 2), row(0, 1), row(0, 0)); + + assertRows(execute("SELECT c1, c2 FROM %s WHERE key='foo' AND c1 < 1 ORDER BY c1 ASC, c2 ASC"), + row(0, 0), row(0, 1), row(0, 2)); + + assertRows(execute("SELECT c1, c2 FROM %s WHERE key='foo' AND c1 < 1 ORDER BY c1 DESC, c2 DESC"), + row(0, 2), row(0, 1), row(0, 0)); + + assertRows(execute("SELECT c1, c2 FROM %s WHERE key='foo' AND c1 <= 1"), + row(1, 2), row(1, 1), row(1, 0), row(0, 2), row(0, 1), row(0, 0)); + + assertRows(execute("SELECT c1, c2 FROM %s WHERE key='foo' AND c1 <= 1 ORDER BY c1 ASC, c2 ASC"), + row(0, 0), row(0, 1), row(0, 2), row(1, 0), row(1, 1), row(1, 2)); + + assertRows(execute("SELECT c1, c2 FROM %s WHERE key='foo' AND c1 <= 1 ORDER BY c1 ASC"), + row(0, 0), row(0, 1), row(0, 2), row(1, 0), row(1, 1), row(1, 2)); + + assertRows(execute("SELECT c1, c2 FROM %s WHERE key='foo' AND c1 <= 1 ORDER BY c1 DESC, c2 DESC"), + row(1, 2), row(1, 1), row(1, 0), row(0, 2), row(0, 1), row(0, 0)); + } + + /** + * Migrated from cql_tests.py:TestCQL.bug_4882_test() + */ + @Test + public void testDifferentOrdering() throws Throwable + { + createTable(" CREATE TABLE %s ( k int, c1 int, c2 int, v int, PRIMARY KEY (k, c1, c2) ) WITH CLUSTERING ORDER BY (c1 ASC, c2 DESC)"); + + execute("INSERT INTO %s (k, c1, c2, v) VALUES (0, 0, 0, 0)"); + execute("INSERT INTO %s (k, c1, c2, v) VALUES (0, 1, 1, 1)"); + execute("INSERT INTO %s (k, c1, c2, v) VALUES (0, 0, 2, 2)"); + execute("INSERT INTO %s (k, c1, c2, v) VALUES (0, 1, 3, 3)"); + + assertRows(execute("select * from %s where k = 0 limit 1"), + row(0, 0, 2, 2)); + } + + /** + * Migrated from cql_tests.py:TestCQL.allow_filtering_test() + */ + @Test + public void testAllowFiltering() throws Throwable + { + createTable("CREATE TABLE %s (k int, c int, v int, PRIMARY KEY (k, c))"); + + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + execute("INSERT INTO %s (k, c, v) VALUES (?, ?, ?)", i, j, j); + + // Don't require filtering, always allowed + String[] queries = new String[] + { + "SELECT * FROM %s WHERE k = 1", + "SELECT * FROM %s WHERE k = 1 AND c > 2", + "SELECT * FROM %s WHERE k = 1 AND c = 2" + }; + + for (String q : queries) + { + execute(q); + execute(q + " ALLOW FILTERING"); + } + + // Require filtering, allowed only with ALLOW FILTERING + queries = new String[] + { + "SELECT * FROM %s WHERE c = 2", + "SELECT * FROM %s WHERE c > 2 AND c <= 4" + }; + + for (String q : queries) + { + assertInvalid(q); + execute(q + " ALLOW FILTERING"); + } + + createTable("CREATE TABLE %s (k int PRIMARY KEY, a int, b int,)"); + createIndex("CREATE INDEX ON %s (a)"); + + for (int i = 0; i < 5; i++) + execute("INSERT INTO %s (k, a, b) VALUES (?, ?, ?)", i, i * 10, i * 100); + + // Don't require filtering, always allowed + queries = new String[] + { + "SELECT * FROM %s WHERE k = 1", + "SELECT * FROM %s WHERE a = 20" + }; + + for (String q : queries) + { + execute(q); + execute(q + " ALLOW FILTERING"); + } + + // Require filtering, allowed only with ALLOW FILTERING + queries = new String[] + { + "SELECT * FROM %s WHERE a = 20 AND b = 200" + }; + + for (String q : queries) + { + assertInvalid(q); + execute(q + " ALLOW FILTERING"); + } + } + + /** + * Test for bug from #5122, + * migrated from cql_tests.py:TestCQL.composite_partition_key_validation_test() + */ + @Test + public void testSelectOnCompositeInvalid() throws Throwable + { + createTable("CREATE TABLE %s (a int, b text, c uuid, PRIMARY KEY ((a, b)))"); + + execute("INSERT INTO %s (a, b , c ) VALUES (1, 'aze', 4d481800-4c5f-11e1-82e0-3f484de45426)"); + execute("INSERT INTO %s (a, b , c ) VALUES (1, 'ert', 693f5800-8acb-11e3-82e0-3f484de45426)"); + execute("INSERT INTO %s (a, b , c ) VALUES (1, 'opl', d4815800-2d8d-11e0-82e0-3f484de45426)"); + + assertRowCount(execute("SELECT * FROM %s"), 3); + assertInvalid("SELECT * FROM %s WHERE a=1"); + } + + /** + * Migrated from cql_tests.py:TestCQL.multi_in_test() + */ + @Test + public void testMultiSelects() throws Throwable + { + doTestVariousSelects(false); + } + + /** + * Migrated from cql_tests.py:TestCQL.multi_in_compact_test() + */ + @Test + public void testMultiSelectsCompactStorage() throws Throwable + { + doTestVariousSelects(true); + } + + + public void doTestVariousSelects(boolean compact) throws Throwable + { + createTable( + "CREATE TABLE %s (group text, zipcode text, state text, fips_regions int, city text, PRIMARY KEY (group, zipcode, state, fips_regions))" + + (compact + ? " WITH COMPACT STORAGE" + : "")); + + String str = "INSERT INTO %s (group, zipcode, state, fips_regions, city) VALUES (?, ?, ?, ?, ?)"; + execute(str, "test", "06029", "CT", 9, "Ellington"); + execute(str, "test", "06031", "CT", 9, "Falls Village"); + execute(str, "test", "06902", "CT", 9, "Stamford"); + execute(str, "test", "06927", "CT", 9, "Stamford"); + execute(str, "test", "10015", "NY", 36, "New York"); + execute(str, "test", "07182", "NJ", 34, "Newark"); + execute(str, "test", "73301", "TX", 48, "Austin"); + execute(str, "test", "94102", "CA", 06, "San Francisco"); + + execute(str, "test2", "06029", "CT", 9, "Ellington"); + execute(str, "test2", "06031", "CT", 9, "Falls Village"); + execute(str, "test2", "06902", "CT", 9, "Stamford"); + execute(str, "test2", "06927", "CT", 9, "Stamford"); + execute(str, "test2", "10015", "NY", 36, "New York"); + execute(str, "test2", "07182", "NJ", 34, "Newark"); + execute(str, "test2", "73301", "TX", 48, "Austin"); + execute(str, "test2", "94102", "CA", 06, "San Francisco"); + + assertRowCount(execute("select zipcode from %s"), 16); + assertRowCount(execute("select zipcode from %s where group='test'"), 8); + assertInvalid("select zipcode from %s where zipcode='06902'"); + assertRowCount(execute("select zipcode from %s where zipcode='06902' ALLOW FILTERING"), 2); + assertRowCount(execute("select zipcode from %s where group='test' and zipcode='06902'"), 1); + assertRowCount(execute("select zipcode from %s where group='test' and zipcode IN ('06902','73301','94102')"), 3); + assertRowCount(execute("select zipcode from %s where group='test' AND zipcode IN ('06902','73301','94102') and state IN ('CT','CA')"), 2); + assertRowCount(execute("select zipcode from %s where group='test' AND zipcode IN ('06902','73301','94102') and state IN ('CT','CA') and fips_regions = 9"), 1); + assertRowCount(execute("select zipcode from %s where group='test' AND zipcode IN ('06902','73301','94102') and state IN ('CT','CA') ORDER BY zipcode DESC"), 2); + assertRowCount(execute("select zipcode from %s where group='test' AND zipcode IN ('06902','73301','94102') and state IN ('CT','CA') and fips_regions > 0"), 2); + assertEmpty(execute("select zipcode from %s where group='test' AND zipcode IN ('06902','73301','94102') and state IN ('CT','CA') and fips_regions < 0")); + } + + /** + * Migrated from cql_tests.py:TestCQL.multi_in_compact_non_composite_test() + */ + @Test + public void testMultiSelectsNonCompositeCompactStorage() throws Throwable + { + createTable("CREATE TABLE %s (key int, c int, v int, PRIMARY KEY (key, c)) WITH COMPACT STORAGE"); + + execute("INSERT INTO %s (key, c, v) VALUES (0, 0, 0)"); + execute("INSERT INTO %s (key, c, v) VALUES (0, 1, 1)"); + execute("INSERT INTO %s (key, c, v) VALUES (0, 2, 2)"); + + assertRows(execute("SELECT * FROM %s WHERE key=0 AND c IN (0, 2)"), + row(0, 0, 0), row(0, 2, 2)); + } + + /** + * Migrated from cql_tests.py:TestCQL.ticket_5230_test() + */ + @Test + public void testMultipleClausesOnPrimaryKey() throws Throwable + { + createTable("CREATE TABLE %s (key text, c text, v text, PRIMARY KEY(key, c))"); + + execute("INSERT INTO %s (key, c, v) VALUES ('foo', '1', '1')"); + execute("INSERT INTO %s(key, c, v) VALUES ('foo', '2', '2')"); + execute("INSERT INTO %s(key, c, v) VALUES ('foo', '3', '3')"); + + assertRows(execute("SELECT c FROM %s WHERE key = 'foo' AND c IN ('1', '2')"), + row("1"), row("2")); + } + + /** + * Migrated from cql_tests.py:TestCQL.bug_5404() + */ + @Test + public void testSelectWithToken() throws Throwable + { + createTable("CREATE TABLE %s (key text PRIMARY KEY)"); + + // We just want to make sure this doesn 't NPE server side + assertInvalid("select * from %s where token(key) > token(int(3030343330393233)) limit 1"); + } + + /** + * Migrated from cql_tests.py:TestCQL.clustering_order_and_functions_test() + */ + @Test + public void testFunctionsWithClusteringDesc() throws Throwable + { + createTable("CREATE TABLE %s ( k int, t timeuuid, PRIMARY KEY (k, t) ) WITH CLUSTERING ORDER BY (t DESC)"); + + for (int i = 0; i < 5; i++) + execute("INSERT INTO %s (k, t) VALUES (?, now())", i); + + execute("SELECT dateOf(t) FROM %s"); + } + + /** + * Migrated from cql_tests.py:TestCQL.select_with_alias_test() + */ + @Test + public void testSelectWithAlias() throws Throwable + { + createTable("CREATE TABLE %s (id int PRIMARY KEY, name text)"); + + for (int id = 0; id < 5; id++) + execute("INSERT INTO %s (id, name) VALUES (?, ?) USING TTL 10 AND TIMESTAMP 0", id, "name" + id); + + // test aliasing count( *) + UntypedResultSet rs = execute("SELECT count(*) AS user_count FROM %s"); + assertEquals("user_count", rs.metadata().get(0).name.toString()); + assertEquals(5L, rs.one().getLong(rs.metadata().get(0).name.toString())); + + // test aliasing regular value + rs = execute("SELECT name AS user_name FROM %s WHERE id = 0"); + assertEquals("user_name", rs.metadata().get(0).name.toString()); + assertEquals("name0", rs.one().getString(rs.metadata().get(0).name.toString())); + + // test aliasing writetime + rs = execute("SELECT writeTime(name) AS name_writetime FROM %s WHERE id = 0"); + assertEquals("name_writetime", rs.metadata().get(0).name.toString()); + assertEquals(0, rs.one().getInt(rs.metadata().get(0).name.toString())); + + // test aliasing ttl + rs = execute("SELECT ttl(name) AS name_ttl FROM %s WHERE id = 0"); + assertEquals("name_ttl", rs.metadata().get(0).name.toString()); + int ttl = rs.one().getInt(rs.metadata().get(0).name.toString()); + assertTrue(ttl == 9 || ttl == 10); + + // test aliasing a regular function + rs = execute("SELECT intAsBlob(id) AS id_blob FROM %s WHERE id = 0"); + assertEquals("id_blob", rs.metadata().get(0).name.toString()); + assertEquals(ByteBuffer.wrap(new byte[4]), rs.one().getBlob(rs.metadata().get(0).name.toString())); + + // test that select throws a meaningful exception for aliases in where clause + 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"); + } + + /** + * Migrated from cql_tests.py:TestCQL.select_distinct_test() + */ + @Test + public void testSelectDistinct() throws Throwable + { + // Test a regular(CQL3) table. + createTable("CREATE TABLE %s (pk0 int, pk1 int, ck0 int, val int, PRIMARY KEY((pk0, pk1), ck0))"); + + for (int i = 0; i < 3; i++) + { + execute("INSERT INTO %s (pk0, pk1, ck0, val) VALUES (?, ?, 0, 0)", i, i); + execute("INSERT INTO %s (pk0, pk1, ck0, val) VALUES (?, ?, 1, 1)", i, i); + } + + assertRows(execute("SELECT DISTINCT pk0, pk1 FROM %s LIMIT 1"), + row(0, 0)); + + assertRows(execute("SELECT DISTINCT pk0, pk1 FROM %s LIMIT 3"), + row(0, 0), + row(2, 2), + row(1, 1)); + + // Test selection validation. + assertInvalidMessage("queries must request all the partition key columns", "SELECT DISTINCT pk0 FROM %s"); + assertInvalidMessage("queries must only request partition key columns", "SELECT DISTINCT pk0, pk1, ck0 FROM %s"); + + //Test a 'compact storage' table. + createTable("CREATE TABLE %s (pk0 int, pk1 int, val int, PRIMARY KEY((pk0, pk1))) WITH COMPACT STORAGE"); + + for (int i = 0; i < 3; i++) + execute("INSERT INTO %s (pk0, pk1, val) VALUES (?, ?, ?)", i, i, i); + + assertRows(execute("SELECT DISTINCT pk0, pk1 FROM %s LIMIT 1"), + row(0, 0)); + + assertRows(execute("SELECT DISTINCT pk0, pk1 FROM %s LIMIT 3"), + row(0, 0), + row(2, 2), + row(1, 1)); + + // Test a 'wide row' thrift table. + createTable("CREATE TABLE %s (pk int, name text, val int, PRIMARY KEY(pk, name)) WITH COMPACT STORAGE"); + + for (int i = 0; i < 3; i++) + { + execute("INSERT INTO %s (pk, name, val) VALUES (?, 'name0', 0)", i); + execute("INSERT INTO %s (pk, name, val) VALUES (?, 'name1', 1)", i); + } + + assertRows(execute("SELECT DISTINCT pk FROM %s LIMIT 1"), + row(1)); + + assertRows(execute("SELECT DISTINCT pk FROM %s LIMIT 3"), + row(1), + row(0), + row(2)); + } + + /** + * Migrated from cql_tests.py:TestCQL.select_distinct_with_deletions_test() + */ + @Test + public void testSelectDistinctWithDeletions() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, c int, v int)"); + + for (int i = 0; i < 10; i++) + execute("INSERT INTO %s (k, c, v) VALUES (?, ?, ?)", i, i, i); + + Object[][] rows = getRows(execute("SELECT DISTINCT k FROM %s")); + Assert.assertEquals(10, rows.length); + Object key_to_delete = rows[3][0]; + + execute("DELETE FROM %s WHERE k=?", key_to_delete); + + rows = getRows(execute("SELECT DISTINCT k FROM %s")); + Assert.assertEquals(9, rows.length); + + rows = getRows(execute("SELECT DISTINCT k FROM %s LIMIT 5")); + Assert.assertEquals(5, rows.length); + + rows = getRows(execute("SELECT DISTINCT k FROM %s")); + Assert.assertEquals(9, rows.length); + } + + /** + * Migrated from cql_tests.py:TestCQL.bug_6327_test() + */ + @Test + public void testSelectInClauseAtOne() throws Throwable + { + createTable("CREATE TABLE %s ( k int, v int, PRIMARY KEY (k, v))"); + + execute("INSERT INTO %s (k, v) VALUES (0, 0)"); + + flush(); + + assertRows(execute("SELECT v FROM %s WHERE k=0 AND v IN (1, 0)"), + row(0)); + } + + /** + * Test for the #6579 'select count' paging bug, + * migrated from cql_tests.py:TestCQL.select_count_paging_test() + */ + @Test + public void testSelectCountPaging() throws Throwable + { + createTable("create table %s (field1 text, field2 timeuuid, field3 boolean, primary key(field1, field2))"); + createIndex("create index test_index on %s (field3)"); + + execute("insert into %s (field1, field2, field3) values ('hola', now(), false)"); + execute("insert into %s (field1, field2, field3) values ('hola', now(), false)"); + + assertRows(execute("select count(*) from %s where field3 = false limit 1"), + row(2L)); + } + + /** + * Test for #7105 bug, + * migrated from cql_tests.py:TestCQL.clustering_order_in_test() + */ + @Test + public void testClusteringOrder() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY ((a, b), c) ) with clustering order by (c desc)"); + + execute("INSERT INTO %s (a, b, c) VALUES (1, 2, 3)"); + execute("INSERT INTO %s (a, b, c) VALUES (4, 5, 6)"); + + assertRows(execute("SELECT * FROM %s WHERE a=1 AND b=2 AND c IN (3)"), + row(1, 2, 3)); + assertRows(execute("SELECT * FROM %s WHERE a=1 AND b=2 AND c IN (3, 4)"), + row(1, 2, 3)); + } + + /** + * Test for #7105 bug, + * SELECT with IN on final column of composite and compound primary key fails + * migrated from cql_tests.py:TestCQL.bug7105_test() + */ + @Test + public void testSelectInFinalColumn() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY (a, b))"); + + execute("INSERT INTO %s (a, b, c, d) VALUES (1, 2, 3, 3)"); + execute("INSERT INTO %s (a, b, c, d) VALUES (1, 4, 6, 5)"); + + assertRows(execute("SELECT * FROM %s WHERE a=1 AND b=2 ORDER BY b DESC"), + row(1, 2, 3, 3)); + } + + @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"); + + } +} diff --git a/test/unit/org/apache/cassandra/cql3/TypeCastTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/UpdateTest.java similarity index 56% rename from test/unit/org/apache/cassandra/cql3/TypeCastTest.java rename to test/unit/org/apache/cassandra/cql3/validation/operations/UpdateTest.java index 7b9c9a22ff..c5d153f171 100644 --- a/test/unit/org/apache/cassandra/cql3/TypeCastTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/UpdateTest.java @@ -15,16 +15,48 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; + +package org.apache.cassandra.cql3.validation.operations; import org.junit.Test; -/** - * Type-casting is mostly using for functions and their use with functions is - * tested in UFTest. This is a few additional "sanity" tests. - */ -public class TypeCastTest extends CQLTester +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.utils.ByteBufferUtil; + +public class UpdateTest extends CQLTester { + /** + * Test altering the type of a column, including the one in the primary key (#4041) + * migrated from cql_tests.py:TestCQL.update_type_test() + */ + @Test + public void testUpdateColumnType() throws Throwable + { + createTable("CREATE TABLE %s (k text, c text, s set , v text, PRIMARY KEY(k, c))"); + + // using utf8 character so that we can see the transition to BytesType + execute("INSERT INTO %s (k, c, v, s) VALUES ('ɸ', 'ɸ', 'ɸ', {'ɸ'})"); + + assertRows(execute("SELECT * FROM %s"), + row("ɸ", "ɸ", set("ɸ"), "ɸ")); + + execute("ALTER TABLE %s ALTER v TYPE blob"); + assertRows(execute("SELECT * FROM %s"), + row("ɸ", "ɸ", set("ɸ"), ByteBufferUtil.bytes("ɸ"))); + + execute("ALTER TABLE %s ALTER k TYPE blob"); + assertRows(execute("SELECT * FROM %s"), + row(ByteBufferUtil.bytes("ɸ"), "ɸ", set("ɸ"), ByteBufferUtil.bytes("ɸ"))); + + execute("ALTER TABLE %s ALTER c TYPE blob"); + assertRows(execute("SELECT * FROM %s"), + row(ByteBufferUtil.bytes("ɸ"), ByteBufferUtil.bytes("ɸ"), set("ɸ"), ByteBufferUtil.bytes("ɸ"))); + + execute("ALTER TABLE %s ALTER s TYPE set"); + assertRows(execute("SELECT * FROM %s"), + row(ByteBufferUtil.bytes("ɸ"), ByteBufferUtil.bytes("ɸ"), set(ByteBufferUtil.bytes("ɸ")), ByteBufferUtil.bytes("ɸ"))); + } + @Test public void testTypeCasts() throws Throwable { diff --git a/test/unit/org/apache/cassandra/cql3/UseStatementTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/UseTest.java similarity index 87% rename from test/unit/org/apache/cassandra/cql3/UseStatementTest.java rename to test/unit/org/apache/cassandra/cql3/validation/operations/UseTest.java index 66b4b42f3a..e1498b65a3 100644 --- a/test/unit/org/apache/cassandra/cql3/UseStatementTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/UseTest.java @@ -15,11 +15,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.cassandra.cql3; +package org.apache.cassandra.cql3.validation.operations; import org.junit.Test; -public class UseStatementTest extends CQLTester +import org.apache.cassandra.cql3.CQLTester; + +public class UseTest extends CQLTester { @Test public void testUseStatementWithBindVariable() throws Throwable diff --git a/test/unit/org/apache/cassandra/service/ClientWarningsTest.java b/test/unit/org/apache/cassandra/service/ClientWarningsTest.java index da7577e516..363fc7d01f 100644 --- a/test/unit/org/apache/cassandra/service/ClientWarningsTest.java +++ b/test/unit/org/apache/cassandra/service/ClientWarningsTest.java @@ -22,8 +22,9 @@ import org.junit.BeforeClass; import org.junit.Test; import org.apache.cassandra.config.DatabaseDescriptor; -import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.cql3.QueryOptions; +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.dht.ByteOrderedPartitioner; import org.apache.cassandra.transport.Message; import org.apache.cassandra.transport.Server; import org.apache.cassandra.transport.SimpleClient; @@ -37,6 +38,8 @@ public class ClientWarningsTest extends CQLTester @BeforeClass public static void setUp() { + DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance); + requireNetwork(); DatabaseDescriptor.setBatchSizeWarnThresholdInKB(1); } diff --git a/test/unit/org/apache/cassandra/transport/MessagePayloadTest.java b/test/unit/org/apache/cassandra/transport/MessagePayloadTest.java index 73daa48e7c..1dd3c5da81 100644 --- a/test/unit/org/apache/cassandra/transport/MessagePayloadTest.java +++ b/test/unit/org/apache/cassandra/transport/MessagePayloadTest.java @@ -29,14 +29,16 @@ import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.cql3.BatchQueryOptions; import org.apache.cassandra.cql3.CQLStatement; -import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.cql3.QueryHandler; import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.QueryProcessor; import org.apache.cassandra.cql3.statements.BatchStatement; import org.apache.cassandra.cql3.statements.ParsedStatement; +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.dht.ByteOrderedPartitioner; import org.apache.cassandra.exceptions.RequestExecutionException; import org.apache.cassandra.exceptions.RequestValidationException; import org.apache.cassandra.service.ClientState; @@ -63,6 +65,8 @@ public class MessagePayloadTest extends CQLTester { try { + DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance); + cqlQueryHandlerField = ClientState.class.getDeclaredField("cqlQueryHandler"); cqlQueryHandlerField.setAccessible(true); diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/TimeUUIDs.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/TimeUUIDs.java index 7bfabf5056..537d54e46b 100644 --- a/tools/stress/src/org/apache/cassandra/stress/generate/values/TimeUUIDs.java +++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/TimeUUIDs.java @@ -46,6 +46,6 @@ public class TimeUUIDs extends Generator @Override public UUID generate() { - return UUIDGen.getTimeUUID(dateGen.generate().getTime(), clockSeqAndNode); + return UUIDGen.getTimeUUID(dateGen.generate().getTime(), 0L, clockSeqAndNode); } }