blob: b52caaa479ebb78325ef0f730343fd6b3a0ed0d6 [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.ConfigurationException;
import org.apache.cassandra.exceptions.InvalidRequestException;
public class CountersTest extends CQLTester
{
/**
* 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()));
}
@Test
public void testCannotAlterWithNonCounterColumn() throws Throwable
{
createTable("CREATE TABLE %s (k int PRIMARY KEY, c counter)");
assertInvalidThrowMessage("Cannot have a non counter column (\"t\") in a counter table",
ConfigurationException.class, formatQuery("ALTER TABLE %s ADD t text"));
createTable("CREATE TABLE %s (k int PRIMARY KEY, t text)");
assertInvalidThrowMessage("Cannot have a counter column (\"c\") in a non counter table",
ConfigurationException.class, formatQuery("ALTER TABLE %s ADD c counter"));
}
/**
* 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
{
createTable("CREATE TABLE %s (k int PRIMARY KEY, a counter)");
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
{
createTable("CREATE TABLE %s (k int PRIMARY KEY, a counter, b counter)");
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 column '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()));
}
/**
* Check that a counter batch works as intended
*/
@Test
public void testCounterBatch() throws Throwable
{
createTable("CREATE TABLE %s (userid int, url text, total counter, PRIMARY KEY (userid, url))");
// Ensure we handle updates to the same CQL row in the same partition properly
execute("BEGIN UNLOGGED BATCH " +
"UPDATE %1$s SET total = total + 1 WHERE userid = 1 AND url = 'http://foo.com'; " +
"UPDATE %1$s SET total = total + 1 WHERE userid = 1 AND url = 'http://foo.com'; " +
"UPDATE %1$s SET total = total + 1 WHERE userid = 1 AND url = 'http://foo.com'; " +
"APPLY BATCH; ");
assertRows(execute("SELECT total FROM %s WHERE userid = 1 AND url = 'http://foo.com'"),
row(3L));
// Ensure we handle different CQL rows in the same partition properly
execute("BEGIN UNLOGGED BATCH " +
"UPDATE %1$s SET total = total + 1 WHERE userid = 1 AND url = 'http://bar.com'; " +
"UPDATE %1$s SET total = total + 1 WHERE userid = 1 AND url = 'http://baz.com'; " +
"UPDATE %1$s SET total = total + 1 WHERE userid = 1 AND url = 'http://bad.com'; " +
"APPLY BATCH; ");
assertRows(execute("SELECT url, total FROM %s WHERE userid = 1"),
row("http://bad.com", 1L),
row("http://bar.com", 1L),
row("http://baz.com", 1L),
row("http://foo.com", 3L)); // from previous batch
// Different counters in the same CQL Row
createTable("CREATE TABLE %s (userid int, url text, first counter, second counter, third counter, PRIMARY KEY (userid, url))");
execute("BEGIN UNLOGGED BATCH " +
"UPDATE %1$s SET first = first + 1 WHERE userid = 1 AND url = 'http://foo.com'; " +
"UPDATE %1$s SET first = first + 1 WHERE userid = 1 AND url = 'http://foo.com'; " +
"UPDATE %1$s SET second = second + 1 WHERE userid = 1 AND url = 'http://foo.com'; " +
"APPLY BATCH; ");
assertRows(execute("SELECT first, second, third FROM %s WHERE userid = 1 AND url = 'http://foo.com'"),
row(2L, 1L, null));
// Different counters in different CQL Rows
execute("BEGIN UNLOGGED BATCH " +
"UPDATE %1$s SET first = first + 1 WHERE userid = 1 AND url = 'http://bad.com'; " +
"UPDATE %1$s SET first = first + 1, second = second + 1 WHERE userid = 1 AND url = 'http://bar.com'; " +
"UPDATE %1$s SET first = first - 1, second = second - 1 WHERE userid = 1 AND url = 'http://bar.com'; " +
"UPDATE %1$s SET second = second + 1 WHERE userid = 1 AND url = 'http://baz.com'; " +
"APPLY BATCH; ");
assertRows(execute("SELECT url, first, second, third FROM %s WHERE userid = 1"),
row("http://bad.com", 1L, null, null),
row("http://bar.com", 0L, 0L, null),
row("http://baz.com", null, 1L, null),
row("http://foo.com", 2L, 1L, null)); // from previous batch
// Different counters in different partitions
execute("BEGIN UNLOGGED BATCH " +
"UPDATE %1$s SET first = first + 1 WHERE userid = 2 AND url = 'http://bad.com'; " +
"UPDATE %1$s SET first = first + 1, second = second + 1 WHERE userid = 3 AND url = 'http://bar.com'; " +
"UPDATE %1$s SET first = first - 1, second = second - 1 WHERE userid = 4 AND url = 'http://bar.com'; " +
"UPDATE %1$s SET second = second + 1 WHERE userid = 5 AND url = 'http://baz.com'; " +
"APPLY BATCH; ");
assertRowsIgnoringOrder(execute("SELECT userid, url, first, second, third FROM %s WHERE userid IN (2, 3, 4, 5)"),
row(2, "http://bad.com", 1L, null, null),
row(3, "http://bar.com", 1L, 1L, null),
row(4, "http://bar.com", -1L, -1L, null),
row(5, "http://baz.com", null, 1L, null));
}
}