blob: 9978f1d0ae07d8f43baec95423a342fa664feed3 [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;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import com.google.common.util.concurrent.Uninterruptibles;
import junit.framework.Assert;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.exceptions.InvalidQueryException;
import org.apache.cassandra.SchemaLoader;
import org.apache.cassandra.concurrent.SEPExecutor;
import org.apache.cassandra.concurrent.Stage;
import org.apache.cassandra.concurrent.StageManager;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.db.ColumnFamilyStore;
import org.apache.cassandra.db.Keyspace;
import org.apache.cassandra.db.SystemKeyspace;
import org.apache.cassandra.db.compaction.CompactionManager;
import org.apache.cassandra.db.marshal.AsciiType;
import org.apache.cassandra.db.view.View;
import org.apache.cassandra.exceptions.SyntaxException;
import org.apache.cassandra.schema.KeyspaceParams;
import org.apache.cassandra.service.ClientWarn;
import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.utils.FBUtilities;
import static junit.framework.Assert.fail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class ViewTest extends CQLTester
{
ProtocolVersion protocolVersion = ProtocolVersion.V4;
private final List<String> views = new ArrayList<>();
@BeforeClass
public static void startup()
{
requireNetwork();
}
@Before
public void begin()
{
views.clear();
}
@After
public void end() throws Throwable
{
for (String viewName : views)
executeNet(protocolVersion, "DROP MATERIALIZED VIEW " + viewName);
}
private void createView(String name, String query) throws Throwable
{
executeNet(protocolVersion, String.format(query, name));
// If exception is thrown, the view will not be added to the list; since it shouldn't have been created, this is
// the desired behavior
views.add(name);
}
private void updateView(String query, Object... params) throws Throwable
{
executeNet(protocolVersion, query, params);
while (!(((SEPExecutor) StageManager.getStage(Stage.VIEW_MUTATION)).getPendingTasks() == 0
&& ((SEPExecutor) StageManager.getStage(Stage.VIEW_MUTATION)).getActiveCount() == 0))
{
Thread.sleep(1);
}
}
@Test
public void testNonExistingOnes() throws Throwable
{
assertInvalidMessage("Cannot drop non existing materialized view", "DROP MATERIALIZED VIEW " + KEYSPACE + ".view_does_not_exist");
assertInvalidMessage("Cannot drop non existing materialized view", "DROP MATERIALIZED VIEW keyspace_does_not_exist.view_does_not_exist");
execute("DROP MATERIALIZED VIEW IF EXISTS " + KEYSPACE + ".view_does_not_exist");
execute("DROP MATERIALIZED VIEW IF EXISTS keyspace_does_not_exist.view_does_not_exist");
}
@Test
public void testExistingRangeTombstoneWithFlush() throws Throwable
{
testExistingRangeTombstone(true);
}
@Test
public void testExistingRangeTombstoneWithoutFlush() throws Throwable
{
testExistingRangeTombstone(false);
}
public void testExistingRangeTombstone(boolean flush) throws Throwable
{
createTable("CREATE TABLE %s (k1 int, c1 int, c2 int, v1 int, v2 int, PRIMARY KEY (k1, c1, c2))");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
createView("view1",
"CREATE MATERIALIZED VIEW view1 AS SELECT * FROM %%s WHERE k1 IS NOT NULL AND c1 IS NOT NULL AND c2 IS NOT NULL PRIMARY KEY (k1, c2, c1)");
updateView("DELETE FROM %s USING TIMESTAMP 10 WHERE k1 = 1 and c1=1");
if (flush)
Keyspace.open(keyspace()).getColumnFamilyStore(currentTable()).forceBlockingFlush();
String table = KEYSPACE + "." + currentTable();
updateView("BEGIN BATCH " +
"INSERT INTO " + table + " (k1, c1, c2, v1, v2) VALUES (1, 0, 0, 0, 0) USING TIMESTAMP 5; " +
"INSERT INTO " + table + " (k1, c1, c2, v1, v2) VALUES (1, 0, 1, 0, 1) USING TIMESTAMP 5; " +
"INSERT INTO " + table + " (k1, c1, c2, v1, v2) VALUES (1, 1, 0, 1, 0) USING TIMESTAMP 5; " +
"INSERT INTO " + table + " (k1, c1, c2, v1, v2) VALUES (1, 1, 1, 1, 1) USING TIMESTAMP 5; " +
"INSERT INTO " + table + " (k1, c1, c2, v1, v2) VALUES (1, 1, 2, 1, 2) USING TIMESTAMP 5; " +
"INSERT INTO " + table + " (k1, c1, c2, v1, v2) VALUES (1, 1, 3, 1, 3) USING TIMESTAMP 5; " +
"INSERT INTO " + table + " (k1, c1, c2, v1, v2) VALUES (1, 2, 0, 2, 0) USING TIMESTAMP 5; " +
"APPLY BATCH");
assertRowsIgnoringOrder(execute("select * from %s"),
row(1, 0, 0, 0, 0),
row(1, 0, 1, 0, 1),
row(1, 2, 0, 2, 0));
assertRowsIgnoringOrder(execute("select k1,c1,c2,v1,v2 from view1"),
row(1, 0, 0, 0, 0),
row(1, 0, 1, 0, 1),
row(1, 2, 0, 2, 0));
}
@Test
public void testPartitionTombstone() throws Throwable
{
createTable("CREATE TABLE %s (k1 int, c1 int , val int, PRIMARY KEY (k1, c1))");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
createView("view1", "CREATE MATERIALIZED VIEW view1 AS SELECT k1 FROM %%s WHERE k1 IS NOT NULL AND c1 IS NOT NULL AND val IS NOT NULL PRIMARY KEY (val, k1, c1)");
updateView("INSERT INTO %s (k1, c1, val) VALUES (1, 2, 200)");
updateView("INSERT INTO %s (k1, c1, val) VALUES (1, 3, 300)");
Assert.assertEquals(2, execute("select * from %s").size());
Assert.assertEquals(2, execute("select * from view1").size());
updateView("DELETE FROM %s WHERE k1 = 1");
Assert.assertEquals(0, execute("select * from %s").size());
Assert.assertEquals(0, execute("select * from view1").size());
}
@Test
public void createMvWithUnrestrictedPKParts() throws Throwable
{
createTable("CREATE TABLE %s (k1 int, c1 int , val int, PRIMARY KEY (k1, c1))");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
createView("view1", "CREATE MATERIALIZED VIEW view1 AS SELECT k1 FROM %%s WHERE k1 IS NOT NULL AND c1 IS NOT NULL AND val IS NOT NULL PRIMARY KEY (val, k1, c1)");
}
@Test
public void testClusteringKeyTombstone() throws Throwable
{
createTable("CREATE TABLE %s (k1 int, c1 int , val int, PRIMARY KEY (k1, c1))");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
createView("view1", "CREATE MATERIALIZED VIEW view1 AS SELECT k1 FROM %%s WHERE k1 IS NOT NULL AND c1 IS NOT NULL AND val IS NOT NULL PRIMARY KEY (val, k1, c1)");
updateView("INSERT INTO %s (k1, c1, val) VALUES (1, 2, 200)");
updateView("INSERT INTO %s (k1, c1, val) VALUES (1, 3, 300)");
Assert.assertEquals(2, execute("select * from %s").size());
Assert.assertEquals(2, execute("select * from view1").size());
updateView("DELETE FROM %s WHERE k1 = 1 and c1 = 3");
Assert.assertEquals(1, execute("select * from %s").size());
Assert.assertEquals(1, execute("select * from view1").size());
}
@Test
public void testPrimaryKeyIsNotNull() throws Throwable
{
createTable("CREATE TABLE %s (" +
"k int, " +
"asciival ascii, " +
"bigintval bigint, " +
"PRIMARY KEY((k, asciival)))");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
// Must include "IS NOT NULL" for primary keys
try
{
createView("mv_test", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s");
fail("Should fail if no primary key is filtered as NOT NULL");
}
catch (Exception e)
{
}
// Must include both when the partition key is composite
try
{
createView("mv_test", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE bigintval IS NOT NULL AND asciival IS NOT NULL PRIMARY KEY (bigintval, k, asciival)");
fail("Should fail if compound primary is not completely filtered as NOT NULL");
}
catch (Exception e)
{
}
dropTable("DROP TABLE %s");
createTable("CREATE TABLE %s (" +
"k int, " +
"asciival ascii, " +
"bigintval bigint, " +
"PRIMARY KEY(k, asciival))");
try
{
createView("mv_test", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s");
fail("Should fail if no primary key is filtered as NOT NULL");
}
catch (Exception e)
{
}
// Can omit "k IS NOT NULL" because we have a sinlge partition key
createView("mv_test", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE bigintval IS NOT NULL AND asciival IS NOT NULL PRIMARY KEY (bigintval, k, asciival)");
}
@Test
public void testStaticTable() throws Throwable
{
createTable("CREATE TABLE %s (" +
"k int, " +
"c int, " +
"sval text static, " +
"val text, " +
"PRIMARY KEY(k,c))");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
try
{
createView("mv_static", "CREATE MATERIALIZED VIEW %%s AS SELECT * FROM %s WHERE sval IS NOT NULL AND k IS NOT NULL AND c IS NOT NULL PRIMARY KEY (sval,k,c)");
fail("Use of static column in a MV primary key should fail");
}
catch (InvalidQueryException e)
{
}
try
{
createView("mv_static", "CREATE MATERIALIZED VIEW %%s AS SELECT val, sval FROM %s WHERE val IS NOT NULL AND k IS NOT NULL AND c IS NOT NULL PRIMARY KEY (val, k, c)");
fail("Explicit select of static column in MV should fail");
}
catch (InvalidQueryException e)
{
}
try
{
createView("mv_static", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE val IS NOT NULL AND k IS NOT NULL AND c IS NOT NULL PRIMARY KEY (val,k,c)");
fail("Implicit select of static column in MV should fail");
}
catch (InvalidQueryException e)
{
}
createView("mv_static", "CREATE MATERIALIZED VIEW %s AS SELECT val,k,c FROM %%s WHERE val IS NOT NULL AND k IS NOT NULL AND c IS NOT NULL PRIMARY KEY (val,k,c)");
for (int i = 0; i < 100; i++)
updateView("INSERT into %s (k,c,sval,val)VALUES(?,?,?,?)", 0, i % 2, "bar" + i, "baz");
Assert.assertEquals(2, execute("select * from %s").size());
assertRows(execute("SELECT sval from %s"), row("bar99"), row("bar99"));
Assert.assertEquals(2, execute("select * from mv_static").size());
assertInvalid("SELECT sval from mv_static");
}
@Test
public void testOldTimestamps() throws Throwable
{
createTable("CREATE TABLE %s (" +
"k int, " +
"c int, " +
"val text, " +
"PRIMARY KEY(k,c))");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
createView("mv_tstest", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE val IS NOT NULL AND k IS NOT NULL AND c IS NOT NULL PRIMARY KEY (val,k,c)");
for (int i = 0; i < 100; i++)
updateView("INSERT into %s (k,c,val)VALUES(?,?,?)", 0, i % 2, "baz");
Keyspace.open(keyspace()).getColumnFamilyStore(currentTable()).forceBlockingFlush();
Assert.assertEquals(2, execute("select * from %s").size());
Assert.assertEquals(2, execute("select * from mv_tstest").size());
assertRows(execute("SELECT val from %s where k = 0 and c = 0"), row("baz"));
assertRows(execute("SELECT c from mv_tstest where k = 0 and val = ?", "baz"), row(0), row(1));
//Make sure an old TS does nothing
updateView("UPDATE %s USING TIMESTAMP 100 SET val = ? where k = ? AND c = ?", "bar", 0, 0);
assertRows(execute("SELECT val from %s where k = 0 and c = 0"), row("baz"));
assertRows(execute("SELECT c from mv_tstest where k = 0 and val = ?", "baz"), row(0), row(1));
assertRows(execute("SELECT c from mv_tstest where k = 0 and val = ?", "bar"));
//Latest TS
updateView("UPDATE %s SET val = ? where k = ? AND c = ?", "bar", 0, 0);
assertRows(execute("SELECT val from %s where k = 0 and c = 0"), row("bar"));
assertRows(execute("SELECT c from mv_tstest where k = 0 and val = ?", "bar"), row(0));
assertRows(execute("SELECT c from mv_tstest where k = 0 and val = ?", "baz"), row(1));
}
@Test
public void testRegularColumnTimestampUpdates() throws Throwable
{
// Regression test for CASSANDRA-10910
createTable("CREATE TABLE %s (" +
"k int PRIMARY KEY, " +
"c int, " +
"val int)");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
createView("mv_rctstest", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE k IS NOT NULL AND c IS NOT NULL PRIMARY KEY (k,c)");
updateView("UPDATE %s SET c = ?, val = ? WHERE k = ?", 0, 0, 0);
updateView("UPDATE %s SET val = ? WHERE k = ?", 1, 0);
updateView("UPDATE %s SET c = ? WHERE k = ?", 1, 0);
assertRows(execute("SELECT c, k, val FROM mv_rctstest"), row(1, 0, 1));
updateView("TRUNCATE %s");
updateView("UPDATE %s USING TIMESTAMP 1 SET c = ?, val = ? WHERE k = ?", 0, 0, 0);
updateView("UPDATE %s USING TIMESTAMP 3 SET c = ? WHERE k = ?", 1, 0);
updateView("UPDATE %s USING TIMESTAMP 2 SET val = ? WHERE k = ?", 1, 0);
updateView("UPDATE %s USING TIMESTAMP 4 SET c = ? WHERE k = ?", 2, 0);
updateView("UPDATE %s USING TIMESTAMP 3 SET val = ? WHERE k = ?", 2, 0);
assertRows(execute("SELECT c, k, val FROM mv_rctstest"), row(2, 0, 2));
assertRows(execute("SELECT c, k, val FROM mv_rctstest limit 1"), row(2, 0, 2));
}
@Test
public void testCountersTable() throws Throwable
{
createTable("CREATE TABLE %s (" +
"k int PRIMARY KEY, " +
"count counter)");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
try
{
createView("mv_counter", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE count IS NOT NULL AND k IS NOT NULL PRIMARY KEY (count,k)");
fail("MV on counter should fail");
}
catch (InvalidQueryException e)
{
}
}
@Test
public void testSuperCoumn() throws Throwable
{
String keyspace = createKeyspaceName();
String table = createTableName();
SchemaLoader.createKeyspace(keyspace,
KeyspaceParams.simple(1),
SchemaLoader.superCFMD(keyspace, table, AsciiType.instance, AsciiType.instance));
execute("USE " + keyspace);
executeNet(protocolVersion, "USE " + keyspace);
try
{
createView("mv_super_column", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM " + keyspace + "." + table + " WHERE key IS NOT NULL AND column1 IS NOT NULL PRIMARY KEY (key,column1)");
fail("MV on SuperColumn table should fail");
}
catch (InvalidQueryException e)
{
assertEquals("Materialized views are not supported on SuperColumn tables", e.getMessage());
}
}
@Test
public void testDurationsTable() throws Throwable
{
createTable("CREATE TABLE %s (" +
"k int PRIMARY KEY, " +
"result duration)");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
try
{
createView("mv_duration", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE result IS NOT NULL AND k IS NOT NULL PRIMARY KEY (result,k)");
fail("MV on duration should fail");
}
catch (InvalidQueryException e)
{
Assert.assertEquals("Cannot use Duration column 'result' in PRIMARY KEY of materialized view", e.getMessage());
}
}
@Test
public void complexTimestampUpdateTestWithFlush() throws Throwable
{
complexTimestampUpdateTest(true);
}
@Test
public void complexTimestampUpdateTestWithoutFlush() throws Throwable
{
complexTimestampUpdateTest(false);
}
public void complexTimestampUpdateTest(boolean flush) throws Throwable
{
createTable("CREATE TABLE %s (a int, b int, c int, d int, e int, PRIMARY KEY (a, b))");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
Keyspace ks = Keyspace.open(keyspace());
createView("mv", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE a IS NOT NULL AND b IS NOT NULL AND c IS NOT NULL PRIMARY KEY (c, a, b)");
ks.getColumnFamilyStore("mv").disableAutoCompaction();
//Set initial values TS=0, leaving e null and verify view
executeNet(protocolVersion, "INSERT INTO %s (a, b, c, d) VALUES (0, 0, 1, 0) USING TIMESTAMP 0");
assertRows(execute("SELECT d from mv WHERE c = ? and a = ? and b = ?", 1, 0, 0), row(0));
if (flush)
FBUtilities.waitOnFutures(ks.flush());
//update c's timestamp TS=2
executeNet(protocolVersion, "UPDATE %s USING TIMESTAMP 2 SET c = ? WHERE a = ? and b = ? ", 1, 0, 0);
assertRows(execute("SELECT d from mv WHERE c = ? and a = ? and b = ?", 1, 0, 0), row(0));
if (flush)
FBUtilities.waitOnFutures(ks.flush());
// change c's value and TS=3, tombstones c=1 and adds c=0 record
executeNet(protocolVersion, "UPDATE %s USING TIMESTAMP 3 SET c = ? WHERE a = ? and b = ? ", 0, 0, 0);
if (flush)
FBUtilities.waitOnFutures(ks.flush());
assertRows(execute("SELECT d from mv WHERE c = ? and a = ? and b = ?", 1, 0, 0));
if(flush)
{
ks.getColumnFamilyStore("mv").forceMajorCompaction();
FBUtilities.waitOnFutures(ks.flush());
}
//change c's value back to 1 with TS=4, check we can see d
executeNet(protocolVersion, "UPDATE %s USING TIMESTAMP 4 SET c = ? WHERE a = ? and b = ? ", 1, 0, 0);
if (flush)
{
ks.getColumnFamilyStore("mv").forceMajorCompaction();
FBUtilities.waitOnFutures(ks.flush());
}
assertRows(execute("SELECT d,e from mv WHERE c = ? and a = ? and b = ?", 1, 0, 0), row(0, null));
//Add e value @ TS=1
executeNet(protocolVersion, "UPDATE %s USING TIMESTAMP 1 SET e = ? WHERE a = ? and b = ? ", 1, 0, 0);
assertRows(execute("SELECT d,e from mv WHERE c = ? and a = ? and b = ?", 1, 0, 0), row(0, 1));
if (flush)
FBUtilities.waitOnFutures(ks.flush());
//Change d value @ TS=2
executeNet(protocolVersion, "UPDATE %s USING TIMESTAMP 2 SET d = ? WHERE a = ? and b = ? ", 2, 0, 0);
assertRows(execute("SELECT d from mv WHERE c = ? and a = ? and b = ?", 1, 0, 0), row(2));
if (flush)
FBUtilities.waitOnFutures(ks.flush());
//Change d value @ TS=3
executeNet(protocolVersion, "UPDATE %s USING TIMESTAMP 3 SET d = ? WHERE a = ? and b = ? ", 1, 0, 0);
assertRows(execute("SELECT d from mv WHERE c = ? and a = ? and b = ?", 1, 0, 0), row(1));
//Tombstone c
executeNet(protocolVersion, "DELETE FROM %s WHERE a = ? and b = ?", 0, 0);
assertRows(execute("SELECT d from mv"));
//Add back without D
executeNet(protocolVersion, "INSERT INTO %s (a, b, c) VALUES (0, 0, 1)");
//Make sure D doesn't pop back in.
assertRows(execute("SELECT d from mv WHERE c = ? and a = ? and b = ?", 1, 0, 0), row((Object) null));
//New partition
// insert a row with timestamp 0
executeNet(protocolVersion, "INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?) USING TIMESTAMP 0", 1, 0, 0, 0, 0);
// overwrite pk and e with timestamp 1, but don't overwrite d
executeNet(protocolVersion, "INSERT INTO %s (a, b, c, e) VALUES (?, ?, ?, ?) USING TIMESTAMP 1", 1, 0, 0, 0);
// delete with timestamp 0 (which should only delete d)
executeNet(protocolVersion, "DELETE FROM %s USING TIMESTAMP 0 WHERE a = ? AND b = ?", 1, 0);
assertRows(execute("SELECT a, b, c, d, e from mv WHERE c = ? and a = ? and b = ?", 0, 1, 0),
row(1, 0, 0, null, 0)
);
executeNet(protocolVersion, "UPDATE %s USING TIMESTAMP 2 SET c = ? WHERE a = ? AND b = ?", 1, 1, 0);
executeNet(protocolVersion, "UPDATE %s USING TIMESTAMP 3 SET c = ? WHERE a = ? AND b = ?", 0, 1, 0);
assertRows(execute("SELECT a, b, c, d, e from mv WHERE c = ? and a = ? and b = ?", 0, 1, 0),
row(1, 0, 0, null, 0)
);
executeNet(protocolVersion, "UPDATE %s USING TIMESTAMP 3 SET d = ? WHERE a = ? AND b = ?", 0, 1, 0);
assertRows(execute("SELECT a, b, c, d, e from mv WHERE c = ? and a = ? and b = ?", 0, 1, 0),
row(1, 0, 0, 0, 0)
);
}
@Test
public void testBuilderWidePartition() throws Throwable
{
createTable("CREATE TABLE %s (" +
"k int, " +
"c int, " +
"intval int, " +
"PRIMARY KEY (k, c))");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
for(int i = 0; i < 1024; i++)
execute("INSERT INTO %s (k, c, intval) VALUES (?, ?, ?)", 0, i, 0);
createView("mv", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE k IS NOT NULL AND c IS NOT NULL AND intval IS NOT NULL PRIMARY KEY (intval, c, k)");
while (!SystemKeyspace.isViewBuilt(keyspace(), "mv"))
Thread.sleep(1000);
assertRows(execute("SELECT count(*) from %s WHERE k = ?", 0), row(1024L));
assertRows(execute("SELECT count(*) from mv WHERE intval = ?", 0), row(1024L));
}
@Test
public void testRangeTombstone() throws Throwable
{
createTable("CREATE TABLE %s (" +
"k int, " +
"asciival ascii, " +
"bigintval bigint, " +
"textval1 text, " +
"textval2 text, " +
"PRIMARY KEY((k, asciival), bigintval, textval1)" +
")");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
createView("mv_test1", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE textval2 IS NOT NULL AND k IS NOT NULL AND asciival IS NOT NULL AND bigintval IS NOT NULL AND textval1 IS NOT NULL PRIMARY KEY ((textval2, k), asciival, bigintval, textval1)");
for (int i = 0; i < 100; i++)
updateView("INSERT into %s (k,asciival,bigintval,textval1,textval2)VALUES(?,?,?,?,?)", 0, "foo", (long) i % 2, "bar" + i, "baz");
Assert.assertEquals(50, execute("select * from %s where k = 0 and asciival = 'foo' and bigintval = 0").size());
Assert.assertEquals(50, execute("select * from %s where k = 0 and asciival = 'foo' and bigintval = 1").size());
Assert.assertEquals(100, execute("select * from mv_test1").size());
//Check the builder works
createView("mv_test2", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE textval2 IS NOT NULL AND k IS NOT NULL AND asciival IS NOT NULL AND bigintval IS NOT NULL AND textval1 IS NOT NULL PRIMARY KEY ((textval2, k), asciival, bigintval, textval1)");
while (!SystemKeyspace.isViewBuilt(keyspace(), "mv_test2"))
Thread.sleep(10);
Assert.assertEquals(100, execute("select * from mv_test2").size());
createView("mv_test3", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE textval2 IS NOT NULL AND k IS NOT NULL AND asciival IS NOT NULL AND bigintval IS NOT NULL AND textval1 IS NOT NULL PRIMARY KEY ((textval2, k), bigintval, textval1, asciival)");
while (!SystemKeyspace.isViewBuilt(keyspace(), "mv_test3"))
Thread.sleep(10);
Assert.assertEquals(100, execute("select * from mv_test3").size());
Assert.assertEquals(100, execute("select asciival from mv_test3 where textval2 = ? and k = ?", "baz", 0).size());
//Write a RT and verify the data is removed from index
updateView("DELETE FROM %s WHERE k = ? AND asciival = ? and bigintval = ?", 0, "foo", 0L);
Assert.assertEquals(50, execute("select asciival from mv_test3 where textval2 = ? and k = ?", "baz", 0).size());
}
@Test
public void testRangeTombstone2() throws Throwable
{
createTable("CREATE TABLE %s (" +
"k int, " +
"asciival ascii, " +
"bigintval bigint, " +
"textval1 text, " +
"PRIMARY KEY((k, asciival), bigintval)" +
")");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
createView("mv", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE textval1 IS NOT NULL AND k IS NOT NULL AND asciival IS NOT NULL AND bigintval IS NOT NULL PRIMARY KEY ((textval1, k), asciival, bigintval)");
for (int i = 0; i < 100; i++)
updateView("INSERT into %s (k,asciival,bigintval,textval1)VALUES(?,?,?,?)", 0, "foo", (long) i % 2, "bar" + i);
Assert.assertEquals(1, execute("select * from %s where k = 0 and asciival = 'foo' and bigintval = 0").size());
Assert.assertEquals(1, execute("select * from %s where k = 0 and asciival = 'foo' and bigintval = 1").size());
Assert.assertEquals(2, execute("select * from %s").size());
Assert.assertEquals(2, execute("select * from mv").size());
//Write a RT and verify the data is removed from index
updateView("DELETE FROM %s WHERE k = ? AND asciival = ? and bigintval = ?", 0, "foo", 0L);
Assert.assertEquals(1, execute("select * from %s").size());
Assert.assertEquals(1, execute("select * from mv").size());
}
@Test
public void testRangeTombstone3() throws Throwable
{
createTable("CREATE TABLE %s (" +
"k int, " +
"asciival ascii, " +
"bigintval bigint, " +
"textval1 text, " +
"PRIMARY KEY((k, asciival), bigintval)" +
")");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
createView("mv", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE textval1 IS NOT NULL AND k IS NOT NULL AND asciival IS NOT NULL AND bigintval IS NOT NULL PRIMARY KEY ((textval1, k), asciival, bigintval)");
for (int i = 0; i < 100; i++)
updateView("INSERT into %s (k,asciival,bigintval,textval1)VALUES(?,?,?,?)", 0, "foo", (long) i % 2, "bar" + i);
Assert.assertEquals(1, execute("select * from %s where k = 0 and asciival = 'foo' and bigintval = 0").size());
Assert.assertEquals(1, execute("select * from %s where k = 0 and asciival = 'foo' and bigintval = 1").size());
Assert.assertEquals(2, execute("select * from %s").size());
Assert.assertEquals(2, execute("select * from mv").size());
//Write a RT and verify the data is removed from index
updateView("DELETE FROM %s WHERE k = ? AND asciival = ? and bigintval >= ?", 0, "foo", 0L);
Assert.assertEquals(0, execute("select * from %s").size());
Assert.assertEquals(0, execute("select * from mv").size());
}
@Test
public void testCompoundPartitionKey() throws Throwable
{
createTable("CREATE TABLE %s (" +
"k int, " +
"asciival ascii, " +
"bigintval bigint, " +
"PRIMARY KEY((k, asciival)))");
CFMetaData metadata = currentTableMetadata();
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
for (ColumnDefinition def : new HashSet<>(metadata.allColumns()))
{
try
{
String query = "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE " + def.name + " IS NOT NULL AND k IS NOT NULL "
+ (def.name.toString().equals("asciival") ? "" : "AND asciival IS NOT NULL ") + "PRIMARY KEY ("
+ def.name + ", k" + (def.name.toString().equals("asciival") ? "" : ", asciival") + ")";
createView("mv1_" + def.name, query);
if (def.type.isMultiCell())
fail("MV on a multicell should fail " + def);
}
catch (InvalidQueryException e)
{
if (!def.type.isMultiCell() && !def.isPartitionKey())
fail("MV creation failed on " + def);
}
try
{
String query = "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE " + def.name + " IS NOT NULL AND k IS NOT NULL "
+ (def.name.toString().equals("asciival") ? "" : "AND asciival IS NOT NULL ") + " PRIMARY KEY ("
+ def.name + ", asciival" + (def.name.toString().equals("k") ? "" : ", k") + ")";
createView("mv2_" + def.name, query);
if (def.type.isMultiCell())
fail("MV on a multicell should fail " + def);
}
catch (InvalidQueryException e)
{
if (!def.type.isMultiCell() && !def.isPartitionKey())
fail("MV creation failed on " + def);
}
try
{
String query = "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE " + def.name + " IS NOT NULL AND k IS NOT NULL "
+ (def.name.toString().equals("asciival") ? "" : "AND asciival IS NOT NULL ") + "PRIMARY KEY ((" + def.name + ", k), asciival)";
createView("mv3_" + def.name, query);
if (def.type.isMultiCell())
fail("MV on a multicell should fail " + def);
}
catch (InvalidQueryException e)
{
if (!def.type.isMultiCell() && !def.isPartitionKey())
fail("MV creation failed on " + def);
}
try
{
String query = "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE " + def.name + " IS NOT NULL AND k IS NOT NULL "
+ (def.name.toString().equals("asciival") ? "" : "AND asciival IS NOT NULL ") + "PRIMARY KEY ((" + def.name + ", k), asciival)";
createView("mv3_" + def.name, query);
fail("Should fail on duplicate name");
}
catch (Exception e)
{
}
try
{
String query = "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE " + def.name + " IS NOT NULL AND k IS NOT NULL "
+ (def.name.toString().equals("asciival") ? "" : "AND asciival IS NOT NULL ") + "PRIMARY KEY ((" + def.name + ", k), nonexistentcolumn)";
createView("mv3_" + def.name, query);
fail("Should fail with unknown base column");
}
catch (InvalidQueryException e)
{
}
}
updateView("INSERT INTO %s (k, asciival, bigintval) VALUES (?, ?, fromJson(?))", 0, "ascii text", "123123123123");
updateView("INSERT INTO %s (k, asciival) VALUES (?, fromJson(?))", 0, "\"ascii text\"");
assertRows(execute("SELECT bigintval FROM %s WHERE k = ? and asciival = ?", 0, "ascii text"), row(123123123123L));
//Check the MV
assertRows(execute("SELECT k, bigintval from mv1_asciival WHERE asciival = ?", "ascii text"), row(0, 123123123123L));
assertRows(execute("SELECT k, bigintval from mv2_k WHERE asciival = ? and k = ?", "ascii text", 0), row(0, 123123123123L));
assertRows(execute("SELECT k from mv1_bigintval WHERE bigintval = ?", 123123123123L), row(0));
assertRows(execute("SELECT asciival from mv3_bigintval where bigintval = ? AND k = ?", 123123123123L, 0), row("ascii text"));
//UPDATE BASE
updateView("INSERT INTO %s (k, asciival, bigintval) VALUES (?, ?, fromJson(?))", 0, "ascii text", "1");
assertRows(execute("SELECT bigintval FROM %s WHERE k = ? and asciival = ?", 0, "ascii text"), row(1L));
//Check the MV
assertRows(execute("SELECT k, bigintval from mv1_asciival WHERE asciival = ?", "ascii text"), row(0, 1L));
assertRows(execute("SELECT k, bigintval from mv2_k WHERE asciival = ? and k = ?", "ascii text", 0), row(0, 1L));
assertRows(execute("SELECT k from mv1_bigintval WHERE bigintval = ?", 123123123123L));
assertRows(execute("SELECT asciival from mv3_bigintval where bigintval = ? AND k = ?", 123123123123L, 0));
assertRows(execute("SELECT asciival from mv3_bigintval where bigintval = ? AND k = ?", 1L, 0), row("ascii text"));
//test truncate also truncates all MV
updateView("TRUNCATE %s");
assertRows(execute("SELECT bigintval FROM %s WHERE k = ? and asciival = ?", 0, "ascii text"));
assertRows(execute("SELECT k, bigintval from mv1_asciival WHERE asciival = ?", "ascii text"));
assertRows(execute("SELECT k, bigintval from mv2_k WHERE asciival = ? and k = ?", "ascii text", 0));
assertRows(execute("SELECT asciival from mv3_bigintval where bigintval = ? AND k = ?", 1L, 0));
}
@Test
public void testCollections() throws Throwable
{
createTable("CREATE TABLE %s (" +
"k int, " +
"intval int, " +
"listval list<int>, " +
"PRIMARY KEY (k))");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
createView("mv", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE k IS NOT NULL AND intval IS NOT NULL PRIMARY KEY (intval, k)");
updateView("INSERT INTO %s (k, intval, listval) VALUES (?, ?, fromJson(?))", 0, 0, "[1, 2, 3]");
assertRows(execute("SELECT k, listval FROM %s WHERE k = ?", 0), row(0, list(1, 2, 3)));
assertRows(execute("SELECT k, listval from mv WHERE intval = ?", 0), row(0, list(1, 2, 3)));
updateView("INSERT INTO %s (k, intval) VALUES (?, ?)", 1, 1);
updateView("INSERT INTO %s (k, listval) VALUES (?, fromJson(?))", 1, "[1, 2, 3]");
assertRows(execute("SELECT k, listval FROM %s WHERE k = ?", 1), row(1, list(1, 2, 3)));
assertRows(execute("SELECT k, listval from mv WHERE intval = ?", 1), row(1, list(1, 2, 3)));
}
@Test
public void testFrozenCollectionsWithComplicatedInnerType() throws Throwable
{
createTable("CREATE TABLE %s (k int, intval int, listval frozen<list<tuple<text,text>>>, PRIMARY KEY (k))");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
createView("mv",
"CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE k IS NOT NULL AND listval IS NOT NULL PRIMARY KEY (k, listval)");
updateView("INSERT INTO %s (k, intval, listval) VALUES (?, ?, fromJson(?))",
0,
0,
"[[\"a\",\"1\"], [\"b\",\"2\"], [\"c\",\"3\"]]");
// verify input
assertRows(execute("SELECT k, listval FROM %s WHERE k = ?", 0),
row(0, list(tuple("a", "1"), tuple("b", "2"), tuple("c", "3"))));
assertRows(execute("SELECT k, listval from mv"),
row(0, list(tuple("a", "1"), tuple("b", "2"), tuple("c", "3"))));
// update listval with the same value and it will be compared in view generator
updateView("INSERT INTO %s (k, listval) VALUES (?, fromJson(?))",
0,
"[[\"a\",\"1\"], [\"b\",\"2\"], [\"c\",\"3\"]]");
// verify result
assertRows(execute("SELECT k, listval FROM %s WHERE k = ?", 0),
row(0, list(tuple("a", "1"), tuple("b", "2"), tuple("c", "3"))));
assertRows(execute("SELECT k, listval from mv"),
row(0, list(tuple("a", "1"), tuple("b", "2"), tuple("c", "3"))));
}
@Test
public void testUpdate() throws Throwable
{
createTable("CREATE TABLE %s (" +
"k int, " +
"intval int, " +
"PRIMARY KEY (k))");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
createView("mv", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE k IS NOT NULL AND intval IS NOT NULL PRIMARY KEY (intval, k)");
updateView("INSERT INTO %s (k, intval) VALUES (?, ?)", 0, 0);
assertRows(execute("SELECT k, intval FROM %s WHERE k = ?", 0), row(0, 0));
assertRows(execute("SELECT k, intval from mv WHERE intval = ?", 0), row(0, 0));
updateView("INSERT INTO %s (k, intval) VALUES (?, ?)", 0, 1);
assertRows(execute("SELECT k, intval FROM %s WHERE k = ?", 0), row(0, 1));
assertRows(execute("SELECT k, intval from mv WHERE intval = ?", 1), row(0, 1));
}
@Test
public void testIgnoreUpdate() throws Throwable
{
// regression test for CASSANDRA-10614
createTable("CREATE TABLE %s (" +
"a int, " +
"b int, " +
"c int, " +
"d int, " +
"PRIMARY KEY (a, b))");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
createView("mv", "CREATE MATERIALIZED VIEW %s AS SELECT a, b, c FROM %%s WHERE a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (b, a)");
updateView("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, 0, 0);
assertRows(execute("SELECT a, b, c from mv WHERE b = ?", 0), row(0, 0, 0));
updateView("UPDATE %s SET d = ? WHERE a = ? AND b = ?", 0, 0, 0);
assertRows(execute("SELECT a, b, c from mv WHERE b = ?", 0), row(0, 0, 0));
// Note: errors here may result in the test hanging when the memtables are flushed as part of the table drop,
// because empty rows in the memtable will cause the flush to fail. This will result in a test timeout that
// should not be ignored.
String table = KEYSPACE + "." + currentTable();
updateView("BEGIN BATCH " +
"INSERT INTO " + table + " (a, b, c, d) VALUES (?, ?, ?, ?); " + // should be accepted
"UPDATE " + table + " SET d = ? WHERE a = ? AND b = ?; " + // should be accepted
"APPLY BATCH",
0, 0, 0, 0,
1, 0, 1);
assertRows(execute("SELECT a, b, c from mv WHERE b = ?", 0), row(0, 0, 0));
assertRows(execute("SELECT a, b, c from mv WHERE b = ?", 1), row(0, 1, null));
ColumnFamilyStore cfs = Keyspace.open(keyspace()).getColumnFamilyStore("mv");
cfs.forceBlockingFlush();
Assert.assertEquals(1, cfs.getLiveSSTables().size());
}
@Test
public void ttlTest() throws Throwable
{
createTable("CREATE TABLE %s (" +
"a int," +
"b int," +
"c int," +
"d int," +
"PRIMARY KEY (a, b))");
executeNet(protocolVersion, "USE " + keyspace());
createView("mv", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE c IS NOT NULL AND a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (c, a, b)");
updateView("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?) USING TTL 3", 1, 1, 1, 1);
Thread.sleep(TimeUnit.SECONDS.toMillis(1));
updateView("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 1, 1, 2);
Thread.sleep(TimeUnit.SECONDS.toMillis(5));
List<Row> results = executeNet(protocolVersion, "SELECT d FROM mv WHERE c = 2 AND a = 1 AND b = 1").all();
Assert.assertEquals(1, results.size());
Assert.assertTrue("There should be a null result given back due to ttl expiry", results.get(0).isNull(0));
}
@Test
public void ttlExpirationTest() throws Throwable
{
createTable("CREATE TABLE %s (" +
"a int," +
"b int," +
"c int," +
"d int," +
"PRIMARY KEY (a, b))");
executeNet(protocolVersion, "USE " + keyspace());
createView("mv", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE c IS NOT NULL AND a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (c, a, b)");
updateView("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?) USING TTL 3", 1, 1, 1, 1);
Thread.sleep(TimeUnit.SECONDS.toMillis(4));
Assert.assertEquals(0, executeNet(protocolVersion, "SELECT * FROM mv WHERE c = 1 AND a = 1 AND b = 1").all().size());
}
@Test
public void rowDeletionTest() throws Throwable
{
createTable("CREATE TABLE %s (" +
"a int," +
"b int," +
"c int," +
"d int," +
"PRIMARY KEY (a, b))");
executeNet(protocolVersion, "USE " + keyspace());
createView("mv", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE c IS NOT NULL AND a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (c, a, b)");
String table = keyspace() + "." + currentTable();
updateView("DELETE FROM " + table + " USING TIMESTAMP 6 WHERE a = 1 AND b = 1;");
updateView("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?) USING TIMESTAMP 3", 1, 1, 1, 1);
Assert.assertEquals(0, executeNet(protocolVersion, "SELECT * FROM mv WHERE c = 1 AND a = 1 AND b = 1").all().size());
}
@Test
public void conflictingTimestampTest() throws Throwable
{
createTable("CREATE TABLE %s (" +
"a int," +
"b int," +
"c int," +
"PRIMARY KEY (a, b))");
executeNet(protocolVersion, "USE " + keyspace());
createView("mv", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE c IS NOT NULL AND a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (c, a, b)");
for (int i = 0; i < 50; i++)
{
updateView("INSERT INTO %s (a, b, c) VALUES (?, ?, ?) USING TIMESTAMP 1", 1, 1, i);
}
ResultSet mvRows = executeNet(protocolVersion, "SELECT c FROM mv");
List<Row> rows = executeNet(protocolVersion, "SELECT c FROM %s").all();
Assert.assertEquals("There should be exactly one row in base", 1, rows.size());
int expected = rows.get(0).getInt("c");
assertRowsNet(protocolVersion, mvRows, row(expected));
}
@Test
public void testClusteringOrder() throws Throwable
{
createTable("CREATE TABLE %s (" +
"a int," +
"b int," +
"c int," +
"d int," +
"PRIMARY KEY (a, b, c))" +
"WITH CLUSTERING ORDER BY (b ASC, c DESC)");
executeNet(protocolVersion, "USE " + keyspace());
createView("mv1", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE b IS NOT NULL AND c IS NOT NULL PRIMARY KEY (a, b, c) WITH CLUSTERING ORDER BY (b DESC)");
createView("mv2", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE b IS NOT NULL AND c IS NOT NULL PRIMARY KEY (a, c, b) WITH CLUSTERING ORDER BY (c ASC)");
createView("mv3", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE b IS NOT NULL AND c IS NOT NULL PRIMARY KEY (a, b, c)");
createView("mv4", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE b IS NOT NULL AND c IS NOT NULL PRIMARY KEY (a, c, b) WITH CLUSTERING ORDER BY (c DESC)");
updateView("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 1, 1, 1);
updateView("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 2, 2, 2);
ResultSet mvRows = executeNet(protocolVersion, "SELECT b FROM mv1");
assertRowsNet(protocolVersion, mvRows,
row(2),
row(1));
mvRows = executeNet(protocolVersion, "SELECT c FROM mv2");
assertRowsNet(protocolVersion, mvRows,
row(1),
row(2));
mvRows = executeNet(protocolVersion, "SELECT b FROM mv3");
assertRowsNet(protocolVersion, mvRows,
row(1),
row(2));
mvRows = executeNet(protocolVersion, "SELECT c FROM mv4");
assertRowsNet(protocolVersion, mvRows,
row(2),
row(1));
}
@Test
public void testMultipleDeletes() throws Throwable
{
createTable("CREATE TABLE %s (" +
"a int," +
"b int," +
"PRIMARY KEY (a, b))");
executeNet(protocolVersion, "USE " + keyspace());
createView("mv1", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE b IS NOT NULL PRIMARY KEY (b, a)");
updateView("INSERT INTO %s (a, b) VALUES (?, ?)", 1, 1);
updateView("INSERT INTO %s (a, b) VALUES (?, ?)", 1, 2);
updateView("INSERT INTO %s (a, b) VALUES (?, ?)", 1, 3);
ResultSet mvRows = executeNet(protocolVersion, "SELECT a, b FROM mv1");
assertRowsNet(protocolVersion, mvRows,
row(1, 1),
row(1, 2),
row(1, 3));
updateView(String.format("BEGIN UNLOGGED BATCH " +
"DELETE FROM %s WHERE a = 1 AND b > 1 AND b < 3;" +
"DELETE FROM %s WHERE a = 1;" +
"APPLY BATCH", currentTable(), currentTable()));
mvRows = executeNet(protocolVersion, "SELECT a, b FROM mv1");
assertRowsNet(protocolVersion, mvRows);
}
@Test
public void testPrimaryKeyOnlyTable() throws Throwable
{
createTable("CREATE TABLE %s (" +
"a int," +
"b int," +
"PRIMARY KEY (a, b))");
executeNet(protocolVersion, "USE " + keyspace());
// Cannot use SELECT *, as those are always handled by the includeAll shortcut in View.updateAffectsView
createView("mv1", "CREATE MATERIALIZED VIEW %s AS SELECT a, b FROM %%s WHERE b IS NOT NULL PRIMARY KEY (b, a)");
updateView("INSERT INTO %s (a, b) VALUES (?, ?)", 1, 1);
ResultSet mvRows = executeNet(protocolVersion, "SELECT a, b FROM mv1");
assertRowsNet(protocolVersion, mvRows, row(1, 1));
}
@Test
public void testPartitionKeyOnlyTable() throws Throwable
{
createTable("CREATE TABLE %s (" +
"a int," +
"b int," +
"PRIMARY KEY ((a, b)))");
executeNet(protocolVersion, "USE " + keyspace());
// Cannot use SELECT *, as those are always handled by the includeAll shortcut in View.updateAffectsView
createView("mv1", "CREATE MATERIALIZED VIEW %s AS SELECT a, b FROM %%s WHERE a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (b, a)");
updateView("INSERT INTO %s (a, b) VALUES (?, ?)", 1, 1);
ResultSet mvRows = executeNet(protocolVersion, "SELECT a, b FROM mv1");
assertRowsNet(protocolVersion, mvRows, row(1, 1));
}
@Test
public void testDeleteSingleColumnInViewClustering() throws Throwable
{
createTable("CREATE TABLE %s (" +
"a int," +
"b int," +
"c int," +
"d int," +
"PRIMARY KEY (a, b))");
executeNet(protocolVersion, "USE " + keyspace());
createView("mv1", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE a IS NOT NULL AND b IS NOT NULL AND d IS NOT NULL PRIMARY KEY (a, d, b)");
updateView("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 0, 0);
ResultSet mvRows = executeNet(protocolVersion, "SELECT a, d, b, c FROM mv1");
assertRowsNet(protocolVersion, mvRows, row(0, 0, 0, 0));
updateView("DELETE c FROM %s WHERE a = ? AND b = ?", 0, 0);
mvRows = executeNet(protocolVersion, "SELECT a, d, b, c FROM mv1");
assertRowsNet(protocolVersion, mvRows, row(0, 0, 0, null));
updateView("DELETE d FROM %s WHERE a = ? AND b = ?", 0, 0);
mvRows = executeNet(protocolVersion, "SELECT a, d, b FROM mv1");
assertTrue(mvRows.isExhausted());
}
@Test
public void testDeleteSingleColumnInViewPartitionKey() throws Throwable
{
createTable("CREATE TABLE %s (" +
"a int," +
"b int," +
"c int," +
"d int," +
"PRIMARY KEY (a, b))");
executeNet(protocolVersion, "USE " + keyspace());
createView("mv1", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE a IS NOT NULL AND b IS NOT NULL AND d IS NOT NULL PRIMARY KEY (d, a, b)");
updateView("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 0, 0);
ResultSet mvRows = executeNet(protocolVersion, "SELECT a, d, b, c FROM mv1");
assertRowsNet(protocolVersion, mvRows, row(0, 0, 0, 0));
updateView("DELETE c FROM %s WHERE a = ? AND b = ?", 0, 0);
mvRows = executeNet(protocolVersion, "SELECT a, d, b, c FROM mv1");
assertRowsNet(protocolVersion, mvRows, row(0, 0, 0, null));
updateView("DELETE d FROM %s WHERE a = ? AND b = ?", 0, 0);
mvRows = executeNet(protocolVersion, "SELECT a, d, b FROM mv1");
assertTrue(mvRows.isExhausted());
}
@Test
public void testCollectionInView() throws Throwable
{
createTable("CREATE TABLE %s (" +
"a int," +
"b int," +
"c map<int, text>," +
"PRIMARY KEY (a))");
executeNet(protocolVersion, "USE " + keyspace());
createView("mvmap", "CREATE MATERIALIZED VIEW %s AS SELECT a, b FROM %%s WHERE b IS NOT NULL PRIMARY KEY (b, a)");
updateView("INSERT INTO %s (a, b) VALUES (?, ?)", 0, 0);
ResultSet mvRows = executeNet(protocolVersion, "SELECT a, b FROM mvmap WHERE b = ?", 0);
assertRowsNet(protocolVersion, mvRows, row(0, 0));
updateView("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 1, 1, map(1, "1"));
mvRows = executeNet(protocolVersion, "SELECT a, b FROM mvmap WHERE b = ?", 1);
assertRowsNet(protocolVersion, mvRows, row(1, 1));
updateView("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, 0, map(0, "0"));
mvRows = executeNet(protocolVersion, "SELECT a, b FROM mvmap WHERE b = ?", 0);
assertRowsNet(protocolVersion, mvRows, row(0, 0));
}
@Test
public void testMultipleNonPrimaryKeysInView() throws Throwable
{
createTable("CREATE TABLE %s (" +
"a int," +
"b int," +
"c int," +
"d int," +
"e int," +
"PRIMARY KEY ((a, b), c))");
try
{
createView("mv_de", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE a IS NOT NULL AND b IS NOT NULL AND c IS NOT NULL AND d IS NOT NULL AND e IS NOT NULL PRIMARY KEY ((d, a), b, e, c)");
fail("Should have rejected a query including multiple non-primary key base columns");
}
catch (Exception e)
{
}
try
{
createView("mv_de", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE a IS NOT NULL AND b IS NOT NULL AND c IS NOT NULL AND d IS NOT NULL AND e IS NOT NULL PRIMARY KEY ((a, b), c, d, e)");
fail("Should have rejected a query including multiple non-primary key base columns");
}
catch (Exception e)
{
}
}
@Test
public void testNullInClusteringColumns() throws Throwable
{
createTable("CREATE TABLE %s (id1 int, id2 int, v1 text, v2 text, PRIMARY KEY (id1, id2))");
executeNet(protocolVersion, "USE " + keyspace());
createView("mv",
"CREATE MATERIALIZED VIEW %s AS" +
" SELECT id1, v1, id2, v2" +
" FROM %%s" +
" WHERE id1 IS NOT NULL AND v1 IS NOT NULL AND id2 IS NOT NULL" +
" PRIMARY KEY (id1, v1, id2)" +
" WITH CLUSTERING ORDER BY (v1 DESC, id2 ASC)");
execute("INSERT INTO %s (id1, id2, v1, v2) VALUES (?, ?, ?, ?)", 0, 1, "foo", "bar");
assertRowsNet(protocolVersion, executeNet(protocolVersion, "SELECT * FROM %s"), row(0, 1, "foo", "bar"));
assertRowsNet(protocolVersion, executeNet(protocolVersion, "SELECT * FROM mv"), row(0, "foo", 1, "bar"));
executeNet(protocolVersion, "UPDATE %s SET v1=? WHERE id1=? AND id2=?", null, 0, 1);
assertRowsNet(protocolVersion, executeNet(protocolVersion, "SELECT * FROM %s"), row(0, 1, null, "bar"));
assertRowsNet(protocolVersion, executeNet(protocolVersion, "SELECT * FROM mv"));
executeNet(protocolVersion, "UPDATE %s SET v2=? WHERE id1=? AND id2=?", "rab", 0, 1);
assertRowsNet(protocolVersion, executeNet(protocolVersion, "SELECT * FROM %s"), row(0, 1, null, "rab"));
assertRowsNet(protocolVersion, executeNet(protocolVersion, "SELECT * FROM mv"));
}
@Test
public void testReservedKeywordsInMV() throws Throwable
{
createTable("CREATE TABLE %s (\"token\" int PRIMARY KEY, \"keyspace\" int)");
executeNet(protocolVersion, "USE " + keyspace());
createView("mv",
"CREATE MATERIALIZED VIEW %s AS" +
" SELECT \"keyspace\", \"token\"" +
" FROM %%s" +
" WHERE \"keyspace\" IS NOT NULL AND \"token\" IS NOT NULL" +
" PRIMARY KEY (\"keyspace\", \"token\")");
execute("INSERT INTO %s (\"token\", \"keyspace\") VALUES (?, ?)", 0, 1);
assertRowsNet(protocolVersion, executeNet(protocolVersion, "SELECT * FROM %s"), row(0, 1));
assertRowsNet(protocolVersion, executeNet(protocolVersion, "SELECT * FROM mv"), row(1, 0));
}
public void testCreateMvWithTTL() throws Throwable
{
createTable("CREATE TABLE %s (" +
"k int PRIMARY KEY, " +
"c int, " +
"val int) WITH default_time_to_live = 60");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
// Must NOT include "default_time_to_live" for Materialized View creation
try
{
createView("mv_ttl1", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE k IS NOT NULL AND c IS NOT NULL PRIMARY KEY (k,c) WITH default_time_to_live = 30");
fail("Should fail if TTL is provided for materialized view");
}
catch (Exception e)
{
}
}
@Test
public void testAlterMvWithTTL() throws Throwable
{
createTable("CREATE TABLE %s (" +
"k int PRIMARY KEY, " +
"c int, " +
"val int) WITH default_time_to_live = 60");
createView("mv_ttl2", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE k IS NOT NULL AND c IS NOT NULL PRIMARY KEY (k,c)");
// Must NOT include "default_time_to_live" on alter Materialized View
try
{
executeNet(protocolVersion, "ALTER MATERIALIZED VIEW %s WITH default_time_to_live = 30");
fail("Should fail if TTL is provided while altering materialized view");
}
catch (Exception e)
{
}
}
@Test
public void testViewBuilderResume() throws Throwable
{
createTable("CREATE TABLE %s (" +
"k int, " +
"c int, " +
"val text, " +
"PRIMARY KEY(k,c))");
execute("USE " + keyspace());
executeNet(protocolVersion, "USE " + keyspace());
CompactionManager.instance.setCoreCompactorThreads(1);
CompactionManager.instance.setMaximumCompactorThreads(1);
ColumnFamilyStore cfs = getCurrentColumnFamilyStore();
cfs.disableAutoCompaction();
for (int i = 0; i < 1024; i++)
execute("INSERT into %s (k,c,val)VALUES(?,?,?)", i, i, ""+i);
cfs.forceBlockingFlush();
for (int i = 0; i < 1024; i++)
execute("INSERT into %s (k,c,val)VALUES(?,?,?)", i, i, ""+i);
cfs.forceBlockingFlush();
for (int i = 0; i < 1024; i++)
execute("INSERT into %s (k,c,val)VALUES(?,?,?)", i, i, ""+i);
cfs.forceBlockingFlush();
for (int i = 0; i < 1024; i++)
execute("INSERT into %s (k,c,val)VALUES(?,?,?)", i, i, ""+i);
cfs.forceBlockingFlush();
createView("mv_test", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE val IS NOT NULL AND k IS NOT NULL AND c IS NOT NULL PRIMARY KEY (val,k,c)");
cfs.enableAutoCompaction();
List<Future<?>> futures = CompactionManager.instance.submitBackground(cfs);
//Force a second MV on the same base table, which will restart the first MV builder...
createView("mv_test2", "CREATE MATERIALIZED VIEW %s AS SELECT val, k, c FROM %%s WHERE val IS NOT NULL AND k IS NOT NULL AND c IS NOT NULL PRIMARY KEY (val,k,c)");
//Compact the base table
FBUtilities.waitOnFutures(futures);
while (!SystemKeyspace.isViewBuilt(keyspace(), "mv_test"))
Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
assertRows(execute("SELECT count(*) FROM mv_test"), row(1024L));
}
@Test(expected = SyntaxException.class)
public void emptyViewNameTest() throws Throwable
{
execute("CREATE MATERIALIZED VIEW \"\" AS SELECT a, b FROM tbl WHERE b IS NOT NULL PRIMARY KEY (b, a)");
}
@Test(expected = SyntaxException.class)
public void emptyBaseTableNameTest() throws Throwable
{
execute("CREATE MATERIALIZED VIEW myview AS SELECT a, b FROM \"\" WHERE b IS NOT NULL PRIMARY KEY (b, a)");
}
/**
* Tests that a client warning is issued on materialized view creation.
*/
@Test
public void testClientWarningOnCreate() throws Throwable
{
createTable("CREATE TABLE %s (k int PRIMARY KEY, v int)");
ClientWarn.instance.captureWarnings();
String viewName = keyspace() + ".warning_view";
execute("CREATE MATERIALIZED VIEW " + viewName +
" AS SELECT v FROM %s WHERE k IS NOT NULL AND v IS NOT NULL PRIMARY KEY (v, k)");
views.add(viewName);
List<String> warnings = ClientWarn.instance.getWarnings();
Assert.assertNotNull(warnings);
Assert.assertEquals(1, warnings.size());
Assert.assertEquals(View.USAGE_WARNING, warnings.get(0));
}
/**
* Tests the configuration flag to disable materialized views.
*/
@Test
public void testDisableMaterializedViews() throws Throwable
{
createTable("CREATE TABLE %s (k int PRIMARY KEY, v int)");
executeNet(protocolVersion, "USE " + keyspace());
boolean enableMaterializedViews = DatabaseDescriptor.getEnableMaterializedViews();
try
{
DatabaseDescriptor.setEnableMaterializedViews(false);
createView("view1", "CREATE MATERIALIZED VIEW %s AS SELECT v FROM %%s WHERE k IS NOT NULL AND v IS NOT NULL PRIMARY KEY (v, k)");
fail("Should not be able to create a materialized view if they are disabled");
}
catch (Throwable e)
{
Assert.assertTrue(e instanceof InvalidQueryException);
Assert.assertTrue(e.getMessage().contains("Materialized views are disabled"));
}
finally
{
DatabaseDescriptor.setEnableMaterializedViews(enableMaterializedViews);
}
}
@Test
public void viewOnCompactTableTest() throws Throwable
{
createTable("CREATE TABLE %s (a int, b int, v int, PRIMARY KEY (a, b)) WITH COMPACT STORAGE");
executeNet(protocolVersion, "USE " + keyspace());
try
{
createView("mv",
"CREATE MATERIALIZED VIEW %s AS SELECT a, b, value FROM %%s WHERE b IS NOT NULL PRIMARY KEY (b, a)");
fail("Should have thrown an exception");
}
catch (Throwable t)
{
Assert.assertEquals("Undefined column name value",
t.getMessage());
}
}
}