content: /*
   * 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;
  
  public class SecondaryIndexOnStaticColumnTest extends CQLTester
  {
      @Test
      public void testSimpleStaticColumn() throws Throwable
      {
          createTable("CREATE TABLE %s (id int, name text, age int static, PRIMARY KEY (id, name))");
  
          createIndex("CREATE INDEX static_age on %s(age)");
          int id1 = 1, id2 = 2, age1 = 24, age2 = 32;
          String name1A = "Taylor", name1B = "Swift",
                 name2 = "Jamie";
  
          execute("INSERT INTO %s (id, name, age) VALUES (?, ?, ?)", id1, name1A, age1);
          execute("INSERT INTO %s (id, name, age) VALUES (?, ?, ?)", id1, name1B, age1);
          execute("INSERT INTO %s (id, name, age) VALUES (?, ?, ?)", id2, name2, age2);
  
          assertRows(execute("SELECT id, name, age FROM %s WHERE age=?", age1),
                row(id1, name1B, age1), row(id1, name1A, age1));
          assertRows(execute("SELECT id, name, age FROM %s WHERE age=?", age2),
                  row(id2, name2, age2));
  
          // Update the rows. Validate that updated values will be reflected in the index.
          int newAge1 = 40;
          execute("UPDATE %s SET age = ? WHERE id = ?", newAge1, id1);
          assertEmpty(execute("SELECT id, name, age FROM %s WHERE age=?", age1));
          assertRows(execute("SELECT id, name, age FROM %s WHERE age=?", newAge1),
                  row(id1, name1B, newAge1), row(id1, name1A, newAge1));
          execute("DELETE FROM %s WHERE id = ?", id2);
          assertEmpty(execute("SELECT id, name, age FROM %s WHERE age=?", age2));
      }
  
      @Test
      public void testIndexOnCompoundRowKey() throws Throwable
      {
          createTable("CREATE TABLE %s (interval text, seq int, id int, severity int static, 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, 3, 10)");
          execute("insert into %s (interval, seq, id , severity) values('t',1, 4, 10)");
          execute("insert into %s (interval, seq, id , severity) values('t',2, 3, 10)");
          execute("insert into %s (interval, seq, id , severity) values('t',2, 4, 10)");
          execute("insert into %s (interval, seq, id , severity) values('m',1, 3, 11)");
          execute("insert into %s (interval, seq, id , severity) values('m',1, 4, 11)");
          execute("insert into %s (interval, seq, id , severity) values('m',2, 3, 11)");
          execute("insert into %s (interval, seq, id , severity) values('m',2, 4, 11)");
  
          assertRows(execute("select * from %s where severity = 10 and interval = 't' and seq = 1"),
                     row("t", 1, 4, 10), row("t", 1, 3, 10));
      }
  
      @Test
      public void testIndexOnCollections() throws Throwable
      {
          createTable("CREATE TABLE %s (k int, v int, l list<int> static, s set<text> static, m map<text, int> static, PRIMARY KEY (k, v))");
  
          createIndex("CREATE INDEX ON %s (l)");
          createIndex("CREATE INDEX ON %s (s)");
          createIndex("CREATE INDEX ON %s (m)");
          createIndex("CREATE INDEX ON %s (keys(m))");
  
          execute("INSERT INTO %s (k, v, l, s, m) VALUES (0, 0, [1, 2],    {'a'},      {'a' : 1, 'b' : 2})");
          execute("INSERT INTO %s (k, v)          VALUES (0, 1)                                  ");
          execute("INSERT INTO %s (k, v, l, s, m) VALUES (1, 0, [4, 5],    {'d'},      {'b' : 1, 'c' : 4})");
  
          // lists
          assertRows(execute("SELECT k, v FROM %s WHERE l CONTAINS 1"), row(0, 0), row(0, 1));
          assertEmpty(execute("SELECT k, v FROM %s WHERE k = 1 AND l CONTAINS 1"));
          assertRows(execute("SELECT k, v FROM %s WHERE l CONTAINS 4"), row(1, 0));
          assertEmpty(execute("SELECT k, v FROM %s WHERE l CONTAINS 6"));
  
          // update lists
          execute("UPDATE %s SET l = l + [3] WHERE k = ?", 0);
          assertRows(execute("SELECT k, v FROM %s WHERE l CONTAINS 3"), row(0, 0), row(0, 1));
  
          // sets
          assertRows(execute("SELECT k, v FROM %s WHERE s CONTAINS 'a'"), row(0, 0), row(0, 1));
          assertRows(execute("SELECT k, v FROM %s WHERE k = 0 AND s CONTAINS 'a'"), row(0, 0), row(0, 1));
          assertRows(execute("SELECT k, v FROM %s WHERE s CONTAINS 'd'"), row(1, 0));
          assertEmpty(execute("SELECT k, v FROM %s  WHERE s CONTAINS 'e'"));
  
          // update sets
          execute("UPDATE %s SET s = s + {'b'} WHERE k = ?", 0);
          assertRows(execute("SELECT k, v FROM %s WHERE s CONTAINS 'b'"), row(0, 0), row(0, 1));
          execute("UPDATE %s SET s = s - {'a'} WHERE k = ?", 0);
          assertEmpty(execute("SELECT k, v FROM %s WHERE s CONTAINS 'a'"));
  
          // maps
          assertRows(execute("SELECT k, v FROM %s WHERE m CONTAINS 1"), row(1, 0), 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 4"), row(1, 0));
          assertEmpty(execute("SELECT k, v FROM %s  WHERE m CONTAINS 5"));
  
          assertRows(execute("SELECT k, v FROM %s WHERE m CONTAINS KEY 'b'"), row(1, 0), row(0, 0), row(0, 1));
          assertRows(execute("SELECT k, v FROM %s WHERE k = 0 AND m CONTAINS KEY 'b'"), row(0, 0), row(0, 1));
          assertRows(execute("SELECT k, v FROM %s WHERE m CONTAINS KEY 'c'"), row(1, 0));
          assertEmpty(execute("SELECT k, v FROM %s  WHERE m CONTAINS KEY 'd'"));
  
          // update maps.
          execute("UPDATE %s SET m['c'] = 5 WHERE k = 0");
          assertRows(execute("SELECT k, v FROM %s WHERE m CONTAINS 5"), row(0, 0), row(0, 1));
          assertRows(execute("SELECT k, v FROM %s WHERE m CONTAINS KEY 'c'"), row(1, 0), row(0, 0), row(0, 1));
          execute("DELETE m['a'] FROM %s WHERE k = 0");
          assertEmpty(execute("SELECT k, v FROM %s  WHERE m CONTAINS KEY 'a'"));
      }
  
      @Test
      public void testIndexOnFrozenCollections() throws Throwable
      {
          createTable("CREATE TABLE %s (k int, v int, l frozen<list<int>> static, s frozen<set<text>> static, m frozen<map<text, int>> static, PRIMARY KEY (k, v))");
  
          createIndex("CREATE INDEX ON %s (FULL(l))");
          createIndex("CREATE INDEX ON %s (FULL(s))");
          createIndex("CREATE INDEX ON %s (FULL(m))");
  
          execute("INSERT INTO %s (k, v, l, s, m) VALUES (0, 0, [1, 2],    {'a'},      {'a' : 1, 'b' : 2})");
          execute("INSERT INTO %s (k, v)          VALUES (0, 1)                                  ");
          execute("INSERT INTO %s (k, v, l, s, m) VALUES (1, 0, [4, 5],    {'d'},      {'b' : 1, 'c' : 4})");
          execute("UPDATE %s SET l=[3], s={'3'}, m={'3': 3} WHERE k=3" );
  
          // lists
          assertRows(execute("SELECT k, v FROM %s WHERE l = [1, 2]"), row(0, 0), row(0, 1));
          assertEmpty(execute("SELECT k, v FROM %s WHERE k = 1 AND l = [1, 2]"));
          assertEmpty(execute("SELECT k, v FROM %s WHERE l = [4]"));
          assertRows(execute("SELECT k, v FROM %s WHERE l = [3]"), row(3, null));
  
          // update lists
          execute("UPDATE %s SET l = [1, 2, 3] WHERE k = ?", 0);
          assertEmpty(execute("SELECT k, v FROM %s WHERE l = [1, 2]"));
          assertRows(execute("SELECT k, v FROM %s WHERE l = [1, 2, 3]"), row(0, 0), row(0, 1));
  
          // sets
          assertRows(execute("SELECT k, v FROM %s WHERE s = {'a'}"), row(0, 0), row(0, 1));
          assertEmpty(execute("SELECT k, v FROM %s WHERE k = 1 AND s = {'a'}"));
          assertEmpty(execute("SELECT k, v FROM %s WHERE s = {'b'}"));
          assertRows(execute("SELECT k, v FROM %s WHERE s = {'3'}"), row(3, null));
  
          // update sets
          execute("UPDATE %s SET s = {'a', 'b'} WHERE k = ?", 0);
          assertEmpty(execute("SELECT k, v FROM %s WHERE s = {'a'}"));
          assertRows(execute("SELECT k, v FROM %s WHERE s = {'a', 'b'}"), row(0, 0), row(0, 1));
  
          // maps
          assertRows(execute("SELECT k, v FROM %s WHERE m = {'a' : 1, 'b' : 2}"), row(0, 0), row(0, 1));
          assertEmpty(execute("SELECT k, v FROM %s WHERE k = 1 AND m = {'a' : 1, 'b' : 2}"));
          assertEmpty(execute("SELECT k, v FROM %s WHERE m = {'a' : 1, 'b' : 3}"));
          assertEmpty(execute("SELECT k, v FROM %s WHERE m = {'a' : 1, 'c' : 2}"));
          assertRows(execute("SELECT k, v FROM %s WHERE m = {'3': 3}"), row(3, null));
  
          // update maps.
          execute("UPDATE %s SET m = {'a': 2, 'b': 3} WHERE k = ?", 0);
          assertEmpty(execute("SELECT k, v FROM %s WHERE m = {'a': 1, 'b': 2}"));
          assertRows(execute("SELECT k, v FROM %s WHERE m = {'a': 2, 'b': 3}"), row(0, 0), row(0, 1));
      }
  
      @Test
      public void testStaticIndexAndNonStaticIndex() throws Throwable
      {
          createTable("CREATE TABLE %s (id int, company text, age int static, salary int, PRIMARY KEY(id, company))");
          createIndex("CREATE INDEX on %s(age)");
          createIndex("CREATE INDEX on %s(salary)");
  
          String company1 = "company1", company2 = "company2";
  
          execute("INSERT INTO %s(id, company, age, salary) VALUES(?, ?, ?, ?)", 1, company1, 20, 1000);
          execute("INSERT INTO %s(id, company,      salary) VALUES(?, ?,    ?)", 1, company2,     2000);
          execute("INSERT INTO %s(id, company, age, salary) VALUES(?, ?, ?, ?)", 2, company1, 40, 2000);
  
          assertRows(execute("SELECT id, company, age, salary FROM %s WHERE age = 20 AND salary = 2000 ALLOW FILTERING"),
                     row(1, company2, 20, 2000));
      }
  
      @Test
      public void testIndexOnUDT() throws Throwable
      {
          String typeName = createType("CREATE TYPE %s (street text, city text)");
  
          createTable(String.format(
              "CREATE TABLE %%s (id int, company text, home frozen<%s> static, price int, PRIMARY KEY(id, company))",
              typeName));
          createIndex("CREATE INDEX on %s(home)");
  
          String addressString = "{street: 'Centre', city: 'C'}";
          String companyName = "Random";
  
          execute("INSERT INTO %s(id, company, home, price) "
                  + "VALUES(1, '" + companyName + "', " + addressString + ", 10000)");
          assertRows(execute("SELECT id, company FROM %s WHERE home = " + addressString), row(1, companyName));
          String newAddressString = "{street: 'Fifth', city: 'P'}";
  
          execute("UPDATE %s SET home = " + newAddressString + " WHERE id = 1");
          assertEmpty(execute("SELECT id, company FROM %s WHERE home = " + addressString));
          assertRows(execute("SELECT id, company FROM %s WHERE home = " + newAddressString), row(1, companyName));
      }
  }
  