blob: 94e1c52e06ac6c3b001cb85cf7f092c50a22a259 [file] [log] [blame]
/*
* 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.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));
execute("UPDATE %s SET total += 6 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 -= 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 += -2 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 -= -2 WHERE userid = 1 AND url = 'http://foo.com'");
assertRows(execute("SELECT total FROM %s WHERE userid = 1 AND url = 'http://foo.com'"),
row(1L));
}
/**
* 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 mix counter and non counter columns in the same table",
InvalidRequestException.class,
String.format("CREATE TABLE %s.%s (id bigint PRIMARY KEY, count counter, things set<text>)", 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<counter>)", tableName));
tableName = KEYSPACE + "." + createTableName();
assertInvalidThrow(InvalidRequestException.class,
String.format("CREATE TABLE %s (k int PRIMARY KEY, s set<counter>)", tableName));
tableName = KEYSPACE + "." + createTableName();
assertInvalidThrow(InvalidRequestException.class,
String.format("CREATE TABLE %s (k int PRIMARY KEY, m map<text, counter>)", 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
);
}
@Test
public void testCounterFiltering() throws Throwable
{
for (String compactStorageClause : new String[]{ "", " WITH COMPACT STORAGE" })
{
createTable("CREATE TABLE %s (k int PRIMARY KEY, a counter)" + compactStorageClause);
for (int i = 0; i < 10; i++)
execute("UPDATE %s SET a = a + ? WHERE k = ?", (long) i, i);
execute("UPDATE %s SET a = a + ? WHERE k = ?", 6L, 10);
// GT
assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a > ? ALLOW FILTERING", 5L),
row(6, 6L),
row(7, 7L),
row(8, 8L),
row(9, 9L),
row(10, 6L));
// GTE
assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a >= ? ALLOW FILTERING", 6L),
row(6, 6L),
row(7, 7L),
row(8, 8L),
row(9, 9L),
row(10, 6L));
// LT
assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a < ? ALLOW FILTERING", 3L),
row(0, 0L),
row(1, 1L),
row(2, 2L));
// LTE
assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a <= ? ALLOW FILTERING", 3L),
row(0, 0L),
row(1, 1L),
row(2, 2L),
row(3, 3L));
// EQ
assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a = ? ALLOW FILTERING", 6L),
row(6, 6L),
row(10, 6L));
}
}
@Test
public void testCounterFilteringWithNull() throws Throwable
{
for (String compactStorageClause : new String[]{ "", " WITH COMPACT STORAGE" })
{
createTable("CREATE TABLE %s (k int PRIMARY KEY, a counter, b counter)" + compactStorageClause);
execute("UPDATE %s SET a = a + ? WHERE k = ?", 1L, 1);
assertRows(execute("SELECT * FROM %s WHERE a > ? ALLOW FILTERING", 0L),
row(1, 1L, null));
// GT
assertEmpty(execute("SELECT * FROM %s WHERE b > ? ALLOW FILTERING", 1L));
// GTE
assertEmpty(execute("SELECT * FROM %s WHERE b >= ? ALLOW FILTERING", 1L));
// LT
assertEmpty(execute("SELECT * FROM %s WHERE b < ? ALLOW FILTERING", 1L));
// LTE
assertEmpty(execute("SELECT * FROM %s WHERE b <= ? ALLOW FILTERING", 1L));
// EQ
assertEmpty(execute("SELECT * FROM %s WHERE b = ? ALLOW FILTERING", 1L));
// with null
assertInvalidMessage("Invalid null value for counter increment/decrement",
"SELECT * FROM %s WHERE b = null ALLOW FILTERING");
}
}
/**
* Test for the validation bug of #9395.
*/
@Test
public void testProhibitReversedCounterAsPartOfPrimaryKey() throws Throwable
{
assertInvalidThrowMessage("counter type is not supported for PRIMARY KEY part a",
InvalidRequestException.class, String.format("CREATE TABLE %s.%s (a counter, b int, PRIMARY KEY (b, a)) WITH CLUSTERING ORDER BY (a desc);", KEYSPACE, createTableName()));
}
/**
* Test for the bug of #11726.
*/
@Test
public void testCounterAndColumnSelection() throws Throwable
{
for (String compactStorageClause : new String[]{ "", " WITH COMPACT STORAGE" })
{
createTable("CREATE TABLE %s (k int PRIMARY KEY, c counter)" + compactStorageClause);
// Flush 2 updates in different sstable so that the following select does a merge, which is what triggers
// the problem from #11726
execute("UPDATE %s SET c = c + ? WHERE k = ?", 1L, 0);
flush();
execute("UPDATE %s SET c = c + ? WHERE k = ?", 1L, 0);
flush();
// Querying, but not including the counter. Pre-CASSANDRA-11726, this made us query the counter but include
// it's value, which broke at merge (post-CASSANDRA-11726 are special cases to never skip values).
assertRows(execute("SELECT k FROM %s"), row(0));
}
}
}