Handle single-col deletions in MVs correctly

Patch by Tyler Hobbs; reviewed by Carl Yeksigian for CASSANDRA-10796


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/83f8ccc6
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/83f8ccc6
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/83f8ccc6

Branch: refs/heads/cassandra-3.1
Commit: 83f8ccc6685bf81a5264c3dfa1969ce061d2bc61
Parents: d0da9e7
Author: Tyler Hobbs <tylerlho...@gmail.com>
Authored: Fri Dec 4 11:42:13 2015 -0600
Committer: Tyler Hobbs <tylerlho...@gmail.com>
Committed: Fri Dec 4 11:42:13 2015 -0600

----------------------------------------------------------------------
 CHANGES.txt                                     |   2 +
 .../apache/cassandra/db/rows/AbstractCell.java  |   5 +-
 .../apache/cassandra/db/rows/AbstractRow.java   |   6 +-
 .../apache/cassandra/db/view/TemporalRow.java   |   6 +-
 src/java/org/apache/cassandra/db/view/View.java |  15 +-
 .../apache/cassandra/db/view/ViewManager.java   |   4 +
 .../apache/cassandra/service/StorageProxy.java  |  14 +-
 .../apache/cassandra/cql3/ViewSchemaTest.java   | 762 +++++++++++++++++++
 .../org/apache/cassandra/cql3/ViewTest.java     | 707 +----------------
 9 files changed, 838 insertions(+), 683 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/83f8ccc6/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 520afff..c22d138 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,6 @@
 3.0.1
+ * Handle single-column deletions correction in materialized views
+   when the column is part of the view primary key (CASSANDRA-10796)
  * Fix issue with datadir migration on upgrade (CASSANDRA-10788)
  * Fix bug with range tombstones on reverse queries and test coverage for
    AbstractBTreePartition (CASSANDRA-10059)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/83f8ccc6/src/java/org/apache/cassandra/db/rows/AbstractCell.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/rows/AbstractCell.java 
b/src/java/org/apache/cassandra/db/rows/AbstractCell.java
index e804b7a..882c0e0 100644
--- a/src/java/org/apache/cassandra/db/rows/AbstractCell.java
+++ b/src/java/org/apache/cassandra/db/rows/AbstractCell.java
@@ -110,7 +110,10 @@ public abstract class AbstractCell extends Cell
                                  ct.valueComparator().getString(value()),
                                  livenessInfoString());
         }
-        return String.format("[%s=%s %s]", column().name, 
type.getString(value()), livenessInfoString());
+        if (isTombstone())
+            return String.format("[%s=<tombstone> %s]", column().name, 
livenessInfoString());
+        else
+            return String.format("[%s=%s %s]", column().name, 
type.getString(value()), livenessInfoString());
     }
 
     private String livenessInfoString()

http://git-wip-us.apache.org/repos/asf/cassandra/blob/83f8ccc6/src/java/org/apache/cassandra/db/rows/AbstractRow.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/rows/AbstractRow.java 
b/src/java/org/apache/cassandra/db/rows/AbstractRow.java
index 8958575..484f981 100644
--- a/src/java/org/apache/cassandra/db/rows/AbstractRow.java
+++ b/src/java/org/apache/cassandra/db/rows/AbstractRow.java
@@ -126,7 +126,11 @@ public abstract class AbstractRow extends 
AbstractCollection<ColumnData> impleme
                 if (cd.column().isSimple())
                 {
                     Cell cell = (Cell)cd;
-                    
sb.append(cell.column().name).append('=').append(cell.column().type.getString(cell.value()));
+                    sb.append(cell.column().name).append('=');
+                    if (cell.isTombstone())
+                        sb.append("<tombstone>");
+                    else
+                        sb.append(cell.column().type.getString(cell.value()));
                 }
                 else
                 {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/83f8ccc6/src/java/org/apache/cassandra/db/view/TemporalRow.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/view/TemporalRow.java 
b/src/java/org/apache/cassandra/db/view/TemporalRow.java
index 01da6e7..8898857 100644
--- a/src/java/org/apache/cassandra/db/view/TemporalRow.java
+++ b/src/java/org/apache/cassandra/db/view/TemporalRow.java
@@ -426,7 +426,11 @@ public class TemporalRow
 
             Collection<org.apache.cassandra.db.rows.Cell> val = 
values(definition, resolver);
             if (val != null && val.size() == 1)
-                return Iterables.getOnlyElement(val).value();
+            {
+                org.apache.cassandra.db.rows.Cell cell = 
Iterables.getOnlyElement(val);
+                // handle single-column deletions correctly
+                return cell.isTombstone() ? null : cell.value();
+            }
         }
         return null;
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/83f8ccc6/src/java/org/apache/cassandra/db/view/View.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/view/View.java 
b/src/java/org/apache/cassandra/db/view/View.java
index 9388288..30e9776 100644
--- a/src/java/org/apache/cassandra/db/view/View.java
+++ b/src/java/org/apache/cassandra/db/view/View.java
@@ -43,6 +43,8 @@ import org.apache.cassandra.service.ClientState;
 import org.apache.cassandra.service.pager.QueryPager;
 import org.apache.cassandra.transport.Server;
 import org.apache.cassandra.utils.FBUtilities;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * A View copies data from a base table into a view table which can be queried 
independently from the
@@ -58,6 +60,8 @@ import org.apache.cassandra.utils.FBUtilities;
  */
 public class View
 {
+    private static final Logger logger = LoggerFactory.getLogger(View.class);
+
     /**
      * The columns should all be updated together, so we use this object as 
group.
      */
@@ -356,7 +360,14 @@ public class View
         CBuilder clustering = CBuilder.create(viewCfm.comparator);
         for (int i = 0; i < viewCfm.clusteringColumns().size(); i++)
         {
-            
clustering.add(temporalRow.clusteringValue(viewCfm.clusteringColumns().get(i), 
resolver));
+            ColumnDefinition column = viewCfm.clusteringColumns().get(i);
+            ByteBuffer value = temporalRow.clusteringValue(column, resolver);
+
+            // handle single-column deletions correctly to avoid nulls in the 
view primary key
+            if (value == null)
+                return null;
+
+            clustering.add(value);
         }
         regularBuilder.newRow(clustering.build());
         regularBuilder.addPrimaryKeyLivenessInfo(LivenessInfo.create(viewCfm,
@@ -663,7 +674,7 @@ public class View
         {
             // In updateAffectsView, we check the partition to see if there is 
at least one row that matches the
             // filters and is live.  If there is more than one row in the 
partition, we need to re-check each one
-            // invididually.
+            // individually.
             if (partition.rowCount() != 1 && 
!selectQuery.selectsClustering(partition.partitionKey(), 
temporalRow.baseClustering()))
                 continue;
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/83f8ccc6/src/java/org/apache/cassandra/db/view/ViewManager.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/view/ViewManager.java 
b/src/java/org/apache/cassandra/db/view/ViewManager.java
index c11e641..9fe0544 100644
--- a/src/java/org/apache/cassandra/db/view/ViewManager.java
+++ b/src/java/org/apache/cassandra/db/view/ViewManager.java
@@ -34,6 +34,8 @@ import org.apache.cassandra.db.commitlog.ReplayPosition;
 import org.apache.cassandra.db.partitions.PartitionUpdate;
 import org.apache.cassandra.dht.Token;
 import org.apache.cassandra.service.StorageProxy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Manages {@link View}'s for a single {@link ColumnFamilyStore}. All of the 
views for that table are created when this
@@ -46,6 +48,8 @@ import org.apache.cassandra.service.StorageProxy;
  */
 public class ViewManager
 {
+    private static final Logger logger = 
LoggerFactory.getLogger(ViewManager.class);
+
     public class ForStore
     {
         private final ConcurrentNavigableMap<String, View> viewsByName;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/83f8ccc6/src/java/org/apache/cassandra/service/StorageProxy.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/service/StorageProxy.java 
b/src/java/org/apache/cassandra/service/StorageProxy.java
index 7ff07fc..15be7c6 100644
--- a/src/java/org/apache/cassandra/service/StorageProxy.java
+++ b/src/java/org/apache/cassandra/service/StorageProxy.java
@@ -704,9 +704,21 @@ public class StorageProxy implements StorageProxyMBean
                     // When local node is the endpoint and there are no 
pending nodes we can
                     // Just apply the mutation locally.
                     if 
(pairedEndpoint.equals(FBUtilities.getBroadcastAddress()) && 
wrapper.handler.pendingEndpoints.isEmpty() && 
StorageService.instance.isJoined())
-                        mutation.apply(writeCommitLog);
+                    {
+                        try
+                        {
+                            mutation.apply(writeCommitLog);
+                        }
+                        catch (Exception exc)
+                        {
+                            logger.error("Error applying local view update to 
keyspace {}: {}", mutation.getKeyspaceName(), mutation);
+                            throw exc;
+                        }
+                    }
                     else
+                    {
                         wrappers.add(wrapper);
+                    }
                 }
 
                 if (!wrappers.isEmpty())

http://git-wip-us.apache.org/repos/asf/cassandra/blob/83f8ccc6/test/unit/org/apache/cassandra/cql3/ViewSchemaTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/ViewSchemaTest.java 
b/test/unit/org/apache/cassandra/cql3/ViewSchemaTest.java
new file mode 100644
index 0000000..b34f475
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/ViewSchemaTest.java
@@ -0,0 +1,762 @@
+/*
+ * 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.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.UUID;
+
+import junit.framework.Assert;
+
+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.Schema;
+import org.apache.cassandra.db.SystemKeyspace;
+import org.apache.cassandra.serializers.SimpleDateSerializer;
+import org.apache.cassandra.serializers.TimeSerializer;
+import org.apache.cassandra.utils.ByteBufferUtil;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.datastax.driver.core.exceptions.InvalidQueryException;
+
+
+public class ViewSchemaTest extends CQLTester
+{
+    int protocolVersion = 4;
+    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 testCaseSensitivity() throws Throwable
+    {
+        createTable("CREATE TABLE %s (\"theKey\" int, \"theClustering\" int, 
\"theValue\" int, PRIMARY KEY (\"theKey\", \"theClustering\"))");
+
+        execute("USE " + keyspace());
+        executeNet(protocolVersion, "USE " + keyspace());
+
+        execute("INSERT INTO %s (\"theKey\", \"theClustering\", \"theValue\") 
VALUES (?, ?, ?)", 0, 0, 0);
+
+        createView("mv_test", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM 
%%s " +
+                              "WHERE \"theKey\" IS NOT NULL AND 
\"theClustering\" IS NOT NULL AND \"theValue\" IS NOT NULL " +
+                              "PRIMARY KEY (\"theKey\", \"theClustering\")");
+
+        while (!SystemKeyspace.isViewBuilt(keyspace(), "mv_test"))
+            Thread.sleep(10);
+        createView("mv_test2", "CREATE MATERIALIZED VIEW %s AS SELECT 
\"theKey\", \"theClustering\", \"theValue\" FROM %%s " +
+                               "WHERE \"theKey\" IS NOT NULL AND 
\"theClustering\" IS NOT NULL AND \"theValue\" IS NOT NULL " +
+                               "PRIMARY KEY (\"theKey\", \"theClustering\")");
+        while (!SystemKeyspace.isViewBuilt(keyspace(), "mv_test2"))
+            Thread.sleep(10);
+
+        for (String mvname : Arrays.asList("mv_test", "mv_test2"))
+        {
+            assertRows(execute("SELECT \"theKey\", \"theClustering\", 
\"theValue\" FROM " + mvname),
+               row(0, 0, 0)
+            );
+        }
+
+        executeNet(protocolVersion, "ALTER TABLE %s RENAME \"theClustering\" 
TO \"Col\"");
+
+        for (String mvname : Arrays.asList("mv_test", "mv_test2"))
+        {
+            assertRows(execute("SELECT \"theKey\", \"Col\", \"theValue\" FROM 
" + mvname),
+                       row(0, 0, 0)
+            );
+        }
+    }
+
+    @Test
+    public void testAccessAndSchema() throws Throwable
+    {
+        createTable("CREATE TABLE %s (" +
+                    "k int, " +
+                    "asciival ascii, " +
+                    "bigintval bigint, " +
+                    "PRIMARY KEY((k, asciival)))");
+
+        execute("USE " + keyspace());
+        executeNet(protocolVersion, "USE " + keyspace());
+
+        createView("mv1_test", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM 
%%s WHERE bigintval IS NOT NULL AND k IS NOT NULL AND asciival IS NOT NULL 
PRIMARY KEY (bigintval, k, asciival)");
+        updateView("INSERT INTO %s(k,asciival,bigintval)VALUES(?,?,?)", 0, 
"foo", 1L);
+
+        try
+        {
+            updateView("INSERT INTO mv1_test(k,asciival,bigintval) 
VALUES(?,?,?)", 1, "foo", 2L);
+            Assert.fail("Shouldn't be able to modify a MV directly");
+        }
+        catch (Exception e)
+        {
+        }
+
+        try
+        {
+            executeNet(protocolVersion, "ALTER TABLE mv1_test ADD foo text");
+            Assert.fail("Should not be able to use alter table with MV");
+        }
+        catch (Exception e)
+        {
+        }
+
+        try
+        {
+            executeNet(protocolVersion, "ALTER TABLE mv1_test WITH compaction 
= { 'class' : 'LeveledCompactionStrategy' }");
+            Assert.fail("Should not be able to use alter table with MV");
+        }
+        catch (Exception e)
+        {
+        }
+
+        executeNet(protocolVersion, "ALTER MATERIALIZED VIEW mv1_test WITH 
compaction = { 'class' : 'LeveledCompactionStrategy' }");
+
+        //Test alter add
+        executeNet(protocolVersion, "ALTER TABLE %s ADD foo text");
+        CFMetaData metadata = Schema.instance.getCFMetaData(keyspace(), 
"mv1_test");
+        
Assert.assertNotNull(metadata.getColumnDefinition(ByteBufferUtil.bytes("foo")));
+
+        updateView("INSERT INTO %s(k,asciival,bigintval,foo)VALUES(?,?,?,?)", 
0, "foo", 1L, "bar");
+        assertRows(execute("SELECT foo from %s"), row("bar"));
+
+        //Test alter rename
+        executeNet(protocolVersion, "ALTER TABLE %s RENAME asciival TO bar");
+
+        assertRows(execute("SELECT bar from %s"), row("foo"));
+        metadata = Schema.instance.getCFMetaData(keyspace(), "mv1_test");
+        
Assert.assertNotNull(metadata.getColumnDefinition(ByteBufferUtil.bytes("bar")));
+    }
+
+
+    @Test
+    public void testTwoTablesOneView() throws Throwable
+    {
+        execute("USE " + keyspace());
+        executeNet(protocolVersion, "USE " + keyspace());
+
+        createTable("CREATE TABLE " + keyspace() + ".dummy_table (" +
+                "j int, " +
+                "intval int, " +
+                "PRIMARY KEY (j))");
+
+        createTable("CREATE TABLE " + keyspace() + ".real_base (" +
+                "k int, " +
+                "intval int, " +
+                "PRIMARY KEY (k))");
+
+        createView("mv", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM " + 
keyspace() + ".real_base WHERE k IS NOT NULL AND intval IS NOT NULL PRIMARY KEY 
(intval, k)");
+        createView("mv2", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM " + 
keyspace() + ".dummy_table WHERE j IS NOT NULL AND intval IS NOT NULL PRIMARY 
KEY (intval, j)");
+
+        updateView("INSERT INTO " + keyspace() + ".real_base (k, intval) 
VALUES (?, ?)", 0, 0);
+        assertRows(execute("SELECT k, intval FROM " + keyspace() + ".real_base 
WHERE k = ?", 0), row(0, 0));
+        assertRows(execute("SELECT k, intval from mv WHERE intval = ?", 0), 
row(0, 0));
+
+        updateView("INSERT INTO " + keyspace() + ".real_base (k, intval) 
VALUES (?, ?)", 0, 1);
+        assertRows(execute("SELECT k, intval FROM " + keyspace() + ".real_base 
WHERE k = ?", 0), row(0, 1));
+        assertRows(execute("SELECT k, intval from mv WHERE intval = ?", 1), 
row(0, 1));
+
+        assertRows(execute("SELECT k, intval FROM " + keyspace() + ".real_base 
WHERE k = ?", 0), row(0, 1));
+        assertRows(execute("SELECT k, intval from mv WHERE intval = ?", 1), 
row(0, 1));
+
+        updateView("INSERT INTO " + keyspace() +".dummy_table (j, intval) 
VALUES(?, ?)", 0, 1);
+        assertRows(execute("SELECT j, intval FROM " + keyspace() + 
".dummy_table WHERE j = ?", 0), row(0, 1));
+        assertRows(execute("SELECT k, intval from mv WHERE intval = ?", 1), 
row(0, 1));
+    }
+
+    @Test
+    public void testReuseName() 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));
+
+        executeNet(protocolVersion, "DROP MATERIALIZED VIEW mv");
+        views.remove("mv");
+
+        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, 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 testAllTypes() throws Throwable
+    {
+        String myType = createType("CREATE TYPE %s (a int, b uuid, c 
set<text>)");
+
+        createTable("CREATE TABLE %s (" +
+                    "k int PRIMARY KEY, " +
+                    "asciival ascii, " +
+                    "bigintval bigint, " +
+                    "blobval blob, " +
+                    "booleanval boolean, " +
+                    "dateval date, " +
+                    "decimalval decimal, " +
+                    "doubleval double, " +
+                    "floatval float, " +
+                    "inetval inet, " +
+                    "intval int, " +
+                    "textval text, " +
+                    "timeval time, " +
+                    "timestampval timestamp, " +
+                    "timeuuidval timeuuid, " +
+                    "uuidval uuid," +
+                    "varcharval varchar, " +
+                    "varintval varint, " +
+                    "listval list<int>, " +
+                    "frozenlistval frozen<list<int>>, " +
+                    "setval set<uuid>, " +
+                    "frozensetval frozen<set<uuid>>, " +
+                    "mapval map<ascii, int>," +
+                    "frozenmapval frozen<map<ascii, int>>," +
+                    "tupleval frozen<tuple<int, ascii, uuid>>," +
+                    "udtval frozen<" + myType + ">)");
+
+        CFMetaData metadata = currentTableMetadata();
+
+        execute("USE " + keyspace());
+        executeNet(protocolVersion, "USE " + keyspace());
+
+        for (ColumnDefinition def : new HashSet<>(metadata.allColumns()))
+        {
+            try
+            {
+                createView("mv_" + def.name, "CREATE MATERIALIZED VIEW %s AS 
SELECT * FROM %%s WHERE " + def.name + " IS NOT NULL AND k IS NOT NULL PRIMARY 
KEY (" + def.name + ",k)");
+
+                if (def.type.isMultiCell())
+                    Assert.fail("MV on a multicell should fail " + def);
+
+                if (def.isPartitionKey())
+                    Assert.fail("MV on partition key should fail " + def);
+            }
+            catch (InvalidQueryException e)
+            {
+                if (!def.type.isMultiCell() && !def.isPartitionKey())
+                    Assert.fail("MV creation failed on " + def);
+            }
+        }
+
+        // fromJson() can only be used when the receiver type is known
+        assertInvalidMessage("fromJson() cannot be used in the selection 
clause", "SELECT fromJson(asciival) FROM %s", 0, 0);
+
+        String func1 = createFunction(KEYSPACE, "int", "CREATE FUNCTION %s (a 
int) CALLED ON NULL INPUT RETURNS text LANGUAGE java AS $$ return a.toString(); 
$$");
+        createFunctionOverload(func1, "int", "CREATE FUNCTION %s (a text) 
CALLED ON NULL INPUT RETURNS text LANGUAGE java AS $$ return new String(a); 
$$");
+
+        // ================ ascii ================
+        updateView("INSERT INTO %s (k, asciival) VALUES (?, fromJson(?))", 0, 
"\"ascii text\"");
+        assertRows(execute("SELECT k, asciival FROM %s WHERE k = ?", 0), 
row(0, "ascii text"));
+
+        updateView("INSERT INTO %s (k, asciival) VALUES (?, fromJson(?))", 0, 
"\"ascii \\\" text\"");
+        assertRows(execute("SELECT k, asciival FROM %s WHERE k = ?", 0), 
row(0, "ascii \" text"));
+
+        // test that we can use fromJson() in other valid places in queries
+        assertRows(execute("SELECT asciival FROM %s WHERE k = fromJson(?)", 
"0"), row("ascii \" text"));
+
+        //Check the MV
+        assertRows(execute("SELECT k, udtval from mv_asciival WHERE asciival = 
?", "ascii text"));
+        assertRows(execute("SELECT k, udtval from mv_asciival WHERE asciival = 
?", "ascii \" text"), row(0, null));
+
+        updateView("UPDATE %s SET asciival = fromJson(?) WHERE k = 
fromJson(?)", "\"ascii \\\" text\"", "0");
+        assertRows(execute("SELECT k, udtval from mv_asciival WHERE asciival = 
?", "ascii \" text"), row(0, null));
+
+        updateView("DELETE FROM %s WHERE k = fromJson(?)", "0");
+        assertRows(execute("SELECT k, asciival FROM %s WHERE k = ?", 0));
+        assertRows(execute("SELECT k, udtval from mv_asciival WHERE asciival = 
?", "ascii \" text"));
+
+        updateView("INSERT INTO %s (k, asciival) VALUES (?, fromJson(?))", 0, 
"\"ascii text\"");
+        assertRows(execute("SELECT k, udtval from mv_asciival WHERE asciival = 
?", "ascii text"), row(0, null));
+
+        // ================ bigint ================
+        updateView("INSERT INTO %s (k, bigintval) VALUES (?, fromJson(?))", 0, 
"123123123123");
+        assertRows(execute("SELECT k, bigintval FROM %s WHERE k = ?", 0), 
row(0, 123123123123L));
+        assertRows(execute("SELECT k, asciival from mv_bigintval WHERE 
bigintval = ?", 123123123123L), row(0, "ascii text"));
+
+        // ================ blob ================
+        updateView("INSERT INTO %s (k, blobval) VALUES (?, fromJson(?))", 0, 
"\"0x00000001\"");
+        assertRows(execute("SELECT k, blobval FROM %s WHERE k = ?", 0), row(0, 
ByteBufferUtil.bytes(1)));
+        assertRows(execute("SELECT k, asciival from mv_blobval WHERE blobval = 
?", ByteBufferUtil.bytes(1)), row(0, "ascii text"));
+
+        // ================ boolean ================
+        updateView("INSERT INTO %s (k, booleanval) VALUES (?, fromJson(?))", 
0, "true");
+        assertRows(execute("SELECT k, booleanval FROM %s WHERE k = ?", 0), 
row(0, true));
+        assertRows(execute("SELECT k, asciival from mv_booleanval WHERE 
booleanval = ?", true), row(0, "ascii text"));
+
+        updateView("INSERT INTO %s (k, booleanval) VALUES (?, fromJson(?))", 
0, "false");
+        assertRows(execute("SELECT k, booleanval FROM %s WHERE k = ?", 0), 
row(0, false));
+        assertRows(execute("SELECT k, asciival from mv_booleanval WHERE 
booleanval = ?", true));
+        assertRows(execute("SELECT k, asciival from mv_booleanval WHERE 
booleanval = ?", false), row(0, "ascii text"));
+
+        // ================ date ================
+        updateView("INSERT INTO %s (k, dateval) VALUES (?, fromJson(?))", 0, 
"\"1987-03-23\"");
+        assertRows(execute("SELECT k, dateval FROM %s WHERE k = ?", 0), row(0, 
SimpleDateSerializer.dateStringToDays("1987-03-23")));
+        assertRows(execute("SELECT k, asciival from mv_dateval WHERE dateval = 
fromJson(?)", "\"1987-03-23\""), row(0, "ascii text"));
+
+        // ================ decimal ================
+        updateView("INSERT INTO %s (k, decimalval) VALUES (?, fromJson(?))", 
0, "123123.123123");
+        assertRows(execute("SELECT k, decimalval FROM %s WHERE k = ?", 0), 
row(0, new BigDecimal("123123.123123")));
+        assertRows(execute("SELECT k, asciival from mv_decimalval WHERE 
decimalval = fromJson(?)", "123123.123123"), row(0, "ascii text"));
+
+        updateView("INSERT INTO %s (k, decimalval) VALUES (?, fromJson(?))", 
0, "123123");
+        assertRows(execute("SELECT k, decimalval FROM %s WHERE k = ?", 0), 
row(0, new BigDecimal("123123")));
+        assertRows(execute("SELECT k, asciival from mv_decimalval WHERE 
decimalval = fromJson(?)", "123123.123123"));
+        assertRows(execute("SELECT k, asciival from mv_decimalval WHERE 
decimalval = fromJson(?)", "123123"), row(0, "ascii text"));
+
+        // accept strings for numbers that cannot be represented as doubles
+        updateView("INSERT INTO %s (k, decimalval) VALUES (?, fromJson(?))", 
0, "\"123123.123123\"");
+        assertRows(execute("SELECT k, decimalval FROM %s WHERE k = ?", 0), 
row(0, new BigDecimal("123123.123123")));
+
+        updateView("INSERT INTO %s (k, decimalval) VALUES (?, fromJson(?))", 
0, "\"-1.23E-12\"");
+        assertRows(execute("SELECT k, decimalval FROM %s WHERE k = ?", 0), 
row(0, new BigDecimal("-1.23E-12")));
+        assertRows(execute("SELECT k, asciival from mv_decimalval WHERE 
decimalval = fromJson(?)", "\"-1.23E-12\""), row(0, "ascii text"));
+
+        // ================ double ================
+        updateView("INSERT INTO %s (k, doubleval) VALUES (?, fromJson(?))", 0, 
"123123.123123");
+        assertRows(execute("SELECT k, doubleval FROM %s WHERE k = ?", 0), 
row(0, 123123.123123d));
+        assertRows(execute("SELECT k, asciival from mv_doubleval WHERE 
doubleval = fromJson(?)", "123123.123123"), row(0, "ascii text"));
+
+        updateView("INSERT INTO %s (k, doubleval) VALUES (?, fromJson(?))", 0, 
"123123");
+        assertRows(execute("SELECT k, doubleval FROM %s WHERE k = ?", 0), 
row(0, 123123.0d));
+        assertRows(execute("SELECT k, asciival from mv_doubleval WHERE 
doubleval = fromJson(?)", "123123"), row(0, "ascii text"));
+
+        // ================ float ================
+        updateView("INSERT INTO %s (k, floatval) VALUES (?, fromJson(?))", 0, 
"123123.123123");
+        assertRows(execute("SELECT k, floatval FROM %s WHERE k = ?", 0), 
row(0, 123123.123123f));
+        assertRows(execute("SELECT k, asciival from mv_floatval WHERE floatval 
= fromJson(?)", "123123.123123"), row(0, "ascii text"));
+
+        updateView("INSERT INTO %s (k, floatval) VALUES (?, fromJson(?))", 0, 
"123123");
+        assertRows(execute("SELECT k, floatval FROM %s WHERE k = ?", 0), 
row(0, 123123.0f));
+        assertRows(execute("SELECT k, asciival from mv_floatval WHERE floatval 
= fromJson(?)", "123123"), row(0, "ascii text"));
+
+        // ================ inet ================
+        updateView("INSERT INTO %s (k, inetval) VALUES (?, fromJson(?))", 0, 
"\"127.0.0.1\"");
+        assertRows(execute("SELECT k, inetval FROM %s WHERE k = ?", 0), row(0, 
InetAddress.getByName("127.0.0.1")));
+        assertRows(execute("SELECT k, asciival from mv_inetval WHERE inetval = 
fromJson(?)", "\"127.0.0.1\""), row(0, "ascii text"));
+
+        updateView("INSERT INTO %s (k, inetval) VALUES (?, fromJson(?))", 0, 
"\"::1\"");
+        assertRows(execute("SELECT k, inetval FROM %s WHERE k = ?", 0), row(0, 
InetAddress.getByName("::1")));
+        assertRows(execute("SELECT k, asciival from mv_inetval WHERE inetval = 
fromJson(?)", "\"127.0.0.1\""));
+        assertRows(execute("SELECT k, asciival from mv_inetval WHERE inetval = 
fromJson(?)", "\"::1\""), row(0, "ascii text"));
+
+        // ================ int ================
+        updateView("INSERT INTO %s (k, intval) VALUES (?, fromJson(?))", 0, 
"123123");
+        assertRows(execute("SELECT k, intval FROM %s WHERE k = ?", 0), row(0, 
123123));
+        assertRows(execute("SELECT k, asciival from mv_intval WHERE intval = 
fromJson(?)", "123123"), row(0, "ascii text"));
+
+        // ================ text (varchar) ================
+        updateView("INSERT INTO %s (k, textval) VALUES (?, fromJson(?))", 0, 
"\"some \\\" text\"");
+        assertRows(execute("SELECT k, textval FROM %s WHERE k = ?", 0), row(0, 
"some \" text"));
+
+        updateView("INSERT INTO %s (k, textval) VALUES (?, fromJson(?))", 0, 
"\"\\u2013\"");
+        assertRows(execute("SELECT k, textval FROM %s WHERE k = ?", 0), row(0, 
"\u2013"));
+        assertRows(execute("SELECT k, asciival from mv_textval WHERE textval = 
fromJson(?)", "\"\\u2013\""), row(0, "ascii text"));
+
+        updateView("INSERT INTO %s (k, textval) VALUES (?, fromJson(?))", 0, 
"\"abcd\"");
+        assertRows(execute("SELECT k, textval FROM %s WHERE k = ?", 0), row(0, 
"abcd"));
+        assertRows(execute("SELECT k, asciival from mv_textval WHERE textval = 
fromJson(?)", "\"abcd\""), row(0, "ascii text"));
+
+        // ================ time ================
+        updateView("INSERT INTO %s (k, timeval) VALUES (?, fromJson(?))", 0, 
"\"07:35:07.000111222\"");
+        assertRows(execute("SELECT k, timeval FROM %s WHERE k = ?", 0), row(0, 
TimeSerializer.timeStringToLong("07:35:07.000111222")));
+        assertRows(execute("SELECT k, asciival from mv_timeval WHERE timeval = 
fromJson(?)", "\"07:35:07.000111222\""), row(0, "ascii text"));
+
+        // ================ timestamp ================
+        updateView("INSERT INTO %s (k, timestampval) VALUES (?, fromJson(?))", 
0, "123123123123");
+        assertRows(execute("SELECT k, timestampval FROM %s WHERE k = ?", 0), 
row(0, new Date(123123123123L)));
+        assertRows(execute("SELECT k, asciival from mv_timestampval WHERE 
timestampval = fromJson(?)", "123123123123"), row(0, "ascii text"));
+
+        updateView("INSERT INTO %s (k, timestampval) VALUES (?, fromJson(?))", 
0, "\"2014-01-01\"");
+        assertRows(execute("SELECT k, timestampval FROM %s WHERE k = ?", 0), 
row(0, new SimpleDateFormat("y-M-d").parse("2014-01-01")));
+        assertRows(execute("SELECT k, asciival from mv_timestampval WHERE 
timestampval = fromJson(?)", "\"2014-01-01\""), row(0, "ascii text"));
+
+        // ================ timeuuid ================
+        updateView("INSERT INTO %s (k, timeuuidval) VALUES (?, fromJson(?))", 
0, "\"6bddc89a-5644-11e4-97fc-56847afe9799\"");
+        assertRows(execute("SELECT k, timeuuidval FROM %s WHERE k = ?", 0), 
row(0, UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799")));
+
+        updateView("INSERT INTO %s (k, timeuuidval) VALUES (?, fromJson(?))", 
0, "\"6BDDC89A-5644-11E4-97FC-56847AFE9799\"");
+        assertRows(execute("SELECT k, timeuuidval FROM %s WHERE k = ?", 0), 
row(0, UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799")));
+        assertRows(execute("SELECT k, asciival from mv_timeuuidval WHERE 
timeuuidval = fromJson(?)", "\"6BDDC89A-5644-11E4-97FC-56847AFE9799\""), row(0, 
"ascii text"));
+
+        // ================ uuidval ================
+        updateView("INSERT INTO %s (k, uuidval) VALUES (?, fromJson(?))", 0, 
"\"6bddc89a-5644-11e4-97fc-56847afe9799\"");
+        assertRows(execute("SELECT k, uuidval FROM %s WHERE k = ?", 0), row(0, 
UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799")));
+
+        updateView("INSERT INTO %s (k, uuidval) VALUES (?, fromJson(?))", 0, 
"\"6BDDC89A-5644-11E4-97FC-56847AFE9799\"");
+        assertRows(execute("SELECT k, uuidval FROM %s WHERE k = ?", 0), row(0, 
UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799")));
+        assertRows(execute("SELECT k, asciival from mv_uuidval WHERE uuidval = 
fromJson(?)", "\"6BDDC89A-5644-11E4-97FC-56847AFE9799\""), row(0, "ascii 
text"));
+
+        // ================ varint ================
+        updateView("INSERT INTO %s (k, varintval) VALUES (?, fromJson(?))", 0, 
"123123123123");
+        assertRows(execute("SELECT k, varintval FROM %s WHERE k = ?", 0), 
row(0, new BigInteger("123123123123")));
+        assertRows(execute("SELECT k, asciival from mv_varintval WHERE 
varintval = fromJson(?)", "123123123123"), row(0, "ascii text"));
+
+        // accept strings for numbers that cannot be represented as longs
+        updateView("INSERT INTO %s (k, varintval) VALUES (?, fromJson(?))", 0, 
"\"1234567890123456789012345678901234567890\"");
+        assertRows(execute("SELECT k, varintval FROM %s WHERE k = ?", 0), 
row(0, new BigInteger("1234567890123456789012345678901234567890")));
+        assertRows(execute("SELECT k, asciival from mv_varintval WHERE 
varintval = fromJson(?)", "\"1234567890123456789012345678901234567890\""), 
row(0, "ascii text"));
+
+        // ================ lists ================
+        updateView("INSERT INTO %s (k, listval) VALUES (?, fromJson(?))", 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_textval WHERE textval = 
fromJson(?)", "\"abcd\""), row(0, list(1, 2, 3)));
+
+        updateView("INSERT INTO %s (k, listval) VALUES (?, fromJson(?))", 0, 
"[1]");
+        assertRows(execute("SELECT k, listval FROM %s WHERE k = ?", 0), row(0, 
list(1)));
+        assertRows(execute("SELECT k, listval from mv_textval WHERE textval = 
fromJson(?)", "\"abcd\""), row(0, list(1)));
+
+        updateView("UPDATE %s SET listval = listval + fromJson(?) WHERE k = 
?", "[2]", 0);
+        assertRows(execute("SELECT k, listval FROM %s WHERE k = ?", 0), row(0, 
list(1, 2)));
+        assertRows(execute("SELECT k, listval from mv_textval WHERE textval = 
fromJson(?)", "\"abcd\""), row(0, list(1, 2)));
+
+        updateView("UPDATE %s SET listval = fromJson(?) + listval WHERE k = 
?", "[0]", 0);
+        assertRows(execute("SELECT k, listval FROM %s WHERE k = ?", 0), row(0, 
list(0, 1, 2)));
+        assertRows(execute("SELECT k, listval from mv_textval WHERE textval = 
fromJson(?)", "\"abcd\""), row(0, list(0, 1, 2)));
+
+        updateView("UPDATE %s SET listval[1] = fromJson(?) WHERE k = ?", "10", 
0);
+        assertRows(execute("SELECT k, listval FROM %s WHERE k = ?", 0), row(0, 
list(0, 10, 2)));
+        assertRows(execute("SELECT k, listval from mv_textval WHERE textval = 
fromJson(?)", "\"abcd\""), row(0, list(0, 10, 2)));
+
+        updateView("DELETE listval[1] FROM %s WHERE k = ?", 0);
+        assertRows(execute("SELECT k, listval FROM %s WHERE k = ?", 0), row(0, 
list(0, 2)));
+        assertRows(execute("SELECT k, listval from mv_textval WHERE textval = 
fromJson(?)", "\"abcd\""), row(0, list(0, 2)));
+
+        updateView("INSERT INTO %s (k, listval) VALUES (?, fromJson(?))", 0, 
"[]");
+        assertRows(execute("SELECT k, listval FROM %s WHERE k = ?", 0), row(0, 
null));
+        assertRows(execute("SELECT k, listval from mv_textval WHERE textval = 
fromJson(?)", "\"abcd\""), row(0, null));
+
+        // frozen
+        updateView("INSERT INTO %s (k, frozenlistval) VALUES (?, 
fromJson(?))", 0, "[1, 2, 3]");
+        assertRows(execute("SELECT k, frozenlistval FROM %s WHERE k = ?", 0), 
row(0, list(1, 2, 3)));
+        assertRows(execute("SELECT k, frozenlistval from mv_textval WHERE 
textval = fromJson(?)", "\"abcd\""), row(0, list(1, 2, 3)));
+        assertRows(execute("SELECT k, textval from mv_frozenlistval where 
frozenlistval = fromJson(?)", "[1, 2, 3]"), row(0, "abcd"));
+
+        updateView("INSERT INTO %s (k, frozenlistval) VALUES (?, 
fromJson(?))", 0, "[3, 2, 1]");
+        assertRows(execute("SELECT k, frozenlistval FROM %s WHERE k = ?", 0), 
row(0, list(3, 2, 1)));
+        assertRows(execute("SELECT k, textval from mv_frozenlistval where 
frozenlistval = fromJson(?)", "[1, 2, 3]"));
+        assertRows(execute("SELECT k, textval from mv_frozenlistval where 
frozenlistval = fromJson(?)", "[3, 2, 1]"), row(0, "abcd"));
+        assertRows(execute("SELECT k, frozenlistval from mv_textval WHERE 
textval = fromJson(?)", "\"abcd\""), row(0, list(3, 2, 1)));
+
+        updateView("INSERT INTO %s (k, frozenlistval) VALUES (?, 
fromJson(?))", 0, "[]");
+        assertRows(execute("SELECT k, frozenlistval FROM %s WHERE k = ?", 0), 
row(0, list()));
+        assertRows(execute("SELECT k, frozenlistval from mv_textval WHERE 
textval = fromJson(?)", "\"abcd\""), row(0, list()));
+
+        // ================ sets ================
+        updateView("INSERT INTO %s (k, setval) VALUES (?, fromJson(?))",
+                   0, "[\"6bddc89a-5644-11e4-97fc-56847afe9798\", 
\"6bddc89a-5644-11e4-97fc-56847afe9799\"]");
+        assertRows(execute("SELECT k, setval FROM %s WHERE k = ?", 0),
+                   row(0, 
set(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9798"), 
(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799"))))
+        );
+        assertRows(execute("SELECT k, setval from mv_textval WHERE textval = 
fromJson(?)", "\"abcd\""),
+                   row(0, 
set(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9798"), 
(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799")))));
+
+        // duplicates are okay, just like in CQL
+        updateView("INSERT INTO %s (k, setval) VALUES (?, fromJson(?))",
+                   0, "[\"6bddc89a-5644-11e4-97fc-56847afe9798\", 
\"6bddc89a-5644-11e4-97fc-56847afe9798\", 
\"6bddc89a-5644-11e4-97fc-56847afe9799\"]");
+        assertRows(execute("SELECT k, setval FROM %s WHERE k = ?", 0),
+                   row(0, 
set(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9798"), 
(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799"))))
+        );
+        assertRows(execute("SELECT k, setval from mv_textval WHERE textval = 
fromJson(?)", "\"abcd\""),
+                   row(0, 
set(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9798"), 
(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799")))));
+
+        updateView("UPDATE %s SET setval = setval + fromJson(?) WHERE k = ?", 
"[\"6bddc89a-5644-0000-97fc-56847afe9799\"]", 0);
+        assertRows(execute("SELECT k, setval FROM %s WHERE k = ?", 0),
+                   row(0, 
set(UUID.fromString("6bddc89a-5644-0000-97fc-56847afe9799"), 
UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9798"), 
(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799"))))
+        );
+        assertRows(execute("SELECT k, setval from mv_textval WHERE textval = 
fromJson(?)", "\"abcd\""),
+                   row(0, 
set(UUID.fromString("6bddc89a-5644-0000-97fc-56847afe9799"), 
UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9798"), 
(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799")))));
+
+        updateView("UPDATE %s SET setval = setval - fromJson(?) WHERE k = ?", 
"[\"6bddc89a-5644-0000-97fc-56847afe9799\"]", 0);
+        assertRows(execute("SELECT k, setval FROM %s WHERE k = ?", 0),
+                   row(0, 
set(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9798"), 
(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799"))))
+        );
+        assertRows(execute("SELECT k, setval from mv_textval WHERE textval = 
fromJson(?)", "\"abcd\""),
+                   row(0, 
set(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9798"), 
(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799")))));
+
+        updateView("INSERT INTO %s (k, setval) VALUES (?, fromJson(?))", 0, 
"[]");
+        assertRows(execute("SELECT k, setval FROM %s WHERE k = ?", 0), row(0, 
null));
+        assertRows(execute("SELECT k, setval from mv_textval WHERE textval = 
fromJson(?)", "\"abcd\""),
+                   row(0, null));
+
+
+        // frozen
+        updateView("INSERT INTO %s (k, frozensetval) VALUES (?, fromJson(?))",
+                   0, "[\"6bddc89a-5644-11e4-97fc-56847afe9798\", 
\"6bddc89a-5644-11e4-97fc-56847afe9799\"]");
+        assertRows(execute("SELECT k, frozensetval FROM %s WHERE k = ?", 0),
+                   row(0, 
set(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9798"), 
(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799"))))
+        );
+        assertRows(execute("SELECT k, frozensetval from mv_textval WHERE 
textval = fromJson(?)", "\"abcd\""),
+                   row(0, 
set(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9798"), 
(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799")))));
+
+        updateView("INSERT INTO %s (k, frozensetval) VALUES (?, fromJson(?))",
+                   0, "[\"6bddc89a-0000-11e4-97fc-56847afe9799\", 
\"6bddc89a-5644-11e4-97fc-56847afe9798\"]");
+        assertRows(execute("SELECT k, frozensetval FROM %s WHERE k = ?", 0),
+                   row(0, 
set(UUID.fromString("6bddc89a-0000-11e4-97fc-56847afe9799"), 
(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9798"))))
+        );
+        assertRows(execute("SELECT k, frozensetval from mv_textval WHERE 
textval = fromJson(?)", "\"abcd\""),
+                   row(0, 
set(UUID.fromString("6bddc89a-0000-11e4-97fc-56847afe9799"), 
(UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9798")))));
+
+        // ================ maps ================
+        updateView("INSERT INTO %s (k, mapval) VALUES (?, fromJson(?))", 0, 
"{\"a\": 1, \"b\": 2}");
+        assertRows(execute("SELECT k, mapval FROM %s WHERE k = ?", 0), row(0, 
map("a", 1, "b", 2)));
+        assertRows(execute("SELECT k, mapval from mv_textval WHERE textval = 
fromJson(?)", "\"abcd\""), row(0, map("a", 1, "b", 2)));
+
+        updateView("UPDATE %s SET mapval[?] = ?  WHERE k = ?", "c", 3, 0);
+        assertRows(execute("SELECT k, mapval FROM %s WHERE k = ?", 0),
+                   row(0, map("a", 1, "b", 2, "c", 3))
+        );
+        assertRows(execute("SELECT k, mapval from mv_textval WHERE textval = 
fromJson(?)", "\"abcd\""),
+                   row(0, map("a", 1, "b", 2, "c", 3)));
+
+        updateView("UPDATE %s SET mapval[?] = ?  WHERE k = ?", "b", 10, 0);
+        assertRows(execute("SELECT k, mapval FROM %s WHERE k = ?", 0),
+                   row(0, map("a", 1, "b", 10, "c", 3))
+        );
+        assertRows(execute("SELECT k, mapval from mv_textval WHERE textval = 
fromJson(?)", "\"abcd\""),
+                   row(0, map("a", 1, "b", 10, "c", 3)));
+
+        updateView("DELETE mapval[?] FROM %s WHERE k = ?", "b", 0);
+        assertRows(execute("SELECT k, mapval FROM %s WHERE k = ?", 0),
+                   row(0, map("a", 1, "c", 3))
+        );
+        assertRows(execute("SELECT k, mapval from mv_textval WHERE textval = 
fromJson(?)", "\"abcd\""),
+                   row(0, map("a", 1, "c", 3)));
+
+        updateView("INSERT INTO %s (k, mapval) VALUES (?, fromJson(?))", 0, 
"{}");
+        assertRows(execute("SELECT k, mapval FROM %s WHERE k = ?", 0), row(0, 
null));
+        assertRows(execute("SELECT k, mapval from mv_textval WHERE textval = 
fromJson(?)", "\"abcd\""),
+                   row(0, null));
+
+        // frozen
+        updateView("INSERT INTO %s (k, frozenmapval) VALUES (?, fromJson(?))", 
0, "{\"a\": 1, \"b\": 2}");
+        assertRows(execute("SELECT k, frozenmapval FROM %s WHERE k = ?", 0), 
row(0, map("a", 1, "b", 2)));
+        assertRows(execute("SELECT k, textval FROM mv_frozenmapval WHERE 
frozenmapval = fromJson(?)", "{\"a\": 1, \"b\": 2}"), row(0, "abcd"));
+
+        updateView("INSERT INTO %s (k, frozenmapval) VALUES (?, fromJson(?))", 
0, "{\"b\": 2, \"a\": 3}");
+        assertRows(execute("SELECT k, frozenmapval FROM %s WHERE k = ?", 0), 
row(0, map("a", 3, "b", 2)));
+        assertRows(execute("SELECT k, frozenmapval FROM %s WHERE k = ?", 0), 
row(0, map("a", 3, "b", 2)));
+
+        // ================ tuples ================
+        updateView("INSERT INTO %s (k, tupleval) VALUES (?, fromJson(?))", 0, 
"[1, \"foobar\", \"6bddc89a-5644-11e4-97fc-56847afe9799\"]");
+        assertRows(execute("SELECT k, tupleval FROM %s WHERE k = ?", 0),
+                   row(0, tuple(1, "foobar", 
UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799")))
+        );
+        assertRows(execute("SELECT k, textval FROM mv_tupleval WHERE tupleval 
= ?", tuple(1, "foobar", 
UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799"))),
+                   row(0, "abcd"));
+
+        updateView("INSERT INTO %s (k, tupleval) VALUES (?, fromJson(?))", 0, 
"[1, null, \"6bddc89a-5644-11e4-97fc-56847afe9799\"]");
+        assertRows(execute("SELECT k, tupleval FROM %s WHERE k = ?", 0),
+                   row(0, tuple(1, null, 
UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799")))
+        );
+        assertRows(execute("SELECT k, textval FROM mv_tupleval WHERE tupleval 
= ?", tuple(1, "foobar", 
UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799"))));
+        assertRows(execute("SELECT k, textval FROM mv_tupleval WHERE tupleval 
= ?", tuple(1, null, UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799"))),
+                   row(0, "abcd"));
+
+        // ================ UDTs ================
+        updateView("INSERT INTO %s (k, udtval) VALUES (?, fromJson(?))", 0, 
"{\"a\": 1, \"b\": \"6bddc89a-5644-11e4-97fc-56847afe9799\", \"c\": [\"foo\", 
\"bar\"]}");
+        assertRows(execute("SELECT k, udtval.a, udtval.b, udtval.c FROM %s 
WHERE k = ?", 0),
+                   row(0, 1, 
UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799"), set("bar", "foo"))
+        );
+        assertRows(execute("SELECT k, textval FROM mv_udtval WHERE udtval = 
fromJson(?)", "{\"a\": 1, \"b\": \"6bddc89a-5644-11e4-97fc-56847afe9799\", 
\"c\": [\"foo\", \"bar\"]}"),
+                   row(0, "abcd"));
+
+        // order of fields shouldn't matter
+        updateView("INSERT INTO %s (k, udtval) VALUES (?, fromJson(?))", 0, 
"{\"b\": \"6bddc89a-5644-11e4-97fc-56847afe9799\", \"a\": 1, \"c\": [\"foo\", 
\"bar\"]}");
+        assertRows(execute("SELECT k, udtval.a, udtval.b, udtval.c FROM %s 
WHERE k = ?", 0),
+                   row(0, 1, 
UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799"), set("bar", "foo"))
+        );
+        assertRows(execute("SELECT k, textval FROM mv_udtval WHERE udtval = 
fromJson(?)", "{\"a\": 1, \"b\": \"6bddc89a-5644-11e4-97fc-56847afe9799\", 
\"c\": [\"foo\", \"bar\"]}"),
+                   row(0, "abcd"));
+
+        // test nulls
+        updateView("INSERT INTO %s (k, udtval) VALUES (?, fromJson(?))", 0, 
"{\"a\": null, \"b\": \"6bddc89a-5644-11e4-97fc-56847afe9799\", \"c\": 
[\"foo\", \"bar\"]}");
+        assertRows(execute("SELECT k, udtval.a, udtval.b, udtval.c FROM %s 
WHERE k = ?", 0),
+                   row(0, null, 
UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799"), set("bar", "foo"))
+        );
+        assertRows(execute("SELECT k, textval FROM mv_udtval WHERE udtval = 
fromJson(?)", "{\"a\": 1, \"b\": \"6bddc89a-5644-11e4-97fc-56847afe9799\", 
\"c\": [\"foo\", \"bar\"]}"));
+        assertRows(execute("SELECT k, textval FROM mv_udtval WHERE udtval = 
fromJson(?)", "{\"a\": null, \"b\": \"6bddc89a-5644-11e4-97fc-56847afe9799\", 
\"c\": [\"foo\", \"bar\"]}"),
+                   row(0, "abcd"));
+
+        // test missing fields
+        updateView("INSERT INTO %s (k, udtval) VALUES (?, fromJson(?))", 0, 
"{\"a\": 1, \"b\": \"6bddc89a-5644-11e4-97fc-56847afe9799\"}");
+        assertRows(execute("SELECT k, udtval.a, udtval.b, udtval.c FROM %s 
WHERE k = ?", 0),
+                   row(0, 1, 
UUID.fromString("6bddc89a-5644-11e4-97fc-56847afe9799"), null)
+        );
+        assertRows(execute("SELECT k, textval FROM mv_udtval WHERE udtval = 
fromJson(?)", "{\"a\": null, \"b\": \"6bddc89a-5644-11e4-97fc-56847afe9799\", 
\"c\": [\"foo\", \"bar\"]}"));
+        assertRows(execute("SELECT k, textval FROM mv_udtval WHERE udtval = 
fromJson(?)", "{\"a\": 1, \"b\": \"6bddc89a-5644-11e4-97fc-56847afe9799\"}"),
+                   row(0, "abcd"));
+    }
+
+    @Test
+    public void testDropTableWithMV() throws Throwable
+    {
+        createTable("CREATE TABLE %s (" +
+                "a int," +
+                "b int," +
+                "c int," +
+                "d int," +
+                "PRIMARY KEY (a, b, c))");
+
+        executeNet(protocolVersion, "USE " + keyspace());
+
+        createView(keyspace() + ".mv1",
+                   "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE b 
IS NOT NULL AND c IS NOT NULL PRIMARY KEY (a, b, c)");
+
+        try
+        {
+            executeNet(protocolVersion, "DROP TABLE " + keyspace() + ".mv1");
+            Assert.fail();
+        }
+        catch (InvalidQueryException e)
+        {
+            Assert.assertEquals("Cannot use DROP TABLE on Materialized View", 
e.getMessage());
+        }
+    }
+
+    @Test
+    public void testAlterTable() throws Throwable
+    {
+        createTable("CREATE TABLE %s (" +
+                    "a int," +
+                    "b text," +
+                    "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 PRIMARY KEY (b, a)");
+
+        alterTable("ALTER TABLE %s ALTER b TYPE blob");
+    }
+
+    @Test
+    public void testAlterReversedTypeBaseTable() throws Throwable
+    {
+        createTable("CREATE TABLE %s (" +
+                    "a int," +
+                    "b text," +
+                    "PRIMARY KEY (a, b))" +
+                    "WITH CLUSTERING ORDER BY (b DESC)");
+
+        executeNet(protocolVersion, "USE " + keyspace());
+
+        createView("mv1", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s 
WHERE a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (a, b) WITH CLUSTERING ORDER 
BY (b ASC)");
+
+        alterTable("ALTER TABLE %s ALTER b TYPE blob");
+    }
+
+    @Test
+    public void testAlterReversedTypeViewTable() throws Throwable
+    {
+        createTable("CREATE TABLE %s (" +
+                    "a int," +
+                    "b text," +
+                    "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 PRIMARY KEY (a, b) WITH CLUSTERING ORDER 
BY (b DESC)");
+
+        alterTable("ALTER TABLE %s ALTER b TYPE blob");
+    }
+
+    @Test
+    public void testAlterClusteringViewTable() throws Throwable
+    {
+        createTable("CREATE TABLE %s (" +
+                    "a int," +
+                    "b text," +
+                    "PRIMARY KEY (a))");
+
+        executeNet(protocolVersion, "USE " + keyspace());
+
+        createView("mv1", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s 
WHERE a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (a, b) WITH CLUSTERING ORDER 
BY (b DESC)");
+
+        alterTable("ALTER TABLE %s ALTER b TYPE blob");
+    }
+
+    @Test
+    public void testAlterViewTableValue() throws Throwable
+    {
+        createTable("CREATE TABLE %s (" +
+                    "a int," +
+                    "b int," +
+                    "PRIMARY KEY (a))");
+
+        executeNet(protocolVersion, "USE " + keyspace());
+
+        createView("mv1", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s 
WHERE a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (a, b) WITH CLUSTERING ORDER 
BY (b DESC)");
+
+        assertInvalid("ALTER TABLE %s ALTER b TYPE blob");
+    }
+}

Reply via email to