| /* |
| * 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.HashSet; |
| |
| import org.junit.Assert; |
| import org.junit.Test; |
| |
| import com.datastax.driver.core.ResultSet; |
| import com.datastax.driver.core.exceptions.InvalidQueryException; |
| import org.apache.cassandra.schema.ColumnMetadata; |
| import org.apache.cassandra.schema.TableMetadata; |
| |
| import static org.junit.Assert.assertTrue; |
| |
| /* |
| * This test class was too large and used to timeout CASSANDRA-16777. We're splitting it into: |
| * - ViewTest |
| * - ViewPKTest |
| * - ViewRangesTest |
| * - ViewTimesTest |
| */ |
| public class ViewPKTest extends ViewAbstractTest |
| { |
| @Test |
| public void testPartitionTombstone() throws Throwable |
| { |
| createTable("CREATE TABLE %s (k1 int, c1 int , val int, PRIMARY KEY (k1, c1))"); |
| |
| execute("USE " + keyspace()); |
| executeNet("USE " + keyspace()); |
| |
| createView("view1", "CREATE MATERIALIZED VIEW view1 AS SELECT k1, c1, val 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("USE " + keyspace()); |
| |
| createView("view1", "CREATE MATERIALIZED VIEW view1 AS SELECT val, k1, c1 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("USE " + keyspace()); |
| |
| createView("view1", "CREATE MATERIALIZED VIEW view1 AS SELECT k1, c1, val 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("USE " + keyspace()); |
| |
| // Must include "IS NOT NULL" for primary keys |
| try |
| { |
| createView("mv_test", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s"); |
| Assert.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)"); |
| Assert.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"); |
| Assert.fail("Should fail if no primary key is filtered as NOT NULL"); |
| } |
| catch (Exception e) |
| { |
| } |
| |
| // Must still include both even 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)"); |
| Assert.fail("Should fail if compound primary is not completely filtered as NOT NULL"); |
| } |
| catch (Exception e) |
| { |
| } |
| } |
| |
| @Test |
| public void testCompoundPartitionKey() throws Throwable |
| { |
| createTable("CREATE TABLE %s (" + |
| "k int, " + |
| "asciival ascii, " + |
| "bigintval bigint, " + |
| "PRIMARY KEY((k, asciival)))"); |
| |
| TableMetadata metadata = currentTableMetadata(); |
| |
| execute("USE " + keyspace()); |
| executeNet("USE " + keyspace()); |
| |
| for (ColumnMetadata def : new HashSet<>(metadata.columns())) |
| { |
| 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()) |
| Assert.fail("MV on a multicell should fail " + def); |
| } |
| catch (InvalidQueryException e) |
| { |
| if (!def.type.isMultiCell() && !def.isPartitionKey()) |
| Assert.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()) |
| Assert.fail("MV on a multicell should fail " + def); |
| } |
| catch (InvalidQueryException e) |
| { |
| if (!def.type.isMultiCell() && !def.isPartitionKey()) |
| Assert.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()) |
| Assert.fail("MV on a multicell should fail " + def); |
| } |
| catch (InvalidQueryException e) |
| { |
| if (!def.type.isMultiCell() && !def.isPartitionKey()) |
| Assert.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); |
| |
| Assert.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("mv4_" + def.name, query); |
| Assert.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 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("USE " + keyspace()); |
| |
| createView("mv1", "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 (a, b, c) WITH CLUSTERING ORDER BY (b DESC, c ASC)"); |
| createView("mv2", "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 (a, c, b) WITH CLUSTERING ORDER BY (c ASC, b ASC)"); |
| createView("mv3", "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 (a, b, c)"); |
| createView("mv4", "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 (a, c, b) WITH CLUSTERING ORDER BY (c DESC, b ASC)"); |
| |
| 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("SELECT b FROM mv1"); |
| assertRowsNet(mvRows, row(2), row(1)); |
| |
| mvRows = executeNet("SELECT c FROM mv2"); |
| assertRowsNet(mvRows, row(1), row(2)); |
| |
| mvRows = executeNet("SELECT b FROM mv3"); |
| assertRowsNet(mvRows, row(1), row(2)); |
| |
| mvRows = executeNet("SELECT c FROM mv4"); |
| assertRowsNet(mvRows, row(2), row(1)); |
| } |
| |
| @Test |
| public void testPrimaryKeyOnlyTable() throws Throwable |
| { |
| createTable("CREATE TABLE %s (" + |
| "a int," + |
| "b int," + |
| "PRIMARY KEY (a, b))"); |
| |
| executeNet("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("SELECT a, b FROM mv1"); |
| assertRowsNet(mvRows, row(1, 1)); |
| } |
| |
| @Test |
| public void testPartitionKeyOnlyTable() throws Throwable |
| { |
| createTable("CREATE TABLE %s (" + |
| "a int," + |
| "b int," + |
| "PRIMARY KEY ((a, b)))"); |
| |
| executeNet("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("SELECT a, b FROM mv1"); |
| assertRowsNet(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("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("SELECT a, d, b, c FROM mv1"); |
| assertRowsNet(mvRows, row(0, 0, 0, 0)); |
| |
| updateView("DELETE c FROM %s WHERE a = ? AND b = ?", 0, 0); |
| mvRows = executeNet("SELECT a, d, b, c FROM mv1"); |
| assertRowsNet(mvRows, row(0, 0, 0, null)); |
| |
| updateView("DELETE d FROM %s WHERE a = ? AND b = ?", 0, 0); |
| mvRows = executeNet("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("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("SELECT a, d, b, c FROM mv1"); |
| assertRowsNet(mvRows, row(0, 0, 0, 0)); |
| |
| updateView("DELETE c FROM %s WHERE a = ? AND b = ?", 0, 0); |
| mvRows = executeNet("SELECT a, d, b, c FROM mv1"); |
| assertRowsNet(mvRows, row(0, 0, 0, null)); |
| |
| updateView("DELETE d FROM %s WHERE a = ? AND b = ?", 0, 0); |
| mvRows = executeNet("SELECT a, d, b FROM mv1"); |
| assertTrue(mvRows.isExhausted()); |
| } |
| |
| @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)"); |
| Assert.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)"); |
| Assert.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("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(executeNet("SELECT * FROM %s"), row(0, 1, "foo", "bar")); |
| assertRowsNet(executeNet("SELECT * FROM mv"), row(0, "foo", 1, "bar")); |
| |
| executeNet("UPDATE %s SET v1=? WHERE id1=? AND id2=?", null, 0, 1); |
| assertRowsNet(executeNet("SELECT * FROM %s"), row(0, 1, null, "bar")); |
| assertRowsNet(executeNet("SELECT * FROM mv")); |
| |
| executeNet("UPDATE %s SET v2=? WHERE id1=? AND id2=?", "rab", 0, 1); |
| assertRowsNet(executeNet("SELECT * FROM %s"), row(0, 1, null, "rab")); |
| assertRowsNet(executeNet("SELECT * FROM mv")); |
| } |
| } |