You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by sn...@apache.org on 2015/11/27 11:01:52 UTC

[1/8] cassandra git commit: Some DROP ... IF EXISTS incorrectly result in exceptions on non-existing KS

Repository: cassandra
Updated Branches:
  refs/heads/cassandra-3.0 e8091d5f7 -> d300a1850


Some DROP ... IF EXISTS incorrectly result in exceptions on non-existing KS

patch by Robert Stupp; reviewed by Marcus Eriksson for CASSANDRA-10658


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

Branch: refs/heads/cassandra-3.0
Commit: 4ecbbc08206fc5cd2e91520a5b99ef890f1da75d
Parents: b8a8004
Author: Robert Stupp <sn...@snazy.de>
Authored: Fri Nov 27 10:42:38 2015 +0100
Committer: Robert Stupp <sn...@snazy.de>
Committed: Fri Nov 27 10:42:38 2015 +0100

----------------------------------------------------------------------
 CHANGES.txt                                     |  1 +
 .../cql3/statements/DropTypeStatement.java      | 10 ++++--
 .../cql3/validation/entities/TypeTest.java      | 10 ++++++
 .../cql3/validation/operations/DropTest.java    | 37 ++++++++++++++++++++
 4 files changed, 56 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ecbbc08/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 48f4e89..4adcf4f 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 2.1.12
+ * Some DROP ... IF EXISTS incorrectly result in exceptions on non-existing KS (CASSANDRA-10658)
  * DeletionTime.compareTo wrong in rare cases (CASSANDRA-10749)
  * Force encoding when computing statement ids (CASSANDRA-10755)
  * Properly reject counters as map keys (CASSANDRA-10760)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ecbbc08/src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java b/src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java
index 94edd01..bc6005d 100644
--- a/src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java
@@ -54,7 +54,12 @@ public class DropTypeStatement extends SchemaAlteringStatement
     {
         KSMetaData ksm = Schema.instance.getKSMetaData(name.getKeyspace());
         if (ksm == null)
-            throw new InvalidRequestException(String.format("Cannot drop type in unknown keyspace %s", name.getKeyspace()));
+        {
+            if (ifExists)
+                return;
+            else
+                throw new InvalidRequestException(String.format("Cannot drop type in unknown keyspace %s", name.getKeyspace()));
+        }
 
         UserType old = ksm.userTypes.getType(name.getUserTypeName());
         if (old == null)
@@ -140,7 +145,8 @@ public class DropTypeStatement extends SchemaAlteringStatement
     public boolean announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
     {
         KSMetaData ksm = Schema.instance.getKSMetaData(name.getKeyspace());
-        assert ksm != null;
+        if (ksm == null)
+            return false; // do not assert (otherwise IF EXISTS case fails)
 
         UserType toDrop = ksm.userTypes.getType(name.getUserTypeName());
         // Can be null with ifExists

http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ecbbc08/test/unit/org/apache/cassandra/cql3/validation/entities/TypeTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/TypeTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/TypeTest.java
index f27cca8..f23ce35 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/TypeTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/TypeTest.java
@@ -28,6 +28,16 @@ import static org.junit.Assert.fail;
 public class TypeTest extends CQLTester
 {
     @Test
+    public void testNonExistingOnes() throws Throwable
+    {
+        assertInvalidMessage("No user type named", "DROP TYPE " + KEYSPACE + ".type_does_not_exist");
+        assertInvalidMessage("Cannot drop type in unknown keyspace", "DROP TYPE keyspace_does_not_exist.type_does_not_exist");
+
+        execute("DROP TYPE IF EXISTS " + KEYSPACE + ".type_does_not_exist");
+        execute("DROP TYPE IF EXISTS keyspace_does_not_exist.type_does_not_exist");
+    }
+
+    @Test
     public void testNowToUUIDCompatibility() throws Throwable
     {
         createTable("CREATE TABLE %s (a int, b uuid, PRIMARY KEY (a, b))");

http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ecbbc08/test/unit/org/apache/cassandra/cql3/validation/operations/DropTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/DropTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/DropTest.java
new file mode 100644
index 0000000..b0c0809
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/DropTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.operations;
+
+import org.junit.Test;
+
+import org.apache.cassandra.cql3.CQLTester;
+
+public class DropTest extends CQLTester
+{
+    @Test
+    public void testNonExistingOnes() throws Throwable
+    {
+        assertInvalidMessage("Cannot drop non existing column family", "DROP TABLE " + KEYSPACE + ".table_does_not_exist");
+        assertInvalidMessage("Cannot drop non existing column family", "DROP TABLE keyspace_does_not_exist.table_does_not_exist");
+
+        execute("DROP TABLE IF EXISTS " + KEYSPACE + ".table_does_not_exist");
+        execute("DROP TABLE IF EXISTS keyspace_does_not_exist.table_does_not_exist");
+    }
+
+}


[2/8] cassandra git commit: Merge branch 'cassandra-2.1' into cassandra-2.2

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/b3e6a433/test/unit/org/apache/cassandra/cql3/validation/operations/DropTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/operations/DropTest.java
index 0000000,b0c0809..2c68390
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/DropTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/DropTest.java
@@@ -1,0 -1,37 +1,37 @@@
+ /*
+  * 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.operations;
+ 
+ import org.junit.Test;
+ 
+ import org.apache.cassandra.cql3.CQLTester;
+ 
+ public class DropTest extends CQLTester
+ {
+     @Test
+     public void testNonExistingOnes() throws Throwable
+     {
 -        assertInvalidMessage("Cannot drop non existing column family", "DROP TABLE " + KEYSPACE + ".table_does_not_exist");
 -        assertInvalidMessage("Cannot drop non existing column family", "DROP TABLE keyspace_does_not_exist.table_does_not_exist");
++        assertInvalidMessage("Cannot drop non existing table", "DROP TABLE " + KEYSPACE + ".table_does_not_exist");
++        assertInvalidMessage("Cannot drop non existing table", "DROP TABLE keyspace_does_not_exist.table_does_not_exist");
+ 
+         execute("DROP TABLE IF EXISTS " + KEYSPACE + ".table_does_not_exist");
+         execute("DROP TABLE IF EXISTS keyspace_does_not_exist.table_does_not_exist");
+     }
+ 
+ }


[4/8] cassandra git commit: Merge branch 'cassandra-2.1' into cassandra-2.2

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/b3e6a433/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
index 25566ad,0000000..0d11a82
mode 100644,000000..100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
@@@ -1,2649 -1,0 +1,2663 @@@
 +/*
 + * 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 java.math.BigDecimal;
 +import java.math.BigInteger;
 +import java.nio.ByteBuffer;
 +import java.util.ArrayList;
 +import java.util.Arrays;
 +import java.util.Date;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Set;
 +import java.util.TreeMap;
 +import java.util.TreeSet;
 +import java.util.UUID;
 +
 +import org.junit.Assert;
 +import org.junit.BeforeClass;
 +import org.junit.Test;
 +
 +import com.datastax.driver.core.DataType;
 +import com.datastax.driver.core.Row;
 +import com.datastax.driver.core.TupleType;
 +import com.datastax.driver.core.TupleValue;
 +import com.datastax.driver.core.UDTValue;
 +import com.datastax.driver.core.exceptions.InvalidQueryException;
 +import org.apache.cassandra.config.DatabaseDescriptor;
 +import org.apache.cassandra.cql3.CQL3Type;
 +import org.apache.cassandra.cql3.CQLTester;
 +import org.apache.cassandra.cql3.QueryProcessor;
 +import org.apache.cassandra.cql3.UntypedResultSet;
 +import org.apache.cassandra.cql3.functions.FunctionName;
 +import org.apache.cassandra.cql3.functions.Functions;
 +import org.apache.cassandra.cql3.functions.UDFunction;
 +import org.apache.cassandra.db.marshal.CollectionType;
 +import org.apache.cassandra.dht.ByteOrderedPartitioner;
 +import org.apache.cassandra.exceptions.FunctionExecutionException;
 +import org.apache.cassandra.exceptions.InvalidRequestException;
 +import org.apache.cassandra.service.ClientState;
 +import org.apache.cassandra.transport.Event;
 +import org.apache.cassandra.transport.Server;
 +import org.apache.cassandra.transport.messages.ResultMessage;
 +import org.apache.cassandra.utils.ByteBufferUtil;
 +import org.apache.cassandra.utils.UUIDGen;
 +
 +public class UFTest extends CQLTester
 +{
 +    @BeforeClass
 +    public static void setUp()
 +    {
 +        DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance);
 +    }
 +
 +    @Test
++    public void testNonExistingOnes() throws Throwable
++    {
++        assertInvalidMessage("Cannot drop non existing function", "DROP FUNCTION " + KEYSPACE + ".func_does_not_exist");
++        assertInvalidMessage("Cannot drop non existing function", "DROP FUNCTION " + KEYSPACE + ".func_does_not_exist(int,text)");
++        assertInvalidMessage("Cannot drop non existing function", "DROP FUNCTION keyspace_does_not_exist.func_does_not_exist");
++        assertInvalidMessage("Cannot drop non existing function", "DROP FUNCTION keyspace_does_not_exist.func_does_not_exist(int,text)");
++
++        execute("DROP FUNCTION IF EXISTS " + KEYSPACE + ".func_does_not_exist");
++        execute("DROP FUNCTION IF EXISTS " + KEYSPACE + ".func_does_not_exist(int,text)");
++        execute("DROP FUNCTION IF EXISTS keyspace_does_not_exist.func_does_not_exist");
++        execute("DROP FUNCTION IF EXISTS keyspace_does_not_exist.func_does_not_exist(int,text)");
++    }
++
++    @Test
 +    public void testSchemaChange() throws Throwable
 +    {
 +        String f = createFunction(KEYSPACE,
 +                                  "double, double",
 +                                  "CREATE OR REPLACE FUNCTION %s(state double, val double) " +
 +                                  "RETURNS NULL ON NULL INPUT " +
 +                                  "RETURNS double " +
 +                                  "LANGUAGE javascript " +
 +                                  "AS '\"string\";';");
 +
 +        assertLastSchemaChange(Event.SchemaChange.Change.CREATED, Event.SchemaChange.Target.FUNCTION,
 +                               KEYSPACE, parseFunctionName(f).name,
 +                               "double", "double");
 +
 +        createFunctionOverload(f,
 +                               "double, double",
 +                               "CREATE OR REPLACE FUNCTION %s(state int, val int) " +
 +                               "RETURNS NULL ON NULL INPUT " +
 +                               "RETURNS int " +
 +                               "LANGUAGE javascript " +
 +                               "AS '\"string\";';");
 +
 +        assertLastSchemaChange(Event.SchemaChange.Change.CREATED, Event.SchemaChange.Target.FUNCTION,
 +                               KEYSPACE, parseFunctionName(f).name,
 +                               "int", "int");
 +
 +        schemaChange("CREATE OR REPLACE FUNCTION " + f + "(state int, val int) " +
 +                     "RETURNS NULL ON NULL INPUT " +
 +                     "RETURNS int " +
 +                     "LANGUAGE javascript " +
 +                     "AS '\"string\";';");
 +
 +        assertLastSchemaChange(Event.SchemaChange.Change.UPDATED, Event.SchemaChange.Target.FUNCTION,
 +                               KEYSPACE, parseFunctionName(f).name,
 +                               "int", "int");
 +
 +        schemaChange("DROP FUNCTION " + f + "(double, double)");
 +
 +        assertLastSchemaChange(Event.SchemaChange.Change.DROPPED, Event.SchemaChange.Target.FUNCTION,
 +                               KEYSPACE, parseFunctionName(f).name,
 +                               "double", "double");
 +    }
 +
 +    @Test
 +    public void testFunctionDropOnKeyspaceDrop() throws Throwable
 +    {
 +        String fSin = createFunction(KEYSPACE_PER_TEST, "double",
 +                                     "CREATE FUNCTION %s ( input double ) " +
 +                                     "CALLED ON NULL INPUT " +
 +                                     "RETURNS double " +
 +                                     "LANGUAGE java " +
 +                                     "AS 'return Double.valueOf(Math.sin(input.doubleValue()));'");
 +
 +        FunctionName fSinName = parseFunctionName(fSin);
 +
 +        Assert.assertEquals(1, Functions.find(parseFunctionName(fSin)).size());
 +
 +        assertRows(execute("SELECT function_name, language FROM system.schema_functions WHERE keyspace_name=?", KEYSPACE_PER_TEST),
 +                   row(fSinName.name, "java"));
 +
 +        dropPerTestKeyspace();
 +
 +        assertRows(execute("SELECT function_name, language FROM system.schema_functions WHERE keyspace_name=?", KEYSPACE_PER_TEST));
 +
 +        Assert.assertEquals(0, Functions.find(fSinName).size());
 +    }
 +
 +    @Test
 +    public void testFunctionDropPreparedStatement() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (key int PRIMARY KEY, d double)");
 +
 +        String fSin = createFunction(KEYSPACE_PER_TEST, "double",
 +                                     "CREATE FUNCTION %s ( input double ) " +
 +                                     "CALLED ON NULL INPUT " +
 +                                     "RETURNS double " +
 +                                     "LANGUAGE java " +
 +                                     "AS 'return Double.valueOf(Math.sin(input.doubleValue()));'");
 +
 +        FunctionName fSinName = parseFunctionName(fSin);
 +
 +        Assert.assertEquals(1, Functions.find(parseFunctionName(fSin)).size());
 +
 +        // create a pairs of Select and Inserts. One statement in each pair uses the function so when we
 +        // drop it those statements should be removed from the cache in QueryProcessor. The other statements
 +        // should be unaffected.
 +
 +        ResultMessage.Prepared preparedSelect1 = QueryProcessor.prepare(
 +                                                                       String.format("SELECT key, %s(d) FROM %s.%s", fSin, KEYSPACE, currentTable()),
 +                                                                       ClientState.forInternalCalls(), false);
 +        ResultMessage.Prepared preparedSelect2 = QueryProcessor.prepare(
 +                                                    String.format("SELECT key FROM %s.%s", KEYSPACE, currentTable()),
 +                                                    ClientState.forInternalCalls(), false);
 +        ResultMessage.Prepared preparedInsert1 = QueryProcessor.prepare(
 +                                                      String.format("INSERT INTO %s.%s (key, d) VALUES (?, %s(?))", KEYSPACE, currentTable(), fSin),
 +                                                      ClientState.forInternalCalls(), false);
 +        ResultMessage.Prepared preparedInsert2 = QueryProcessor.prepare(
 +                                                      String.format("INSERT INTO %s.%s (key, d) VALUES (?, ?)", KEYSPACE, currentTable()),
 +                                                      ClientState.forInternalCalls(), false);
 +
 +        Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedSelect1.statementId));
 +        Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedSelect2.statementId));
 +        Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedInsert1.statementId));
 +        Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedInsert2.statementId));
 +
 +        execute("DROP FUNCTION " + fSin + "(double);");
 +
 +        // the statements which use the dropped function should be removed from cache, with the others remaining
 +        Assert.assertNull(QueryProcessor.instance.getPrepared(preparedSelect1.statementId));
 +        Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedSelect2.statementId));
 +        Assert.assertNull(QueryProcessor.instance.getPrepared(preparedInsert1.statementId));
 +        Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedInsert2.statementId));
 +
 +        execute("CREATE FUNCTION " + fSin + " ( input double ) " +
 +                "RETURNS NULL ON NULL INPUT " +
 +                "RETURNS double " +
 +                "LANGUAGE java " +
 +                "AS 'return Double.valueOf(Math.sin(input));'");
 +
 +        Assert.assertEquals(1, Functions.find(fSinName).size());
 +
 +        preparedSelect1= QueryProcessor.prepare(
 +                                         String.format("SELECT key, %s(d) FROM %s.%s", fSin, KEYSPACE, currentTable()),
 +                                         ClientState.forInternalCalls(), false);
 +        preparedInsert1 = QueryProcessor.prepare(
 +                                         String.format("INSERT INTO %s.%s (key, d) VALUES (?, %s(?))", KEYSPACE, currentTable(), fSin),
 +                                         ClientState.forInternalCalls(), false);
 +        Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedSelect1.statementId));
 +        Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedInsert1.statementId));
 +
 +        dropPerTestKeyspace();
 +
 +        // again, only the 2 statements referencing the function should be removed from cache
 +        // this time because the statements select from tables in KEYSPACE, only the function
 +        // is scoped to KEYSPACE_PER_TEST
 +        Assert.assertNull(QueryProcessor.instance.getPrepared(preparedSelect1.statementId));
 +        Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedSelect2.statementId));
 +        Assert.assertNull(QueryProcessor.instance.getPrepared(preparedInsert1.statementId));
 +        Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedInsert2.statementId));
 +    }
 +
 +    @Test
 +    public void testDropFunctionDropsPreparedStatementsWithDelayedValues() throws Throwable
 +    {
 +        // test that dropping a function removes stmts which use
 +        // it to provide a DelayedValue collection from the
 +        // cache in QueryProcessor
 +        checkDelayedValuesCorrectlyIdentifyFunctionsInUse(false);
 +    }
 +
 +    @Test
 +    public void testDropKeyspaceContainingFunctionDropsPreparedStatementsWithDelayedValues() throws Throwable
 +    {
 +        // test that dropping a function removes stmts which use
 +        // it to provide a DelayedValue collection from the
 +        // cache in QueryProcessor
 +        checkDelayedValuesCorrectlyIdentifyFunctionsInUse(true);
 +    }
 +
 +    private ResultMessage.Prepared prepareStatementWithDelayedValue(CollectionType.Kind kind, String function)
 +    {
 +        String collectionType;
 +        String literalArgs;
 +        switch (kind)
 +        {
 +            case LIST:
 +                collectionType = "list<double>";
 +                literalArgs = String.format("[%s(0.0)]", function);
 +                break;
 +            case SET:
 +                collectionType = "set<double>";
 +                literalArgs = String.format("{%s(0.0)}", function);
 +                break;
 +            case MAP:
 +                collectionType = "map<double, double>";
 +                literalArgs = String.format("{%s(0.0):0.0}", function);
 +                break;
 +            default:
 +                Assert.fail("Unsupported collection type " + kind);
 +                collectionType = null;
 +                literalArgs = null;
 +        }
 +
 +        createTable("CREATE TABLE %s (" +
 +                    " key int PRIMARY KEY," +
 +                    " val " + collectionType + ')');
 +
 +        ResultMessage.Prepared prepared = QueryProcessor.prepare(
 +                                                                String.format("INSERT INTO %s.%s (key, val) VALUES (?, %s)",
 +                                                                             KEYSPACE,
 +                                                                             currentTable(),
 +                                                                             literalArgs),
 +                                                                ClientState.forInternalCalls(), false);
 +        Assert.assertNotNull(QueryProcessor.instance.getPrepared(prepared.statementId));
 +        return prepared;
 +    }
 +
 +    private ResultMessage.Prepared prepareStatementWithDelayedValueTuple(String function)
 +    {
 +        createTable("CREATE TABLE %s (" +
 +                    " key int PRIMARY KEY," +
 +                    " val tuple<double> )");
 +
 +        ResultMessage.Prepared prepared = QueryProcessor.prepare(
 +                                                                String.format("INSERT INTO %s.%s (key, val) VALUES (?, (%s(0.0)))",
 +                                                                             KEYSPACE,
 +                                                                             currentTable(),
 +                                                                             function),
 +                                                                ClientState.forInternalCalls(), false);
 +        Assert.assertNotNull(QueryProcessor.instance.getPrepared(prepared.statementId));
 +        return prepared;
 +    }
 +
 +    public void checkDelayedValuesCorrectlyIdentifyFunctionsInUse(boolean dropKeyspace) throws Throwable
 +    {
 +        // prepare a statement which doesn't use any function for a control
 +        createTable("CREATE TABLE %s (" +
 +                    " key int PRIMARY KEY," +
 +                    " val double)");
 +        ResultMessage.Prepared control = QueryProcessor.prepare(
 +                                                               String.format("INSERT INTO %s.%s (key, val) VALUES (?, ?)",
 +                                                                            KEYSPACE,
 +                                                                            currentTable()),
 +                                                               ClientState.forInternalCalls(), false);
 +        Assert.assertNotNull(QueryProcessor.instance.getPrepared(control.statementId));
 +
 +        // a function that we'll drop and verify that statements which use it to
 +        // provide a DelayedValue are removed from the cache in QueryProcessor
 +        String function = createFunction(KEYSPACE_PER_TEST, "double",
 +                                        "CREATE FUNCTION %s ( input double ) " +
 +                                        "CALLED ON NULL INPUT " +
 +                                        "RETURNS double " +
 +                                        "LANGUAGE javascript " +
 +                                        "AS 'input'");
 +        Assert.assertEquals(1, Functions.find(parseFunctionName(function)).size());
 +
 +        List<ResultMessage.Prepared> prepared = new ArrayList<>();
 +        // prepare statements which use the function to provide a DelayedValue
 +        prepared.add(prepareStatementWithDelayedValue(CollectionType.Kind.LIST, function));
 +        prepared.add(prepareStatementWithDelayedValue(CollectionType.Kind.SET, function));
 +        prepared.add(prepareStatementWithDelayedValue(CollectionType.Kind.MAP, function));
 +        prepared.add(prepareStatementWithDelayedValueTuple(function));
 +
 +        // what to drop - the function is scoped to the per-test keyspace, but the prepared statements
 +        // select from the per-fixture keyspace. So if we drop the per-test keyspace, the function
 +        // should be removed along with the statements that reference it. The control statement should
 +        // remain present in the cache. Likewise, if we actually drop the function itself the control
 +        // statement should not be removed, but the others should be
 +        if (dropKeyspace)
 +            dropPerTestKeyspace();
 +        else
 +            execute("DROP FUNCTION " + function);
 +
 +        Assert.assertNotNull(QueryProcessor.instance.getPrepared(control.statementId));
 +        for (ResultMessage.Prepared removed : prepared)
 +            Assert.assertNull(QueryProcessor.instance.getPrepared(removed.statementId));
 +    }
 +
 +    @Test
 +    public void testFunctionCreationAndDrop() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (key int PRIMARY KEY, d double)");
 +
 +        execute("INSERT INTO %s(key, d) VALUES (?, ?)", 1, 1d);
 +        execute("INSERT INTO %s(key, d) VALUES (?, ?)", 2, 2d);
 +        execute("INSERT INTO %s(key, d) VALUES (?, ?)", 3, 3d);
 +
 +        // simple creation
 +        String fSin = createFunction(KEYSPACE_PER_TEST, "double",
 +                                     "CREATE FUNCTION %s ( input double ) " +
 +                                     "CALLED ON NULL INPUT " +
 +                                     "RETURNS double " +
 +                                     "LANGUAGE java " +
 +                                     "AS 'return Math.sin(input);'");
 +        // check we can't recreate the same function
 +        assertInvalidMessage("already exists",
 +                             "CREATE FUNCTION " + fSin + " ( input double ) " +
 +                             "CALLED ON NULL INPUT " +
 +                             "RETURNS double " +
 +                             "LANGUAGE java AS 'return Double.valueOf(Math.sin(input.doubleValue()));'");
 +
 +        // but that it doesn't comply with "IF NOT EXISTS"
 +        execute("CREATE FUNCTION IF NOT EXISTS " + fSin + " ( input double ) " +
 +                "CALLED ON NULL INPUT " +
 +                "RETURNS double " +
 +                "LANGUAGE java AS 'return Double.valueOf(Math.sin(input.doubleValue()));'");
 +
 +        // Validate that it works as expected
 +        assertRows(execute("SELECT key, " + fSin + "(d) FROM %s"),
 +            row(1, Math.sin(1d)),
 +            row(2, Math.sin(2d)),
 +            row(3, Math.sin(3d))
 +        );
 +
 +        // Replace the method with incompatible return type
 +        assertInvalidMessage("the new return type text is not compatible with the return type double of existing function",
 +                             "CREATE OR REPLACE FUNCTION " + fSin + " ( input double ) " +
 +                             "CALLED ON NULL INPUT " +
 +                             "RETURNS text " +
 +                             "LANGUAGE java AS 'return Double.valueOf(42d);'");
 +
 +        // proper replacement
 +        execute("CREATE OR REPLACE FUNCTION " + fSin + " ( input double ) " +
 +                "CALLED ON NULL INPUT " +
 +                "RETURNS double " +
 +                "LANGUAGE java AS 'return Double.valueOf(42d);'");
 +
 +        // Validate the method as been replaced
 +        assertRows(execute("SELECT key, " + fSin + "(d) FROM %s"),
 +            row(1, 42.0),
 +            row(2, 42.0),
 +            row(3, 42.0)
 +        );
 +
 +        // same function but other keyspace
 +        String fSin2 = createFunction(KEYSPACE, "double",
 +                                      "CREATE FUNCTION %s ( input double ) " +
 +                                      "RETURNS NULL ON NULL INPUT " +
 +                                      "RETURNS double " +
 +                                      "LANGUAGE java " +
 +                                      "AS 'return Math.sin(input);'");
 +        assertRows(execute("SELECT key, " + fSin2 + "(d) FROM %s"),
 +            row(1, Math.sin(1d)),
 +            row(2, Math.sin(2d)),
 +            row(3, Math.sin(3d))
 +        );
 +
 +        // Drop
 +        execute("DROP FUNCTION " + fSin);
 +        execute("DROP FUNCTION " + fSin2);
 +
 +        // Drop unexisting function
 +        assertInvalidMessage("Cannot drop non existing function", "DROP FUNCTION " + fSin);
 +        // but don't complain with "IF EXISTS"
 +        execute("DROP FUNCTION IF EXISTS " + fSin);
 +
 +        // can't drop native functions
 +        assertInvalidMessage("system keyspace is not user-modifiable", "DROP FUNCTION totimestamp");
 +        assertInvalidMessage("system keyspace is not user-modifiable", "DROP FUNCTION uuid");
 +
 +        // sin() no longer exists
 +        assertInvalidMessage("Unknown function", "SELECT key, sin(d) FROM %s");
 +    }
 +
 +    @Test
 +    public void testFunctionExecution() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (v text PRIMARY KEY)");
 +
 +        execute("INSERT INTO %s(v) VALUES (?)", "aaa");
 +
 +        String fRepeat = createFunction(KEYSPACE_PER_TEST, "text,int",
 +                                        "CREATE FUNCTION %s(v text, n int) " +
 +                                        "RETURNS NULL ON NULL INPUT " +
 +                                        "RETURNS text " +
 +                                        "LANGUAGE java " +
 +                                        "AS 'StringBuilder sb = new StringBuilder();\n" +
 +                                        "    for (int i = 0; i < n; i++)\n" +
 +                                        "        sb.append(v);\n" +
 +                                        "    return sb.toString();'");
 +
 +        assertRows(execute("SELECT v FROM %s WHERE v=" + fRepeat + "(?, ?)", "a", 3), row("aaa"));
 +        assertEmpty(execute("SELECT v FROM %s WHERE v=" + fRepeat + "(?, ?)", "a", 2));
 +    }
 +
 +    @Test
 +    public void testFunctionExecutionWithReversedTypeAsOutput() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (k int, v text, PRIMARY KEY(k, v)) WITH CLUSTERING ORDER BY (v DESC)");
 +
 +        String fRepeat = createFunction(KEYSPACE_PER_TEST, "text",
 +                                        "CREATE FUNCTION %s(v text) " +
 +                                        "RETURNS NULL ON NULL INPUT " +
 +                                        "RETURNS text " +
 +                                        "LANGUAGE java " +
 +                                        "AS 'return v + v;'");
 +
 +        execute("INSERT INTO %s(k, v) VALUES (?, " + fRepeat + "(?))", 1, "a");
 +    }
 +
 +    @Test
 +    public void testFunctionOverloading() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (k text PRIMARY KEY, v int)");
 +
 +        execute("INSERT INTO %s(k, v) VALUES (?, ?)", "f2", 1);
 +
 +        String fOverload = createFunction(KEYSPACE_PER_TEST, "varchar",
 +                                          "CREATE FUNCTION %s ( input varchar ) " +
 +                                          "RETURNS NULL ON NULL INPUT " +
 +                                          "RETURNS text " +
 +                                          "LANGUAGE java " +
 +                                          "AS 'return \"f1\";'");
 +        createFunctionOverload(fOverload,
 +                               "int",
 +                               "CREATE OR REPLACE FUNCTION %s(i int) " +
 +                               "RETURNS NULL ON NULL INPUT " +
 +                               "RETURNS text " +
 +                               "LANGUAGE java " +
 +                               "AS 'return \"f2\";'");
 +        createFunctionOverload(fOverload,
 +                               "text,text",
 +                               "CREATE OR REPLACE FUNCTION %s(v1 text, v2 text) " +
 +                               "RETURNS NULL ON NULL INPUT " +
 +                               "RETURNS text " +
 +                               "LANGUAGE java " +
 +                               "AS 'return \"f3\";'");
 +        createFunctionOverload(fOverload,
 +                               "ascii",
 +                               "CREATE OR REPLACE FUNCTION %s(v ascii) " +
 +                               "RETURNS NULL ON NULL INPUT " +
 +                               "RETURNS text " +
 +                               "LANGUAGE java " +
 +                               "AS 'return \"f1\";'");
 +
 +        // text == varchar, so this should be considered as a duplicate
 +        assertInvalidMessage("already exists",
 +                             "CREATE FUNCTION " + fOverload + "(v varchar) " +
 +                             "RETURNS NULL ON NULL INPUT " +
 +                             "RETURNS text " +
 +                             "LANGUAGE java AS 'return \"f1\";'");
 +
 +        assertRows(execute("SELECT " + fOverload + "(k), " + fOverload + "(v), " + fOverload + "(k, k) FROM %s"),
 +            row("f1", "f2", "f3")
 +        );
 +
 +        forcePreparedValues();
 +        // This shouldn't work if we use preparation since there no way to know which overload to use
 +        assertInvalidMessage("Ambiguous call to function", "SELECT v FROM %s WHERE k = " + fOverload + "(?)", "foo");
 +        stopForcingPreparedValues();
 +
 +        // but those should since we specifically cast
 +        assertEmpty(execute("SELECT v FROM %s WHERE k = " + fOverload + "((text)?)", "foo"));
 +        assertRows(execute("SELECT v FROM %s WHERE k = " + fOverload + "((int)?)", 3), row(1));
 +        assertEmpty(execute("SELECT v FROM %s WHERE k = " + fOverload + "((ascii)?)", "foo"));
 +        // And since varchar == text, this should work too
 +        assertEmpty(execute("SELECT v FROM %s WHERE k = " + fOverload + "((varchar)?)", "foo"));
 +
 +        // no such functions exist...
 +        assertInvalidMessage("non existing function", "DROP FUNCTION " + fOverload + "(boolean)");
 +        assertInvalidMessage("non existing function", "DROP FUNCTION " + fOverload + "(bigint)");
 +
 +        // 'overloaded' has multiple overloads - so it has to fail (CASSANDRA-7812)
 +        assertInvalidMessage("matches multiple function definitions", "DROP FUNCTION " + fOverload);
 +        execute("DROP FUNCTION " + fOverload + "(varchar)");
 +        assertInvalidMessage("none of its type signatures match", "SELECT v FROM %s WHERE k = " + fOverload + "((text)?)", "foo");
 +        execute("DROP FUNCTION " + fOverload + "(text, text)");
 +        assertInvalidMessage("none of its type signatures match", "SELECT v FROM %s WHERE k = " + fOverload + "((text)?,(text)?)", "foo", "bar");
 +        execute("DROP FUNCTION " + fOverload + "(ascii)");
 +        assertInvalidMessage("cannot be passed as argument 0 of function", "SELECT v FROM %s WHERE k = " + fOverload + "((ascii)?)", "foo");
 +        // single-int-overload must still work
 +        assertRows(execute("SELECT v FROM %s WHERE k = " + fOverload + "((int)?)", 3), row(1));
 +        // overloaded has just one overload now - so the following DROP FUNCTION is not ambigious (CASSANDRA-7812)
 +        execute("DROP FUNCTION " + fOverload);
 +    }
 +
 +    @Test
 +    public void testCreateOrReplaceJavaFunction() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (key int primary key, val double)");
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 2, 2d);
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 3, 3d);
 +
 +        String fName = createFunction(KEYSPACE_PER_TEST, "double",
 +                "CREATE FUNCTION %s( input double ) " +
 +                "CALLED ON NULL INPUT " +
 +                "RETURNS double " +
 +                "LANGUAGE java " +
 +                "AS '\n" +
 +                "  // parameter val is of type java.lang.Double\n" +
 +                "  /* return type is of type java.lang.Double */\n" +
 +                "  if (input == null) {\n" +
 +                "    return null;\n" +
 +                "  }\n" +
 +                "  return Math.sin( input );\n" +
 +                "';");
 +
 +        // just check created function
 +        assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
 +                   row(1, 1d, Math.sin(1d)),
 +                   row(2, 2d, Math.sin(2d)),
 +                   row(3, 3d, Math.sin(3d))
 +        );
 +
 +        execute("CREATE OR REPLACE FUNCTION " + fName + "( input double ) " +
 +                "CALLED ON NULL INPUT " +
 +                "RETURNS double " +
 +                "LANGUAGE java\n" +
 +                "AS '\n" +
 +                "  return input;\n" +
 +                "';");
 +
 +        // check if replaced function returns correct result
 +        assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
 +                   row(1, 1d, 1d),
 +                   row(2, 2d, 2d),
 +                   row(3, 3d, 3d)
 +        );
 +    }
 +
 +    @Test
 +    public void testJavaFunctionNoParameters() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (key int primary key, val double)");
 +
 +        String functionBody = "\n  return 1L;\n";
 +
 +        String fName = createFunction(KEYSPACE, "",
 +                                      "CREATE OR REPLACE FUNCTION %s() " +
 +                                      "RETURNS NULL ON NULL INPUT " +
 +                                      "RETURNS bigint " +
 +                                      "LANGUAGE JAVA\n" +
 +                                      "AS '" +functionBody + "';");
 +
 +        assertRows(execute("SELECT language, body FROM system.schema_functions WHERE keyspace_name=? AND function_name=?",
 +                           KEYSPACE, parseFunctionName(fName).name),
 +                   row("java", functionBody));
 +
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 2, 2d);
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 3, 3d);
 +        assertRows(execute("SELECT key, val, " + fName + "() FROM %s"),
 +                   row(1, 1d, 1L),
 +                   row(2, 2d, 1L),
 +                   row(3, 3d, 1L)
 +        );
 +    }
 +
 +    @Test
 +    public void testJavaFunctionInvalidBodies() throws Throwable
 +    {
 +        try
 +        {
 +            execute("CREATE OR REPLACE FUNCTION " + KEYSPACE + ".jfinv() " +
 +                    "RETURNS NULL ON NULL INPUT " +
 +                    "RETURNS bigint " +
 +                    "LANGUAGE JAVA\n" +
 +                    "AS '\n" +
 +                    "foobarbaz" +
 +                    "\n';");
 +            Assert.fail();
 +        }
 +        catch (InvalidRequestException e)
 +        {
 +            Assert.assertTrue(e.getMessage(), e.getMessage().contains("Java source compilation failed"));
 +            Assert.assertTrue(e.getMessage(), e.getMessage().contains("insert \";\" to complete BlockStatements"));
 +        }
 +
 +        try
 +        {
 +            execute("CREATE OR REPLACE FUNCTION " + KEYSPACE + ".jfinv() " +
 +                    "RETURNS NULL ON NULL INPUT " +
 +                    "RETURNS bigint " +
 +                    "LANGUAGE JAVA\n" +
 +                    "AS '\n" +
 +                    "foobarbaz;" +
 +                    "\n';");
 +            Assert.fail();
 +        }
 +        catch (InvalidRequestException e)
 +        {
 +            Assert.assertTrue(e.getMessage(), e.getMessage().contains("Java source compilation failed"));
 +            Assert.assertTrue(e.getMessage(), e.getMessage().contains("foobarbaz cannot be resolved to a type"));
 +        }
 +    }
 +
 +    @Test
 +    public void testJavaFunctionInvalidReturn() throws Throwable
 +    {
 +        assertInvalidMessage("system keyspace is not user-modifiable",
 +                             "CREATE OR REPLACE FUNCTION jfir(val double) " +
 +                             "RETURNS NULL ON NULL INPUT " +
 +                             "RETURNS double " +
 +                             "LANGUAGE JAVA\n" +
 +                             "AS 'return 1L;';");
 +    }
 +
 +    @Test
 +    public void testJavaFunctionArgumentTypeMismatch() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (key int primary key, val bigint)");
 +
 +        String fName = createFunction(KEYSPACE, "double",
 +                                      "CREATE OR REPLACE FUNCTION %s(val double)" +
 +                                      "RETURNS NULL ON NULL INPUT " +
 +                                      "RETURNS double " +
 +                                      "LANGUAGE JAVA " +
 +                                      "AS 'return Double.valueOf(val);';");
 +
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1L);
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 2, 2L);
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 3, 3L);
 +        assertInvalidMessage("val cannot be passed as argument 0 of function",
 +                             "SELECT key, val, " + fName + "(val) FROM %s");
 +    }
 +
 +    @Test
 +    public void testJavaFunction() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (key int primary key, val double)");
 +
 +        String functionBody = '\n' +
 +                              "  // parameter val is of type java.lang.Double\n" +
 +                              "  /* return type is of type java.lang.Double */\n" +
 +                              "  if (val == null) {\n" +
 +                              "    return null;\n" +
 +                              "  }\n" +
 +                              "  return Math.sin(val);\n";
 +
 +        String fName = createFunction(KEYSPACE, "double",
 +                                      "CREATE OR REPLACE FUNCTION %s(val double) " +
 +                                      "CALLED ON NULL INPUT " +
 +                                      "RETURNS double " +
 +                                      "LANGUAGE JAVA " +
 +                                      "AS '" + functionBody + "';");
 +
 +        FunctionName fNameName = parseFunctionName(fName);
 +
 +        assertRows(execute("SELECT language, body FROM system.schema_functions WHERE keyspace_name=? AND function_name=?",
 +                           fNameName.keyspace, fNameName.name),
 +                   row("java", functionBody));
 +
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 2, 2d);
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 3, 3d);
 +        assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
 +                   row(1, 1d, Math.sin(1d)),
 +                   row(2, 2d, Math.sin(2d)),
 +                   row(3, 3d, Math.sin(3d))
 +        );
 +    }
 +
 +    @Test
 +    public void testFunctionInTargetKeyspace() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (key int primary key, val double)");
 +
 +        execute("CREATE TABLE " + KEYSPACE_PER_TEST + ".second_tab (key int primary key, val double)");
 +
 +        String fName = createFunction(KEYSPACE_PER_TEST, "double",
 +                                      "CREATE OR REPLACE FUNCTION %s(val double) " +
 +                                      "RETURNS NULL ON NULL INPUT " +
 +                                      "RETURNS double " +
 +                                      "LANGUAGE JAVA " +
 +                                      "AS 'return Double.valueOf(val);';");
 +
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 2, 2d);
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 3, 3d);
 +        assertInvalidMessage("Unknown function",
 +                             "SELECT key, val, " + parseFunctionName(fName).name + "(val) FROM %s");
 +
 +        execute("INSERT INTO " + KEYSPACE_PER_TEST + ".second_tab (key, val) VALUES (?, ?)", 1, 1d);
 +        execute("INSERT INTO " + KEYSPACE_PER_TEST + ".second_tab (key, val) VALUES (?, ?)", 2, 2d);
 +        execute("INSERT INTO " + KEYSPACE_PER_TEST + ".second_tab (key, val) VALUES (?, ?)", 3, 3d);
 +        assertRows(execute("SELECT key, val, " + fName + "(val) FROM " + KEYSPACE_PER_TEST + ".second_tab"),
 +                   row(1, 1d, 1d),
 +                   row(2, 2d, 2d),
 +                   row(3, 3d, 3d)
 +        );
 +    }
 +
 +    @Test
 +    public void testFunctionWithReservedName() throws Throwable
 +    {
 +        execute("CREATE TABLE " + KEYSPACE_PER_TEST + ".second_tab (key int primary key, val double)");
 +
 +        String fName = createFunction(KEYSPACE_PER_TEST, "",
 +                                      "CREATE OR REPLACE FUNCTION %s() " +
 +                                      "RETURNS NULL ON NULL INPUT " +
 +                                      "RETURNS timestamp " +
 +                                      "LANGUAGE JAVA " +
 +                                      "AS 'return null;';");
 +
 +        execute("INSERT INTO " + KEYSPACE_PER_TEST + ".second_tab (key, val) VALUES (?, ?)", 1, 1d);
 +        execute("INSERT INTO " + KEYSPACE_PER_TEST + ".second_tab (key, val) VALUES (?, ?)", 2, 2d);
 +        execute("INSERT INTO " + KEYSPACE_PER_TEST + ".second_tab (key, val) VALUES (?, ?)", 3, 3d);
 +
 +        // ensure that system now() is executed
 +        UntypedResultSet rows = execute("SELECT key, val, now() FROM " + KEYSPACE_PER_TEST + ".second_tab");
 +        Assert.assertEquals(3, rows.size());
 +        UntypedResultSet.Row row = rows.iterator().next();
 +        Date ts = row.getTimestamp(row.getColumns().get(2).name.toString());
 +        Assert.assertNotNull(ts);
 +
 +        // ensure that KEYSPACE_PER_TEST's now() is executed
 +        rows = execute("SELECT key, val, " + fName + "() FROM " + KEYSPACE_PER_TEST + ".second_tab");
 +        Assert.assertEquals(3, rows.size());
 +        row = rows.iterator().next();
 +        Assert.assertFalse(row.has(row.getColumns().get(2).name.toString()));
 +    }
 +
 +    @Test
 +    public void testFunctionInSystemKS() throws Throwable
 +    {
 +        execute("CREATE OR REPLACE FUNCTION " + KEYSPACE + ".totimestamp(val timeuuid) " +
 +                "RETURNS NULL ON NULL INPUT " +
 +                "RETURNS timestamp " +
 +                "LANGUAGE JAVA\n" +
 +
 +                "AS 'return null;';");
 +
 +        assertInvalidMessage("system keyspace is not user-modifiable",
 +                             "CREATE OR REPLACE FUNCTION system.jnft(val double) " +
 +                             "RETURNS NULL ON NULL INPUT " +
 +                             "RETURNS double " +
 +                             "LANGUAGE JAVA\n" +
 +                             "AS 'return null;';");
 +        assertInvalidMessage("system keyspace is not user-modifiable",
 +                             "CREATE OR REPLACE FUNCTION system.totimestamp(val timeuuid) " +
 +                             "RETURNS NULL ON NULL INPUT " +
 +                             "RETURNS timestamp " +
 +                             "LANGUAGE JAVA\n" +
 +
 +                             "AS 'return null;';");
 +        assertInvalidMessage("system keyspace is not user-modifiable",
 +                             "DROP FUNCTION system.now");
 +
 +        // KS for executeInternal() is system
 +        assertInvalidMessage("system keyspace is not user-modifiable",
 +                             "CREATE OR REPLACE FUNCTION jnft(val double) " +
 +                             "RETURNS NULL ON NULL INPUT " +
 +                             "RETURNS double " +
 +                             "LANGUAGE JAVA\n" +
 +                             "AS 'return null;';");
 +        assertInvalidMessage("system keyspace is not user-modifiable",
 +                             "CREATE OR REPLACE FUNCTION totimestamp(val timeuuid) " +
 +                             "RETURNS NULL ON NULL INPUT " +
 +                             "RETURNS timestamp " +
 +                             "LANGUAGE JAVA\n" +
 +                             "AS 'return null;';");
 +        assertInvalidMessage("system keyspace is not user-modifiable",
 +                             "DROP FUNCTION now");
 +    }
 +
 +    @Test
 +    public void testFunctionNonExistingKeyspace() throws Throwable
 +    {
 +        assertInvalidMessage("to non existing keyspace",
 +                             "CREATE OR REPLACE FUNCTION this_ks_does_not_exist.jnft(val double) " +
 +                             "RETURNS NULL ON NULL INPUT " +
 +                             "RETURNS double " +
 +                             "LANGUAGE JAVA\n" +
 +                             "AS 'return null;';");
 +    }
 +
 +    @Test
 +    public void testFunctionAfterOnDropKeyspace() throws Throwable
 +    {
 +        dropPerTestKeyspace();
 +
 +        assertInvalidMessage("to non existing keyspace",
 +                             "CREATE OR REPLACE FUNCTION " + KEYSPACE_PER_TEST + ".jnft(val double) " +
 +                             "RETURNS NULL ON NULL INPUT " +
 +                             "RETURNS double " +
 +                             "LANGUAGE JAVA\n" +
 +                             "AS 'return null;';");
 +    }
 +
 +    @Test
 +    public void testJavaKeyspaceFunction() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (key int primary key, val double)");
 +
 +        String functionBody = '\n' +
 +                              "  // parameter val is of type java.lang.Double\n" +
 +                              "  /* return type is of type java.lang.Double */\n" +
 +                              "  if (val == null) {\n" +
 +                              "    return null;\n" +
 +                              "  }\n" +
 +                              "  return Math.sin( val );\n";
 +
 +        String fName = createFunction(KEYSPACE_PER_TEST, "double",
 +                                     "CREATE OR REPLACE FUNCTION %s(val double) " +
 +                                     "CALLED ON NULL INPUT " +
 +                                     "RETURNS double " +
 +                                     "LANGUAGE JAVA " +
 +                                     "AS '" + functionBody + "';");
 +
 +        FunctionName fNameName = parseFunctionName(fName);
 +
 +        assertRows(execute("SELECT language, body FROM system.schema_functions WHERE keyspace_name=? AND function_name=?",
 +                           fNameName.keyspace, fNameName.name),
 +                   row("java", functionBody));
 +
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 2, 2d);
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 3, 3d);
 +        assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
 +                   row(1, 1d, Math.sin(1d)),
 +                   row(2, 2d, Math.sin(2d)),
 +                   row(3, 3d, Math.sin(3d))
 +        );
 +    }
 +
 +    @Test
 +    public void testJavaRuntimeException() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (key int primary key, val double)");
 +
 +        String functionBody = '\n' +
 +                              "  throw new RuntimeException(\"oh no!\");\n";
 +
 +        String fName = createFunction(KEYSPACE_PER_TEST, "double",
 +                                      "CREATE OR REPLACE FUNCTION %s(val double) " +
 +                                      "RETURNS NULL ON NULL INPUT " +
 +                                      "RETURNS double " +
 +                                      "LANGUAGE JAVA\n" +
 +                                      "AS '" + functionBody + "';");
 +
 +        FunctionName fNameName = parseFunctionName(fName);
 +
 +        assertRows(execute("SELECT language, body FROM system.schema_functions WHERE keyspace_name=? AND function_name=?",
 +                           fNameName.keyspace, fNameName.name),
 +                   row("java", functionBody));
 +
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 2, 2d);
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 3, 3d);
 +
 +        // function throws a RuntimeException which is wrapped by FunctionExecutionException
 +        assertInvalidThrowMessage("java.lang.RuntimeException: oh no", FunctionExecutionException.class,
 +                                  "SELECT key, val, " + fName + "(val) FROM %s");
 +    }
 +
 +    @Test
 +    public void testJavaDollarQuotedFunction() throws Throwable
 +    {
 +        String functionBody = '\n' +
 +                              "  // parameter val is of type java.lang.Double\n" +
 +                              "  /* return type is of type java.lang.Double */\n" +
 +                              "  if (input == null) {\n" +
 +                              "    return null;\n" +
 +                              "  }\n" +
 +                              "  return \"'\"+Math.sin(input)+'\\\'';\n";
 +
 +        String fName = createFunction(KEYSPACE_PER_TEST, "double",
 +                                      "CREATE FUNCTION %s( input double ) " +
 +                                      "CALLED ON NULL INPUT " +
 +                                      "RETURNS text " +
 +                                      "LANGUAGE java\n" +
 +                                      "AS $$" + functionBody + "$$;");
 +
 +        FunctionName fNameName = parseFunctionName(fName);
 +
 +        assertRows(execute("SELECT language, body FROM system.schema_functions WHERE keyspace_name=? AND function_name=?",
 +                           fNameName.keyspace, fNameName.name),
 +                   row("java", functionBody));
 +    }
 +
 +    @Test
 +    public void testJavaSimpleCollections() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (key int primary key, lst list<double>, st set<text>, mp map<int, boolean>)");
 +
 +        String fList = createFunction(KEYSPACE_PER_TEST, "list<double>",
 +                                     "CREATE FUNCTION %s( lst list<double> ) " +
 +                                     "RETURNS NULL ON NULL INPUT " +
 +                                     "RETURNS list<double> " +
 +                                     "LANGUAGE java\n" +
 +                                     "AS $$return lst;$$;");
 +        String fSet = createFunction(KEYSPACE_PER_TEST, "set<text>",
 +                                     "CREATE FUNCTION %s( st set<text> ) " +
 +                                     "RETURNS NULL ON NULL INPUT " +
 +                                     "RETURNS set<text> " +
 +                                     "LANGUAGE java\n" +
 +                                     "AS $$return st;$$;");
 +        String fMap = createFunction(KEYSPACE_PER_TEST, "map<int, boolean>",
 +                                     "CREATE FUNCTION %s( mp map<int, boolean> ) " +
 +                                     "RETURNS NULL ON NULL INPUT " +
 +                                     "RETURNS map<int, boolean> " +
 +                                     "LANGUAGE java\n" +
 +                                     "AS $$return mp;$$;");
 +
 +        List<Double> list = Arrays.asList(1d, 2d, 3d);
 +        Set<String> set = new TreeSet<>(Arrays.asList("one", "three", "two"));
 +        Map<Integer, Boolean> map = new TreeMap<>();
 +        map.put(1, true);
 +        map.put(2, false);
 +        map.put(3, true);
 +
 +        execute("INSERT INTO %s (key, lst, st, mp) VALUES (1, ?, ?, ?)", list, set, map);
 +
 +        assertRows(execute("SELECT " + fList + "(lst), " + fSet + "(st), " + fMap + "(mp) FROM %s WHERE key = 1"),
 +                   row(list, set, map));
 +
 +        // same test - but via native protocol
 +        for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
 +            assertRowsNet(version,
 +                          executeNet(version, "SELECT " + fList + "(lst), " + fSet + "(st), " + fMap + "(mp) FROM %s WHERE key = 1"),
 +                          row(list, set, map));
 +    }
 +
 +    @Test
 +    public void testWrongKeyspace() throws Throwable
 +    {
 +        String typeName = createType("CREATE TYPE %s (txt text, i int)");
 +        String type = KEYSPACE + '.' + typeName;
 +
 +        assertInvalidMessage(String.format("Statement on keyspace %s cannot refer to a user type in keyspace %s; user types can only be used in the keyspace they are defined in",
 +                                           KEYSPACE_PER_TEST, KEYSPACE),
 +                             "CREATE FUNCTION " + KEYSPACE_PER_TEST + ".test_wrong_ks( val int ) " +
 +                             "CALLED ON NULL INPUT " +
 +                             "RETURNS " + type + " " +
 +                             "LANGUAGE java\n" +
 +                             "AS $$return val;$$;");
 +
 +        assertInvalidMessage(String.format("Statement on keyspace %s cannot refer to a user type in keyspace %s; user types can only be used in the keyspace they are defined in",
 +                                           KEYSPACE_PER_TEST, KEYSPACE),
 +                             "CREATE FUNCTION " + KEYSPACE_PER_TEST + ".test_wrong_ks( val " + type + " ) " +
 +                             "CALLED ON NULL INPUT " +
 +                             "RETURNS int " +
 +                             "LANGUAGE java\n" +
 +                             "AS $$return val;$$;");
 +    }
 +
 +    @Test
 +    public void testComplexNullValues() throws Throwable
 +    {
 +        String type = KEYSPACE + '.' + createType("CREATE TYPE %s (txt text, i int)");
 +
 +        createTable("CREATE TABLE %s (key int primary key, lst list<double>, st set<text>, mp map<int, boolean>," +
 +                    "tup frozen<tuple<double, text, int, boolean>>, udt frozen<" + type + ">)");
 +
 +        String fList = createFunction(KEYSPACE, "list<double>",
 +                                      "CREATE FUNCTION %s( coll list<double> ) " +
 +                                      "CALLED ON NULL INPUT " +
 +                                      "RETURNS list<double> " +
 +                                      "LANGUAGE java\n" +
 +                                      "AS $$return coll;$$;");
 +        String fSet = createFunction(KEYSPACE, "set<text>",
 +                                     "CREATE FUNCTION %s( coll set<text> ) " +
 +                                     "CALLED ON NULL INPUT " +
 +                                     "RETURNS set<text> " +
 +                                     "LANGUAGE java\n" +
 +                                     "AS $$return coll;$$;");
 +        String fMap = createFunction(KEYSPACE, "map<int, boolean>",
 +                                     "CREATE FUNCTION %s( coll map<int, boolean> ) " +
 +                                     "CALLED ON NULL INPUT " +
 +                                     "RETURNS map<int, boolean> " +
 +                                     "LANGUAGE java\n" +
 +                                     "AS $$return coll;$$;");
 +        String fTup = createFunction(KEYSPACE, "tuple<double, text, int, boolean>",
 +                                     "CREATE FUNCTION %s( val tuple<double, text, int, boolean> ) " +
 +                                     "CALLED ON NULL INPUT " +
 +                                     "RETURNS tuple<double, text, int, boolean> " +
 +                                     "LANGUAGE java\n" +
 +                                     "AS $$return val;$$;");
 +        String fUdt = createFunction(KEYSPACE, type,
 +                                     "CREATE FUNCTION %s( val " + type + " ) " +
 +                                     "CALLED ON NULL INPUT " +
 +                                     "RETURNS " + type + " " +
 +                                     "LANGUAGE java\n" +
 +                                     "AS $$return val;$$;");
 +        List<Double> list = Arrays.asList(1d, 2d, 3d);
 +        Set<String> set = new TreeSet<>(Arrays.asList("one", "three", "two"));
 +        Map<Integer, Boolean> map = new TreeMap<>();
 +        map.put(1, true);
 +        map.put(2, false);
 +        map.put(3, true);
 +        Object t = tuple(1d, "one", 42, false);
 +
 +        execute("INSERT INTO %s (key, lst, st, mp, tup, udt) VALUES (1, ?, ?, ?, ?, {txt: 'one', i:1})", list, set, map, t);
 +        execute("INSERT INTO %s (key, lst, st, mp, tup, udt) VALUES (2, ?, ?, ?, ?, null)", null, null, null, null);
 +
 +        execute("SELECT " +
 +                fList + "(lst), " +
 +                fSet + "(st), " +
 +                fMap + "(mp), " +
 +                fTup + "(tup), " +
 +                fUdt + "(udt) FROM %s WHERE key = 1");
 +        UntypedResultSet.Row row = execute("SELECT " +
 +                                           fList + "(lst) as l, " +
 +                                           fSet + "(st) as s, " +
 +                                           fMap + "(mp) as m, " +
 +                                           fTup + "(tup) as t, " +
 +                                           fUdt + "(udt) as u " +
 +                                           "FROM %s WHERE key = 1").one();
 +        Assert.assertNotNull(row.getBytes("l"));
 +        Assert.assertNotNull(row.getBytes("s"));
 +        Assert.assertNotNull(row.getBytes("m"));
 +        Assert.assertNotNull(row.getBytes("t"));
 +        Assert.assertNotNull(row.getBytes("u"));
 +        row = execute("SELECT " +
 +                      fList + "(lst) as l, " +
 +                      fSet + "(st) as s, " +
 +                      fMap + "(mp) as m, " +
 +                      fTup + "(tup) as t, " +
 +                      fUdt + "(udt) as u " +
 +                      "FROM %s WHERE key = 2").one();
 +        Assert.assertNull(row.getBytes("l"));
 +        Assert.assertNull(row.getBytes("s"));
 +        Assert.assertNull(row.getBytes("m"));
 +        Assert.assertNull(row.getBytes("t"));
 +        Assert.assertNull(row.getBytes("u"));
 +
 +        for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
 +        {
 +            Row r = executeNet(version, "SELECT " +
 +                                        fList + "(lst) as l, " +
 +                                        fSet + "(st) as s, " +
 +                                        fMap + "(mp) as m, " +
 +                                        fTup + "(tup) as t, " +
 +                                        fUdt + "(udt) as u " +
 +                                        "FROM %s WHERE key = 1").one();
 +            Assert.assertNotNull(r.getBytesUnsafe("l"));
 +            Assert.assertNotNull(r.getBytesUnsafe("s"));
 +            Assert.assertNotNull(r.getBytesUnsafe("m"));
 +            Assert.assertNotNull(r.getBytesUnsafe("t"));
 +            Assert.assertNotNull(r.getBytesUnsafe("u"));
 +            r = executeNet(version, "SELECT " +
 +                                    fList + "(lst) as l, " +
 +                                    fSet + "(st) as s, " +
 +                                    fMap + "(mp) as m, " +
 +                                    fTup + "(tup) as t, " +
 +                                    fUdt + "(udt) as u " +
 +                                    "FROM %s WHERE key = 2").one();
 +            Assert.assertNull(r.getBytesUnsafe("l"));
 +            Assert.assertNull(r.getBytesUnsafe("s"));
 +            Assert.assertNull(r.getBytesUnsafe("m"));
 +            Assert.assertNull(r.getBytesUnsafe("t"));
 +            Assert.assertNull(r.getBytesUnsafe("u"));
 +        }
 +    }
 +
 +    @Test
 +    public void testJavaTupleType() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (key int primary key, tup frozen<tuple<double, text, int, boolean>>)");
 +
 +        String fName = createFunction(KEYSPACE, "tuple<double, text, int, boolean>",
 +                                     "CREATE FUNCTION %s( tup tuple<double, text, int, boolean> ) " +
 +                                     "RETURNS NULL ON NULL INPUT " +
 +                                     "RETURNS tuple<double, text, int, boolean> " +
 +                                     "LANGUAGE java\n" +
 +                                     "AS $$return tup;$$;");
 +
 +        Object t = tuple(1d, "foo", 2, true);
 +
 +        execute("INSERT INTO %s (key, tup) VALUES (1, ?)", t);
 +
 +        assertRows(execute("SELECT tup FROM %s WHERE key = 1"),
 +                   row(t));
 +
 +        assertRows(execute("SELECT " + fName + "(tup) FROM %s WHERE key = 1"),
 +                   row(t));
 +    }
 +
 +    @Test
 +    public void testJavaTupleTypeCollection() throws Throwable
 +    {
 +        String tupleTypeDef = "tuple<double, list<double>, set<text>, map<int, boolean>>";
 +
 +        createTable("CREATE TABLE %s (key int primary key, tup frozen<" + tupleTypeDef + ">)");
 +
 +        String fTup0 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
 +                "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
 +                "CALLED ON NULL INPUT " +
 +                "RETURNS " + tupleTypeDef + ' ' +
 +                "LANGUAGE java\n" +
 +                "AS $$return " +
 +                "       tup;$$;");
 +        String fTup1 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
 +                "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
 +                "CALLED ON NULL INPUT " +
 +                "RETURNS double " +
 +                "LANGUAGE java\n" +
 +                "AS $$return " +
 +                "       Double.valueOf(tup.getDouble(0));$$;");
 +        String fTup2 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
 +                                      "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
 +                                      "RETURNS NULL ON NULL INPUT " +
 +                                      "RETURNS list<double> " +
 +                                      "LANGUAGE java\n" +
 +                                      "AS $$return " +
 +                                      "       tup.getList(1, Double.class);$$;");
 +        String fTup3 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
 +                "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
 +                "RETURNS NULL ON NULL INPUT " +
 +                "RETURNS set<text> " +
 +                "LANGUAGE java\n" +
 +                "AS $$return " +
 +                "       tup.getSet(2, String.class);$$;");
 +        String fTup4 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
 +                "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
 +                "RETURNS NULL ON NULL INPUT " +
 +                "RETURNS map<int, boolean> " +
 +                "LANGUAGE java\n" +
 +                "AS $$return " +
 +                "       tup.getMap(3, Integer.class, Boolean.class);$$;");
 +
 +        List<Double> list = Arrays.asList(1d, 2d, 3d);
 +        Set<String> set = new TreeSet<>(Arrays.asList("one", "three", "two"));
 +        Map<Integer, Boolean> map = new TreeMap<>();
 +        map.put(1, true);
 +        map.put(2, false);
 +        map.put(3, true);
 +
 +        Object t = tuple(1d, list, set, map);
 +
 +        execute("INSERT INTO %s (key, tup) VALUES (1, ?)", t);
 +
 +        assertRows(execute("SELECT " + fTup0 + "(tup) FROM %s WHERE key = 1"),
 +                   row(t));
 +        assertRows(execute("SELECT " + fTup1 + "(tup) FROM %s WHERE key = 1"),
 +                   row(1d));
 +        assertRows(execute("SELECT " + fTup2 + "(tup) FROM %s WHERE key = 1"),
 +                   row(list));
 +        assertRows(execute("SELECT " + fTup3 + "(tup) FROM %s WHERE key = 1"),
 +                   row(set));
 +        assertRows(execute("SELECT " + fTup4 + "(tup) FROM %s WHERE key = 1"),
 +                   row(map));
 +
 +        TupleType tType = TupleType.of(DataType.cdouble(),
 +                                       DataType.list(DataType.cdouble()),
 +                                       DataType.set(DataType.text()),
 +                                       DataType.map(DataType.cint(), DataType.cboolean()));
 +        TupleValue tup = tType.newValue(1d, list, set, map);
 +        for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
 +        {
 +            assertRowsNet(version,
 +                          executeNet(version, "SELECT " + fTup0 + "(tup) FROM %s WHERE key = 1"),
 +                          row(tup));
 +            assertRowsNet(version,
 +                          executeNet(version, "SELECT " + fTup1 + "(tup) FROM %s WHERE key = 1"),
 +                          row(1d));
 +            assertRowsNet(version,
 +                          executeNet(version, "SELECT " + fTup2 + "(tup) FROM %s WHERE key = 1"),
 +                          row(list));
 +            assertRowsNet(version,
 +                          executeNet(version, "SELECT " + fTup3 + "(tup) FROM %s WHERE key = 1"),
 +                          row(set));
 +            assertRowsNet(version,
 +                          executeNet(version, "SELECT " + fTup4 + "(tup) FROM %s WHERE key = 1"),
 +                          row(map));
 +        }
 +    }
 +
 +    @Test
 +    public void testJavaUserTypeWithUse() throws Throwable
 +    {
 +        String type = createType("CREATE TYPE %s (txt text, i int)");
 +        createTable("CREATE TABLE %s (key int primary key, udt frozen<" + KEYSPACE + '.' + type + ">)");
 +        execute("INSERT INTO %s (key, udt) VALUES (1, {txt: 'one', i:1})");
 +
 +        for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
 +        {
 +            executeNet(version, "USE " + KEYSPACE);
 +
 +            executeNet(version,
 +                       "CREATE FUNCTION f_use1( udt " + type + " ) " +
 +                       "RETURNS NULL ON NULL INPUT " +
 +                       "RETURNS " + type + " " +
 +                       "LANGUAGE java " +
 +                       "AS $$return " +
 +                       "     udt;$$;");
 +            try
 +            {
 +                List<Row> rowsNet = executeNet(version, "SELECT f_use1(udt) FROM %s WHERE key = 1").all();
 +                Assert.assertEquals(1, rowsNet.size());
 +                UDTValue udtVal = rowsNet.get(0).getUDTValue(0);
 +                Assert.assertEquals("one", udtVal.getString("txt"));
 +                Assert.assertEquals(1, udtVal.getInt("i"));
 +            }
 +            finally
 +            {
 +                executeNet(version, "DROP FUNCTION f_use1");
 +            }
 +        }
 +    }
 +
 +    @Test
 +    public void testJavaUserType() throws Throwable
 +    {
 +        String type = KEYSPACE + '.' + createType("CREATE TYPE %s (txt text, i int)");
 +
 +        createTable("CREATE TABLE %s (key int primary key, udt frozen<" + type + ">)");
 +
 +        String fUdt0 = createFunction(KEYSPACE, type,
 +                                      "CREATE FUNCTION %s( udt " + type + " ) " +
 +                                      "RETURNS NULL ON NULL INPUT " +
 +                                      "RETURNS " + type + " " +
 +                                      "LANGUAGE java " +
 +                                      "AS $$return " +
 +                                      "     udt;$$;");
 +        String fUdt1 = createFunction(KEYSPACE, type,
 +                                      "CREATE FUNCTION %s( udt " + type + ") " +
 +                                      "RETURNS NULL ON NULL INPUT " +
 +                                      "RETURNS text " +
 +                                      "LANGUAGE java " +
 +                                      "AS $$return " +
 +                                      "     udt.getString(\"txt\");$$;");
 +        String fUdt2 = createFunction(KEYSPACE, type,
 +                                      "CREATE FUNCTION %s( udt " + type + ") " +
 +                                      "CALLED ON NULL INPUT " +
 +                                      "RETURNS int " +
 +                                      "LANGUAGE java " +
 +                                      "AS $$return " +
 +                                      "     Integer.valueOf(udt.getInt(\"i\"));$$;");
 +
 +        execute("INSERT INTO %s (key, udt) VALUES (1, {txt: 'one', i:1})");
 +
 +        UntypedResultSet rows = execute("SELECT " + fUdt0 + "(udt) FROM %s WHERE key = 1");
 +        Assert.assertEquals(1, rows.size());
 +        assertRows(execute("SELECT " + fUdt1 + "(udt) FROM %s WHERE key = 1"),
 +                   row("one"));
 +        assertRows(execute("SELECT " + fUdt2 + "(udt) FROM %s WHERE key = 1"),
 +                   row(1));
 +
 +        for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
 +        {
 +            List<Row> rowsNet = executeNet(version, "SELECT " + fUdt0 + "(udt) FROM %s WHERE key = 1").all();
 +            Assert.assertEquals(1, rowsNet.size());
 +            UDTValue udtVal = rowsNet.get(0).getUDTValue(0);
 +            Assert.assertEquals("one", udtVal.getString("txt"));
 +            Assert.assertEquals(1, udtVal.getInt("i"));
 +            assertRowsNet(version,
 +                          executeNet(version, "SELECT " + fUdt1 + "(udt) FROM %s WHERE key = 1"),
 +                          row("one"));
 +            assertRowsNet(version,
 +                          executeNet(version, "SELECT " + fUdt2 + "(udt) FROM %s WHERE key = 1"),
 +                          row(1));
 +        }
 +    }
 +
 +    @Test
 +    public void testUserTypeDrop() throws Throwable
 +    {
 +        String type = KEYSPACE + '.' + createType("CREATE TYPE %s (txt text, i int)");
 +
 +        createTable("CREATE TABLE %s (key int primary key, udt frozen<" + type + ">)");
 +
 +        String fName = createFunction(KEYSPACE, type,
 +                                      "CREATE FUNCTION %s( udt " + type + " ) " +
 +                                      "CALLED ON NULL INPUT " +
 +                                      "RETURNS int " +
 +                                      "LANGUAGE java " +
 +                                      "AS $$return " +
 +                                      "     Integer.valueOf(udt.getInt(\"i\"));$$;");
 +
 +        FunctionName fNameName = parseFunctionName(fName);
 +
 +        Assert.assertEquals(1, Functions.find(fNameName).size());
 +
 +        ResultMessage.Prepared prepared = QueryProcessor.prepare(String.format("SELECT key, %s(udt) FROM %s.%s", fName, KEYSPACE, currentTable()),
 +                                                                 ClientState.forInternalCalls(), false);
 +        Assert.assertNotNull(QueryProcessor.instance.getPrepared(prepared.statementId));
 +
 +        // UT still referenced by table
 +        assertInvalidMessage("Cannot drop user type", "DROP TYPE " + type);
 +
 +        execute("DROP TABLE %s");
 +
 +        // UT still referenced by UDF
 +        assertInvalidMessage("as it is still used by function", "DROP TYPE " + type);
 +
 +        Assert.assertNull(QueryProcessor.instance.getPrepared(prepared.statementId));
 +
 +        // function stays
 +        Assert.assertEquals(1, Functions.find(fNameName).size());
 +    }
 +
 +    @Test
 +    public void testJavaUserTypeRenameField() throws Throwable
 +    {
 +        String type = KEYSPACE + '.' + createType("CREATE TYPE %s (txt text, i int)");
 +
 +        createTable("CREATE TABLE %s (key int primary key, udt frozen<" + type + ">)");
 +
 +        String fName = createFunction(KEYSPACE, type,
 +                                      "CREATE FUNCTION %s( udt " + type + " ) " +
 +                                      "RETURNS NULL ON NULL INPUT " +
 +                                      "RETURNS text " +
 +                                      "LANGUAGE java\n" +
 +                                      "AS $$return udt.getString(\"txt\");$$;");
 +
 +        execute("INSERT INTO %s (key, udt) VALUES (1, {txt: 'one', i:1})");
 +
 +        assertRows(execute("SELECT " + fName + "(udt) FROM %s WHERE key = 1"),
 +                   row("one"));
 +
 +        execute("ALTER TYPE " + type + " RENAME txt TO str");
 +
 +        assertInvalidMessage("txt is not a field defined in this UDT",
 +                             "SELECT " + fName + "(udt) FROM %s WHERE key = 1");
 +
 +        execute("ALTER TYPE " + type + " RENAME str TO txt");
 +
 +        assertRows(execute("SELECT " + fName + "(udt) FROM %s WHERE key = 1"),
 +                   row("one"));
 +    }
 +
 +    @Test
 +    public void testJavaUserTypeAddFieldWithReplace() throws Throwable
 +    {
 +        String type = KEYSPACE + '.' + createType("CREATE TYPE %s (txt text, i int)");
 +
 +        createTable("CREATE TABLE %s (key int primary key, udt frozen<" + type + ">)");
 +
 +        String fName1replace = createFunction(KEYSPACE, type,
 +                                              "CREATE FUNCTION %s( udt " + type + ") " +
 +                                              "RETURNS NULL ON NULL INPUT " +
 +                                              "RETURNS text " +
 +                                              "LANGUAGE java\n" +
 +                                              "AS $$return udt.getString(\"txt\");$$;");
 +        String fName2replace = createFunction(KEYSPACE, type,
 +                                              "CREATE FUNCTION %s( udt " + type + " ) " +
 +                                              "CALLED ON NULL INPUT " +
 +                                              "RETURNS int " +
 +                                              "LANGUAGE java\n" +
 +                                              "AS $$return Integer.valueOf(udt.getInt(\"i\"));$$;");
 +        String fName3replace = createFunction(KEYSPACE, type,
 +                                              "CREATE FUNCTION %s( udt " + type + " ) " +
 +                                              "CALLED ON NULL INPUT " +
 +                                              "RETURNS double " +
 +                                              "LANGUAGE java\n" +
 +                                              "AS $$return Double.valueOf(udt.getDouble(\"added\"));$$;");
 +        String fName4replace = createFunction(KEYSPACE, type,
 +                                              "CREATE FUNCTION %s( udt " + type + " ) " +
 +                                              "RETURNS NULL ON NULL INPUT " +
 +                                              "RETURNS " + type + " " +
 +                                              "LANGUAGE java\n" +
 +                                              "AS $$return udt;$$;");
 +
 +        String fName1noReplace = createFunction(KEYSPACE, type,
 +                                              "CREATE FUNCTION %s( udt " + type + " ) " +
 +                                              "RETURNS NULL ON NULL INPUT " +
 +                                              "RETURNS text " +
 +                                              "LANGUAGE java\n" +
 +                                              "AS $$return udt.getString(\"txt\");$$;");
 +        String fName2noReplace = createFunction(KEYSPACE, type,
 +                                              "CREATE FUNCTION %s( udt " + type + " ) " +
 +                                              "CALLED ON NULL INPUT " +
 +                                              "RETURNS int " +
 +                                              "LANGUAGE java\n" +
 +                                              "AS $$return Integer.valueOf(udt.getInt(\"i\"));$$;");
 +        String fName3noReplace = createFunction(KEYSPACE, type,
 +                                                "CREATE FUNCTION %s( udt " + type + " ) " +
 +                                                "CALLED ON NULL INPUT " +
 +                                                "RETURNS double " +
 +                                                "LANGUAGE java\n" +
 +                                                "AS $$return Double.valueOf(udt.getDouble(\"added\"));$$;");
 +        String fName4noReplace = createFunction(KEYSPACE, type,
 +                                                "CREATE FUNCTION %s( udt " + type + " ) " +
 +                                                "RETURNS NULL ON NULL INPUT " +
 +                                                "RETURNS " + type + " " +
 +                                                "LANGUAGE java\n" +
 +                                                "AS $$return udt;$$;");
 +
 +        execute("INSERT INTO %s (key, udt) VALUES (1, {txt: 'one', i:1})");
 +
 +        assertRows(execute("SELECT " + fName1replace + "(udt) FROM %s WHERE key = 1"),
 +                   row("one"));
 +        assertRows(execute("SELECT " + fName2replace + "(udt) FROM %s WHERE key = 1"),
 +                   row(1));
 +
 +        // add field
 +
 +        execute("ALTER TYPE " + type + " ADD added double");
 +
 +        execute("INSERT INTO %s (key, udt) VALUES (2, {txt: 'two', i:2, added: 2})");
 +
 +        // note: type references of functions remain at the state _before_ the type mutation
 +        // means we need to recreate the functions
 +
 +        execute(String.format("CREATE OR REPLACE FUNCTION %s( udt %s ) " +
 +                              "RETURNS NULL ON NULL INPUT " +
 +                              "RETURNS text " +
 +                              "LANGUAGE java\n" +
 +                              "AS $$return " +
 +                              "     udt.getString(\"txt\");$$;",
 +                              fName1replace, type));
 +        Assert.assertEquals(1, Functions.find(parseFunctionName(fName1replace)).size());
 +        execute(String.format("CREATE OR REPLACE FUNCTION %s( udt %s ) " +
 +                              "CALLED ON NULL INPUT " +
 +                              "RETURNS int " +
 +                              "LANGUAGE java\n" +
 +                              "AS $$return " +
 +                              "     Integer.valueOf(udt.getInt(\"i\"));$$;",
 +                              fName2replace, type));
 +        Assert.assertEquals(1, Functions.find(parseFunctionName(fName2replace)).size());
 +        execute(String.format("CREATE OR REPLACE FUNCTION %s( udt %s ) " +
 +                              "CALLED ON NULL INPUT " +
 +                              "RETURNS double " +
 +                              "LANGUAGE java\n" +
 +                              "AS $$return " +
 +                              "     Double.valueOf(udt.getDouble(\"added\"));$$;",
 +                              fName3replace, type));
 +        Assert.assertEquals(1, Functions.find(parseFunctionName(fName3replace)).size());
 +        execute(String.format("CREATE OR REPLACE FUNCTION %s( udt %s ) " +
 +                              "RETURNS NULL ON NULL INPUT " +
 +                              "RETURNS %s " +
 +                              "LANGUAGE java\n" +
 +                              "AS $$return " +
 +                              "     udt;$$;",
 +                              fName4replace, type, type));
 +        Assert.assertEquals(1, Functions.find(parseFunctionName(fName4replace)).size());
 +
 +        assertRows(execute("SELECT " + fName1replace + "(udt) FROM %s WHERE key = 2"),
 +                   row("two"));
 +        assertRows(execute("SELECT " + fName2replace + "(udt) FROM %s WHERE key = 2"),
 +                   row(2));
 +        assertRows(execute("SELECT " + fName3replace + "(udt) FROM %s WHERE key = 2"),
 +                   row(2d));
 +        assertRows(execute("SELECT " + fName3replace + "(udt) FROM %s WHERE key = 1"),
 +                   row(0d));
 +
 +        // un-replaced functions will work since the user type has changed
 +        // and the UDF has exchanged the user type reference
 +
 +        assertRows(execute("SELECT " + fName1noReplace + "(udt) FROM %s WHERE key = 2"),
 +                   row("two"));
 +        assertRows(execute("SELECT " + fName2noReplace + "(udt) FROM %s WHERE key = 2"),
 +                   row(2));
 +        assertRows(execute("SELECT " + fName3noReplace + "(udt) FROM %s WHERE key = 2"),
 +                   row(2d));
 +        assertRows(execute("SELECT " + fName3noReplace + "(udt) FROM %s WHERE key = 1"),
 +                   row(0d));
 +
 +        execute("DROP FUNCTION " + fName1replace);
 +        execute("DROP FUNCTION " + fName2replace);
 +        execute("DROP FUNCTION " + fName3replace);
 +        execute("DROP FUNCTION " + fName4replace);
 +        execute("DROP FUNCTION " + fName1noReplace);
 +        execute("DROP FUNCTION " + fName2noReplace);
 +        execute("DROP FUNCTION " + fName3noReplace);
 +        execute("DROP FUNCTION " + fName4noReplace);
 +    }
 +
 +    @Test
 +    public void testJavaUTCollections() throws Throwable
 +    {
 +        String type = KEYSPACE + '.' + createType("CREATE TYPE %s (txt text, i int)");
 +
 +        createTable(String.format("CREATE TABLE %%s " +
 +                                  "(key int primary key, lst list<frozen<%s>>, st set<frozen<%s>>, mp map<int, frozen<%s>>)",
 +                                  type, type, type));
 +
 +        String fName1 = createFunction(KEYSPACE, "list<frozen<" + type + ">>",
 +                              "CREATE FUNCTION %s( lst list<frozen<" + type + ">> ) " +
 +                              "RETURNS NULL ON NULL INPUT " +
 +                              "RETURNS text " +
 +                              "LANGUAGE java\n" +
 +                              "AS $$" +
 +                              "     com.datastax.driver.core.UDTValue udtVal = (com.datastax.driver.core.UDTValue)lst.get(1);" +
 +                              "     return udtVal.getString(\"txt\");$$;");
 +        String fName2 = createFunction(KEYSPACE, "set<frozen<" + type + ">>",
 +                                       "CREATE FUNCTION %s( st set<frozen<" + type + ">> ) " +
 +                                       "RETURNS NULL ON NULL INPUT " +
 +                                       "RETURNS text " +
 +                                       "LANGUAGE java\n" +
 +                                       "AS $$" +
 +                                       "     com.datastax.driver.core.UDTValue udtVal = (com.datastax.driver.core.UDTValue)st.iterator().next();" +
 +                                       "     return udtVal.getString(\"txt\");$$;");
 +        String fName3 = createFunction(KEYSPACE, "map<int, frozen<" + type + ">>",
 +                              "CREATE FUNCTION %s( mp map<int, frozen<" + type + ">> ) " +
 +                              "RETURNS NULL ON NULL INPUT " +
 +                              "RETURNS text " +
 +                              "LANGUAGE java\n" +
 +                              "AS $$" +
 +                              "     com.datastax.driver.core.UDTValue udtVal = (com.datastax.driver.core.UDTValue)mp.get(Integer.valueOf(3));" +
 +                              "     return udtVal.getString(\"txt\");$$;");
 +
 +        execute("INSERT INTO %s (key, lst, st, mp) values (1, " +
 +                "[ {txt: 'one', i:1}, {txt: 'three', i:1}, {txt: 'one', i:1} ] , " +
 +                "{ {txt: 'one', i:1}, {txt: 'three', i:3}, {txt: 'two', i:2} }, " +
 +                "{ 1: {txt: 'one', i:1}, 2: {txt: 'one', i:3}, 3: {txt: 'two', i:2} })");
 +
 +        assertRows(execute("SELECT " + fName1 + "(lst), " + fName2 + "(st), " + fName3 + "(mp) FROM %s WHERE key = 1"),
 +                   row("three", "one", "two"));
 +
 +        for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
 +            assertRowsNet(version,
 +                          executeNet(version, "SELECT " + fName1 + "(lst), " + fName2 + "(st), " + fName3 + "(mp) FROM %s WHERE key = 1"),
 +                          row("three", "one", "two"));
 +    }
 +
 +    @Test
 +    public void testJavascriptSimpleCollections() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (key int primary key, lst list<double>, st set<text>, mp map<int, boolean>)");
 +
 +        String fName1 = createFunction(KEYSPACE_PER_TEST, "list<double>",
 +                "CREATE FUNCTION %s( lst list<double> ) " +
 +                "RETURNS NULL ON NULL INPUT " +
 +                "RETURNS list<double> " +
 +                "LANGUAGE javascript\n" +
 +                "AS 'lst;';");
 +        String fName2 = createFunction(KEYSPACE_PER_TEST, "set<text>",
 +                "CREATE FUNCTION %s( st set<text> ) " +
 +                "RETURNS NULL ON NULL INPUT " +
 +                "RETURNS set<text> " +
 +                "LANGUAGE javascript\n" +
 +                "AS 'st;';");
 +        String fName3 = createFunction(KEYSPACE_PER_TEST, "map<int, boolean>",
 +                "CREATE FUNCTION %s( mp map<int, boolean> ) " +
 +                "RETURNS NULL ON NULL INPUT " +
 +                "RETURNS map<int, boolean> " +
 +                "LANGUAGE javascript\n" +
 +                "AS 'mp;';");
 +
 +        List<Double> list = Arrays.asList(1d, 2d, 3d);
 +        Set<String> set = new TreeSet<>(Arrays.asList("one", "three", "two"));
 +        Map<Integer, Boolean> map = new TreeMap<>();
 +        map.put(1, true);
 +        map.put(2, false);
 +        map.put(3, true);
 +
 +        execute("INSERT INTO %s (key, lst, st, mp) VALUES (1, ?, ?, ?)", list, set, map);
 +
 +        assertRows(execute("SELECT lst, st, mp FROM %s WHERE key = 1"),
 +                   row(list, set, map));
 +
 +        assertRows(execute("SELECT " + fName1 + "(lst), " + fName2 + "(st), " + fName3 + "(mp) FROM %s WHERE key = 1"),
 +                   row(list, set, map));
 +
 +        for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
 +            assertRowsNet(version,
 +                          executeNet(version, "SELECT " + fName1 + "(lst), " + fName2 + "(st), " + fName3 + "(mp) FROM %s WHERE key = 1"),
 +                          row(list, set, map));
 +    }
 +
 +    @Test
 +    public void testJavascriptTupleType() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (key int primary key, tup frozen<tuple<double, text, int, boolean>>)");
 +
 +        String fName = createFunction(KEYSPACE_PER_TEST, "tuple<double, text, int, boolean>",
 +                "CREATE FUNCTION %s( tup tuple<double, text, int, boolean> ) " +
 +                "RETURNS NULL ON NULL INPUT " +
 +                "RETURNS tuple<double, text, int, boolean> " +
 +                "LANGUAGE javascript\n" +
 +                "AS $$tup;$$;");
 +
 +        Object t = tuple(1d, "foo", 2, true);
 +
 +        execute("INSERT INTO %s (key, tup) VALUES (1, ?)", t);
 +
 +        assertRows(execute("SELECT tup FROM %s WHERE key = 1"),
 +                   row(t));
 +
 +        assertRows(execute("SELECT " + fName + "(tup) FROM %s WHERE key = 1"),
 +                   row(t));
 +    }
 +
 +    @Test
 +    public void testJavascriptTupleTypeCollection() throws Throwable
 +    {
 +        String tupleTypeDef = "tuple<double, list<double>, set<text>, map<int, boolean>>";
 +        createTable("CREATE TABLE %s (key int primary key, tup frozen<" + tupleTypeDef + ">)");
 +
 +        String fTup1 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
 +                "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
 +                "RETURNS NULL ON NULL INPUT " +
 +                "RETURNS tuple<double, list<double>, set<text>, map<int, boolean>> " +
 +                "LANGUAGE javascript\n" +
 +                "AS $$" +
 +                "       tup;$$;");
 +        String fTup2 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
 +                "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
 +                "RETURNS NULL ON NULL INPUT " +
 +                "RETURNS double " +
 +                "LANGUAGE javascript\n" +
 +                "AS $$" +
 +                "       tup.getDouble(0);$$;");
 +        String fTup3 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
 +                "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
 +                "RETURNS NULL ON NULL INPUT " +
 +                "RETURNS list<double> " +
 +                "LANGUAGE javascript\n" +
 +                "AS $$" +
 +                "       tup.getList(1, java.lang.Class.forName(\"java.lang.Double\"));$$;");
 +        String fTup4 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
 +                "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
 +                "RETURNS NULL ON NULL INPUT " +
 +                "RETURNS set<text> " +
 +                "LANGUAGE javascript\n" +
 +                "AS $$" +
 +                "       tup.getSet(2, java.lang.Class.forName(\"java.lang.String\"));$$;");
 +        String fTup5 = createFunction(KEYSPACE_PER_TEST, tupleTypeDef,
 +                "CREATE FUNCTION %s( tup " + tupleTypeDef + " ) " +
 +                "RETURNS NULL ON NULL INPUT " +
 +                "RETURNS map<int, boolean> " +
 +                "LANGUAGE javascript\n" +
 +                "AS $$" +
 +                "       tup.getMap(3, java.lang.Class.forName(\"java.lang.Integer\"), java.lang.Class.forName(\"java.lang.Boolean\"));$$;");
 +
 +        List<Double> list = Arrays.asList(1d, 2d, 3d);
 +        Set<String> set = new TreeSet<>(Arrays.asList("one", "three", "two"));
 +        Map<Integer, Boolean> map = new TreeMap<>();
 +        map.put(1, true);
 +        map.put(2, false);
 +        map.put(3, true);
 +
 +        Object t = tuple(1d, list, set, map);
 +
 +        execute("INSERT INTO %s (key, tup) VALUES (1, ?)", t);
 +
 +        assertRows(execute("SELECT " + fTup1 + "(tup) FROM %s WHERE key = 1"),
 +                   row(t));
 +        assertRows(execute("SELECT " + fTup2 + "(tup) FROM %s WHERE key = 1"),
 +                   row(1d));
 +        assertRows(execute("SELECT " + fTup3 + "(tup) FROM %s WHERE key = 1"),
 +                   row(list));
 +        assertRows(execute("SELECT " + fTup4 + "(tup) FROM %s WHERE key = 1"),
 +                   row(set));
 +        assertRows(execute("SELECT " + fTup5 + "(tup) FROM %s WHERE key = 1"),
 +                   row(map));
 +
 +        // same test - but via native protocol
 +        TupleType tType = TupleType.of(DataType.cdouble(),
 +                                       DataType.list(DataType.cdouble()),
 +                                       DataType.set(DataType.text()),
 +                                       DataType.map(DataType.cint(), DataType.cboolean()));
 +        TupleValue tup = tType.newValue(1d, list, set, map);
 +        for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
 +        {
 +            assertRowsNet(version,
 +                          executeNet(version, "SELECT " + fTup1 + "(tup) FROM %s WHERE key = 1"),
 +                          row(tup));
 +            assertRowsNet(version,
 +                          executeNet(version, "SELECT " + fTup2 + "(tup) FROM %s WHERE key = 1"),
 

<TRUNCATED>

[5/8] cassandra git commit: Merge branch 'cassandra-2.1' into cassandra-2.2

Posted by sn...@apache.org.
Merge branch 'cassandra-2.1' into cassandra-2.2


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

Branch: refs/heads/cassandra-3.0
Commit: b3e6a433eaf8486c8bd5306c48ffa3cb826234bb
Parents: db97083 4ecbbc0
Author: Robert Stupp <sn...@snazy.de>
Authored: Fri Nov 27 10:44:14 2015 +0100
Committer: Robert Stupp <sn...@snazy.de>
Committed: Fri Nov 27 10:44:14 2015 +0100

----------------------------------------------------------------------
 CHANGES.txt                                     |  1 +
 .../cql3/statements/DropTypeStatement.java      | 10 ++++--
 .../cql3/validation/entities/TypeTest.java      | 10 ++++++
 .../cql3/validation/entities/UFTest.java        | 14 ++++++++
 .../validation/operations/AggregationTest.java  | 14 ++++++++
 .../cql3/validation/operations/DropTest.java    | 37 ++++++++++++++++++++
 6 files changed, 84 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/b3e6a433/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index 8779275,4adcf4f..c2940cc
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,19 -1,5 +1,20 @@@
 -2.1.12
 +2.2.4
 + * CQL.textile syntax incorrectly includes optional keyspace for aggregate SFUNC and FINALFUNC (CASSANDRA-10747)
 + * Fix JSON update with prepared statements (CASSANDRA-10631)
 + * Don't do anticompaction after subrange repair (CASSANDRA-10422)
 + * Fix SimpleDateType type compatibility (CASSANDRA-10027)
 + * (Hadoop) fix splits calculation (CASSANDRA-10640)
 + * (Hadoop) ensure that Cluster instances are always closed (CASSANDRA-10058)
 + * (cqlsh) show partial trace if incomplete after max_trace_wait (CASSANDRA-7645)
 + * Use most up-to-date version of schema for system tables (CASSANDRA-10652)
 + * Deprecate memory_allocator in cassandra.yaml (CASSANDRA-10581,10628)
 + * Expose phi values from failure detector via JMX and tweak debug
 +   and trace logging (CASSANDRA-9526)
 + * Fix RangeNamesQueryPager (CASSANDRA-10509)
 + * Deprecate Pig support (CASSANDRA-10542)
 + * Reduce contention getting instances of CompositeType (CASSANDRA-10433)
 +Merged from 2.1:
+  * Some DROP ... IF EXISTS incorrectly result in exceptions on non-existing KS (CASSANDRA-10658)
   * DeletionTime.compareTo wrong in rare cases (CASSANDRA-10749)
   * Force encoding when computing statement ids (CASSANDRA-10755)
   * Properly reject counters as map keys (CASSANDRA-10760)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b3e6a433/src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b3e6a433/test/unit/org/apache/cassandra/cql3/validation/entities/TypeTest.java
----------------------------------------------------------------------


[8/8] cassandra git commit: Merge branch 'cassandra-2.2' into cassandra-3.0

Posted by sn...@apache.org.
Merge branch 'cassandra-2.2' into cassandra-3.0


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

Branch: refs/heads/cassandra-3.0
Commit: d300a1850b4c9aa8b854f5fbc7921c8f9b2892b0
Parents: e8091d5 b3e6a43
Author: Robert Stupp <sn...@snazy.de>
Authored: Fri Nov 27 10:51:23 2015 +0100
Committer: Robert Stupp <sn...@snazy.de>
Committed: Fri Nov 27 10:55:02 2015 +0100

----------------------------------------------------------------------
 CHANGES.txt                                     |  1 +
 .../cql3/statements/DropAggregateStatement.java | 15 ++++----
 .../cql3/statements/DropFunctionStatement.java  | 27 +++++++++-----
 .../cql3/statements/DropTableStatement.java     |  2 ++
 .../cql3/statements/DropTypeStatement.java      | 10 ++++--
 .../org/apache/cassandra/cql3/ViewTest.java     | 10 ++++++
 .../cql3/validation/entities/TypeTest.java      | 10 ++++++
 .../cql3/validation/entities/UFTest.java        | 14 ++++++++
 .../validation/operations/AggregationTest.java  | 14 ++++++++
 .../cql3/validation/operations/DropTest.java    | 37 ++++++++++++++++++++
 10 files changed, 123 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/d300a185/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index bc183fc,c2940cc..5e6c03c
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -17,7 -5,16 +17,8 @@@ Merged from 2.2
   * Fix SimpleDateType type compatibility (CASSANDRA-10027)
   * (Hadoop) fix splits calculation (CASSANDRA-10640)
   * (Hadoop) ensure that Cluster instances are always closed (CASSANDRA-10058)
 - * (cqlsh) show partial trace if incomplete after max_trace_wait (CASSANDRA-7645)
 - * Use most up-to-date version of schema for system tables (CASSANDRA-10652)
 - * Deprecate memory_allocator in cassandra.yaml (CASSANDRA-10581,10628)
 - * Expose phi values from failure detector via JMX and tweak debug
 -   and trace logging (CASSANDRA-9526)
 - * Fix RangeNamesQueryPager (CASSANDRA-10509)
 - * Deprecate Pig support (CASSANDRA-10542)
 - * Reduce contention getting instances of CompositeType (CASSANDRA-10433)
  Merged from 2.1:
+  * Some DROP ... IF EXISTS incorrectly result in exceptions on non-existing KS (CASSANDRA-10658)
   * DeletionTime.compareTo wrong in rare cases (CASSANDRA-10749)
   * Force encoding when computing statement ids (CASSANDRA-10755)
   * Properly reject counters as map keys (CASSANDRA-10760)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/d300a185/src/java/org/apache/cassandra/cql3/statements/DropAggregateStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/DropAggregateStatement.java
index bef9e74,2d5ea70..2b1432b
--- a/src/java/org/apache/cassandra/cql3/statements/DropAggregateStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropAggregateStatement.java
@@@ -88,14 -94,14 +88,17 @@@ public final class DropAggregateStateme
                                                              "'DESCRIBE AGGREGATE %s' command to find all overloads",
                                                              functionName, functionName, functionName));
  
--        List<AbstractType<?>> argTypes = new ArrayList<>(argRawTypes.size());
--        for (CQL3Type.Raw rawType : argRawTypes)
--            argTypes.add(prepareType("arguments", rawType));
--
--        Function old;
++        Function old = null;
          if (argsPresent)
          {
-             old = Schema.instance.findFunction(functionName, argTypes).orElse(null);
 -            old = Functions.find(functionName, argTypes);
++            if (Schema.instance.getKSMetaData(functionName.keyspace) != null)
++            {
++                List<AbstractType<?>> argTypes = new ArrayList<>(argRawTypes.size());
++                for (CQL3Type.Raw rawType : argRawTypes)
++                    argTypes.add(prepareType("arguments", rawType));
++
++                old = Schema.instance.findFunction(functionName, argTypes).orElse(null);
++            }
              if (old == null || !(old instanceof AggregateFunction))
              {
                  if (ifExists)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/d300a185/src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java
index 3cef2da,edd8a65..6f11f9c
--- a/src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java
@@@ -64,19 -62,19 +64,23 @@@ public final class DropFunctionStatemen
      @Override
      public Prepared prepare() throws InvalidRequestException
      {
--        argTypes = new ArrayList<>(argRawTypes.size());
--        for (CQL3Type.Raw rawType : argRawTypes)
++        if (Schema.instance.getKSMetaData(functionName.keyspace) != null)
          {
--            if (rawType.isFrozen())
--                throw new InvalidRequestException("The function arguments should not be frozen; remove the frozen<> modifier");
++            argTypes = new ArrayList<>(argRawTypes.size());
++            for (CQL3Type.Raw rawType : argRawTypes)
++            {
++                if (rawType.isFrozen())
++                    throw new InvalidRequestException("The function arguments should not be frozen; remove the frozen<> modifier");
  
--            // UDT are not supported non frozen but we do not allow the frozen keyword for argument. So for the moment we
--            // freeze them here
--            if (!rawType.canBeNonFrozen())
--                rawType.freeze();
++                // UDT are not supported non frozen but we do not allow the frozen keyword for argument. So for the moment we
++                // freeze them here
++                if (!rawType.canBeNonFrozen())
++                    rawType.freeze();
  
--            argTypes.add(rawType.prepare(functionName.keyspace).getType());
++                argTypes.add(rawType.prepare(functionName.keyspace).getType());
++            }
          }
++
          return super.prepare();
      }
  
@@@ -161,7 -175,7 +165,12 @@@
          Function old;
          if (argsPresent)
          {
 -            old = Functions.find(functionName, argTypes);
++            if (argTypes == null)
++            {
++                return null;
++            }
++
 +            old = Schema.instance.findFunction(functionName, argTypes).orElse(null);
              if (old == null || !(old instanceof ScalarFunction))
              {
                  return null;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/d300a185/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
index 79c46f5,e690c3e..8e18cad
--- a/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
@@@ -62,34 -58,8 +62,36 @@@ public class DropTableStatement extend
      {
          try
          {
 +            KeyspaceMetadata ksm = Schema.instance.getKSMetaData(keyspace());
++            if (ksm == null)
++                throw new ConfigurationException(String.format("Cannot drop table in unknown keyspace '%s'", keyspace()));
 +            CFMetaData cfm = ksm.getTableOrViewNullable(columnFamily());
 +            if (cfm != null)
 +            {
 +                if (cfm.isView())
 +                    throw new InvalidRequestException("Cannot use DROP TABLE on Materialized View");
 +
 +                boolean rejectDrop = false;
 +                StringBuilder messageBuilder = new StringBuilder();
 +                for (ViewDefinition def : ksm.views)
 +                {
 +                    if (def.baseTableId.equals(cfm.cfId))
 +                    {
 +                        if (rejectDrop)
 +                            messageBuilder.append(',');
 +                        rejectDrop = true;
 +                        messageBuilder.append(def.viewName);
 +                    }
 +                }
 +                if (rejectDrop)
 +                {
 +                    throw new InvalidRequestException(String.format("Cannot drop table when materialized views still depend on it (%s.{%s})",
 +                                                                    keyspace(),
 +                                                                    messageBuilder.toString()));
 +                }
 +            }
              MigrationManager.announceColumnFamilyDrop(keyspace(), columnFamily(), isLocalOnly);
 -            return true;
 +            return new Event.SchemaChange(Event.SchemaChange.Change.DROPPED, Event.SchemaChange.Target.TABLE, keyspace(), columnFamily());
          }
          catch (ConfigurationException e)
          {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/d300a185/src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java
index 58abde9,6993ea3..6db47ca
--- a/src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java
@@@ -54,11 -54,17 +54,16 @@@ public class DropTypeStatement extends 
  
      public void validate(ClientState state) throws RequestValidationException
      {
 -        KSMetaData ksm = Schema.instance.getKSMetaData(name.getKeyspace());
 +        KeyspaceMetadata ksm = Schema.instance.getKSMetaData(name.getKeyspace());
          if (ksm == null)
-             throw new InvalidRequestException(String.format("Cannot drop type in unknown keyspace %s", name.getKeyspace()));
+         {
+             if (ifExists)
+                 return;
+             else
+                 throw new InvalidRequestException(String.format("Cannot drop type in unknown keyspace %s", name.getKeyspace()));
+         }
  
 -        UserType old = ksm.userTypes.getType(name.getUserTypeName());
 -        if (old == null)
 +        if (!ksm.types.get(name.getUserTypeName()).isPresent())
          {
              if (ifExists)
                  return;
@@@ -130,17 -153,18 +135,18 @@@
          return name.getKeyspace();
      }
  
 -    public boolean announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
 +    public Event.SchemaChange announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
      {
 -        KSMetaData ksm = Schema.instance.getKSMetaData(name.getKeyspace());
 +        KeyspaceMetadata ksm = Schema.instance.getKSMetaData(name.getKeyspace());
-         assert ksm != null;
+         if (ksm == null)
 -            return false; // do not assert (otherwise IF EXISTS case fails)
++            return null; // do not assert (otherwise IF EXISTS case fails)
  
 -        UserType toDrop = ksm.userTypes.getType(name.getUserTypeName());
 +        UserType toDrop = ksm.types.getNullable(name.getUserTypeName());
          // Can be null with ifExists
          if (toDrop == null)
 -            return false;
 +            return null;
  
          MigrationManager.announceTypeDrop(toDrop, isLocalOnly);
 -        return true;
 +        return new Event.SchemaChange(Event.SchemaChange.Change.DROPPED, Event.SchemaChange.Target.TYPE, keyspace(), name.getStringTypeName());
      }
  }


[6/8] cassandra git commit: Merge branch 'cassandra-2.2' into cassandra-3.0

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/d300a185/test/unit/org/apache/cassandra/cql3/validation/operations/AggregationTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/operations/AggregationTest.java
index a1fb68b,e661b4f..2713895
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/AggregationTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/AggregationTest.java
@@@ -50,6 -48,20 +50,20 @@@ import static org.junit.Assert.assertTr
  public class AggregationTest extends CQLTester
  {
      @Test
+     public void testNonExistingOnes() throws Throwable
+     {
 -        assertInvalidMessage("Cannot drop non existing aggregate", "DROP AGGREGATE " + KEYSPACE + ".aggr_does_not_exist");
 -        assertInvalidMessage("Cannot drop non existing aggregate", "DROP AGGREGATE " + KEYSPACE + ".aggr_does_not_exist(int,text)");
 -        assertInvalidMessage("Cannot drop non existing aggregate", "DROP AGGREGATE keyspace_does_not_exist.aggr_does_not_exist");
 -        assertInvalidMessage("Cannot drop non existing aggregate", "DROP AGGREGATE keyspace_does_not_exist.aggr_does_not_exist(int,text)");
++        assertInvalidThrowMessage("Cannot drop non existing aggregate", InvalidRequestException.class, "DROP AGGREGATE " + KEYSPACE + ".aggr_does_not_exist");
++        assertInvalidThrowMessage("Cannot drop non existing aggregate", InvalidRequestException.class, "DROP AGGREGATE " + KEYSPACE + ".aggr_does_not_exist(int,text)");
++        assertInvalidThrowMessage("Cannot drop non existing aggregate", InvalidRequestException.class, "DROP AGGREGATE keyspace_does_not_exist.aggr_does_not_exist");
++        assertInvalidThrowMessage("Cannot drop non existing aggregate", InvalidRequestException.class, "DROP AGGREGATE keyspace_does_not_exist.aggr_does_not_exist(int,text)");
+ 
+         execute("DROP AGGREGATE IF EXISTS " + KEYSPACE + ".aggr_does_not_exist");
+         execute("DROP AGGREGATE IF EXISTS " + KEYSPACE + ".aggr_does_not_exist(int,text)");
+         execute("DROP AGGREGATE IF EXISTS keyspace_does_not_exist.aggr_does_not_exist");
+         execute("DROP AGGREGATE IF EXISTS keyspace_does_not_exist.aggr_does_not_exist(int,text)");
+     }
+ 
+     @Test
      public void testFunctions() throws Throwable
      {
          createTable("CREATE TABLE %s (a int, b int, c double, d decimal, e smallint, f tinyint, primary key (a, b))");

http://git-wip-us.apache.org/repos/asf/cassandra/blob/d300a185/test/unit/org/apache/cassandra/cql3/validation/operations/DropTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/operations/DropTest.java
index 0000000,2c68390..e5c7089
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/DropTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/DropTest.java
@@@ -1,0 -1,37 +1,37 @@@
+ /*
+  * 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.operations;
+ 
+ import org.junit.Test;
+ 
+ import org.apache.cassandra.cql3.CQLTester;
+ 
+ public class DropTest extends CQLTester
+ {
+     @Test
+     public void testNonExistingOnes() throws Throwable
+     {
+         assertInvalidMessage("Cannot drop non existing table", "DROP TABLE " + KEYSPACE + ".table_does_not_exist");
 -        assertInvalidMessage("Cannot drop non existing table", "DROP TABLE keyspace_does_not_exist.table_does_not_exist");
++        assertInvalidMessage("Cannot drop table in unknown keyspace", "DROP TABLE keyspace_does_not_exist.table_does_not_exist");
+ 
+         execute("DROP TABLE IF EXISTS " + KEYSPACE + ".table_does_not_exist");
+         execute("DROP TABLE IF EXISTS keyspace_does_not_exist.table_does_not_exist");
+     }
+ 
+ }


[7/8] cassandra git commit: Merge branch 'cassandra-2.2' into cassandra-3.0

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/d300a185/test/unit/org/apache/cassandra/cql3/ViewTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/ViewTest.java
index ff1ba2f,0000000..74c6374
mode 100644,000000..100644
--- a/test/unit/org/apache/cassandra/cql3/ViewTest.java
+++ b/test/unit/org/apache/cassandra/cql3/ViewTest.java
@@@ -1,1612 -1,0 +1,1622 @@@
 +/*
 + * 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 java.util.concurrent.TimeUnit;
 +
 +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.ColumnFamilyStore;
 +import org.apache.cassandra.db.Keyspace;
 +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.apache.cassandra.utils.FBUtilities;
 +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;
 +
 +public class ViewTest 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 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 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 testPartitionTombstone() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (k1 int, c1 int , val int, PRIMARY KEY (k1))");
 +
 +        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(1, execute("select * from %s").size());
 +        Assert.assertEquals(1, 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 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");
 +            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)
 +        {
 +        }
 +
 +        // 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 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 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)");
 +            Assert.fail("MV on static should fail");
 +        }
 +        catch (InvalidQueryException e)
 +        {
 +        }
 +
 +        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)");
 +
 +        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 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)");
 +            Assert.fail("MV on counter should fail");
 +        }
 +        catch (InvalidQueryException e)
 +        {
 +        }
 +    }
 +
 +    @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);
 +        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())
 +                    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("mv3_" + 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 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 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 ignored
 +                "APPLY BATCH",
 +                0, 0, 0, 0,
 +                1, 0, 1);
 +        assertRows(execute("SELECT a, b, c from mv WHERE b = ?", 0), row(0, 0, 0));
 +        assertEmpty(execute("SELECT a, b, c from mv WHERE b = ?", 1));
 +
 +        ColumnFamilyStore cfs = Keyspace.open(keyspace()).getColumnFamilyStore("mv");
 +        cfs.forceBlockingFlush();
 +        Assert.assertEquals(1, cfs.getLiveSSTables().size());
 +    }
 +
 +    @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 testDecimalUpdate() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (" +
 +                    "k int, " +
 +                    "decimalval decimal, " +
 +                    "asciival ascii, " +
 +                    "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 decimalval IS NOT NULL PRIMARY KEY (decimalval, k)");
 +
 +        updateView("INSERT INTO %s (k, asciival) VALUES (?, ?)", 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 WHERE decimalval = fromJson(?)", "123123.123123"));
 +        assertRows(execute("SELECT k, asciival from mv 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, asciival FROM %s WHERE k = ?", 0), row(0, new BigDecimal("123123.123123"), "ascii text"));
 +        assertRows(execute("SELECT k, asciival from mv WHERE decimalval = fromJson(?)", "\"123123.123123\""), row(0, "ascii text"));
 +    }
 +
 +    @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 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 5", 1, 1, 1, 1);
 +
 +        Thread.sleep(TimeUnit.SECONDS.toMillis(3));
 +        updateView("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 1, 1, 2);
 +
 +        Thread.sleep(TimeUnit.SECONDS.toMillis(3));
 +        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 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 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 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 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");
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/d300a185/test/unit/org/apache/cassandra/cql3/validation/entities/TypeTest.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/d300a185/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
index ce62e6c,0d11a82..467a082
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
@@@ -58,7 -61,27 +58,21 @@@ import org.apache.cassandra.utils.UUIDG
  
  public class UFTest extends CQLTester
  {
 -    @BeforeClass
 -    public static void setUp()
 -    {
 -        DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance);
 -    }
 -
      @Test
+     public void testNonExistingOnes() throws Throwable
+     {
 -        assertInvalidMessage("Cannot drop non existing function", "DROP FUNCTION " + KEYSPACE + ".func_does_not_exist");
 -        assertInvalidMessage("Cannot drop non existing function", "DROP FUNCTION " + KEYSPACE + ".func_does_not_exist(int,text)");
 -        assertInvalidMessage("Cannot drop non existing function", "DROP FUNCTION keyspace_does_not_exist.func_does_not_exist");
 -        assertInvalidMessage("Cannot drop non existing function", "DROP FUNCTION keyspace_does_not_exist.func_does_not_exist(int,text)");
++        assertInvalidThrowMessage("Cannot drop non existing function", InvalidRequestException.class, "DROP FUNCTION " + KEYSPACE + ".func_does_not_exist");
++        assertInvalidThrowMessage("Cannot drop non existing function", InvalidRequestException.class, "DROP FUNCTION " + KEYSPACE + ".func_does_not_exist(int,text)");
++        assertInvalidThrowMessage("Cannot drop non existing function", InvalidRequestException.class, "DROP FUNCTION keyspace_does_not_exist.func_does_not_exist");
++        assertInvalidThrowMessage("Cannot drop non existing function", InvalidRequestException.class, "DROP FUNCTION keyspace_does_not_exist.func_does_not_exist(int,text)");
+ 
+         execute("DROP FUNCTION IF EXISTS " + KEYSPACE + ".func_does_not_exist");
+         execute("DROP FUNCTION IF EXISTS " + KEYSPACE + ".func_does_not_exist(int,text)");
+         execute("DROP FUNCTION IF EXISTS keyspace_does_not_exist.func_does_not_exist");
+         execute("DROP FUNCTION IF EXISTS keyspace_does_not_exist.func_does_not_exist(int,text)");
+     }
+ 
+     @Test
      public void testSchemaChange() throws Throwable
      {
          String f = createFunction(KEYSPACE,


[3/8] cassandra git commit: Merge branch 'cassandra-2.1' into cassandra-2.2

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/b3e6a433/test/unit/org/apache/cassandra/cql3/validation/operations/AggregationTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/operations/AggregationTest.java
index 1649654,0000000..e661b4f
mode 100644,000000..100644
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/AggregationTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/AggregationTest.java
@@@ -1,1631 -1,0 +1,1645 @@@
 +/*
 + * 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.operations;
 +
 +import java.math.BigDecimal;
 +import java.text.SimpleDateFormat;
 +import java.util.Calendar;
 +import java.util.Date;
 +import java.util.TimeZone;
 +
 +import org.apache.commons.lang3.time.DateUtils;
 +
 +import org.junit.Test;
 +
 +import org.apache.cassandra.cql3.CQLTester;
 +import org.apache.cassandra.cql3.QueryProcessor;
 +import org.apache.cassandra.cql3.UntypedResultSet;
 +import org.apache.cassandra.cql3.UntypedResultSet.Row;
 +import org.apache.cassandra.cql3.functions.Functions;
 +import org.apache.cassandra.cql3.functions.UDAggregate;
 +import org.apache.cassandra.db.SystemKeyspace;
 +import org.apache.cassandra.exceptions.FunctionExecutionException;
 +import org.apache.cassandra.exceptions.InvalidRequestException;
 +import org.apache.cassandra.service.ClientState;
 +import org.apache.cassandra.transport.Event;
 +import org.apache.cassandra.transport.messages.ResultMessage;
 +
 +import static org.junit.Assert.assertEquals;
 +import static org.junit.Assert.assertNotNull;
 +import static org.junit.Assert.assertNull;
 +import static org.junit.Assert.assertTrue;
 +
 +public class AggregationTest extends CQLTester
 +{
 +    @Test
++    public void testNonExistingOnes() throws Throwable
++    {
++        assertInvalidMessage("Cannot drop non existing aggregate", "DROP AGGREGATE " + KEYSPACE + ".aggr_does_not_exist");
++        assertInvalidMessage("Cannot drop non existing aggregate", "DROP AGGREGATE " + KEYSPACE + ".aggr_does_not_exist(int,text)");
++        assertInvalidMessage("Cannot drop non existing aggregate", "DROP AGGREGATE keyspace_does_not_exist.aggr_does_not_exist");
++        assertInvalidMessage("Cannot drop non existing aggregate", "DROP AGGREGATE keyspace_does_not_exist.aggr_does_not_exist(int,text)");
++
++        execute("DROP AGGREGATE IF EXISTS " + KEYSPACE + ".aggr_does_not_exist");
++        execute("DROP AGGREGATE IF EXISTS " + KEYSPACE + ".aggr_does_not_exist(int,text)");
++        execute("DROP AGGREGATE IF EXISTS keyspace_does_not_exist.aggr_does_not_exist");
++        execute("DROP AGGREGATE IF EXISTS keyspace_does_not_exist.aggr_does_not_exist(int,text)");
++    }
++
++    @Test
 +    public void testFunctions() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int, b int, c double, d decimal, e smallint, f tinyint, primary key (a, b))");
 +
 +        // Test with empty table
 +        assertColumnNames(execute("SELECT COUNT(*) FROM %s"), "count");
 +        assertRows(execute("SELECT COUNT(*) FROM %s"), row(0L));
 +        assertColumnNames(execute("SELECT max(b), min(b), sum(b), avg(b)," +
 +                                  "max(c), sum(c), avg(c)," +
 +                                  "sum(d), avg(d)," +
 +                                  "max(e), min(e), sum(e), avg(e)," +
 +                                  "max(f), min(f), sum(f), avg(f) FROM %s"),
 +                          "system.max(b)", "system.min(b)", "system.sum(b)", "system.avg(b)",
 +                          "system.max(c)", "system.sum(c)", "system.avg(c)",
 +                          "system.sum(d)", "system.avg(d)",
 +                          "system.max(e)", "system.min(e)", "system.sum(e)", "system.avg(e)",
 +                          "system.max(f)", "system.min(f)", "system.sum(f)", "system.avg(f)");
 +        assertRows(execute("SELECT max(b), min(b), sum(b), avg(b)," +
 +                           "max(c), sum(c), avg(c)," +
 +                           "sum(d), avg(d)," +
 +                           "max(e), min(e), sum(e), avg(e)," +
 +                           "max(f), min(f), sum(f), avg(f) FROM %s"),
 +                   row(null, null, 0, 0, null, 0.0, 0.0, new BigDecimal("0"), new BigDecimal("0"),
 +                       null, null, (short)0, (short)0,
 +                       null, null, (byte)0, (byte)0));
 +
 +        execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (1, 1, 11.5, 11.5, 1, 1)");
 +        execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (1, 2, 9.5, 1.5, 2, 2)");
 +        execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (1, 3, 9.0, 2.0, 3, 3)");
 +
 +        assertRows(execute("SELECT max(b), min(b), sum(b), avg(b) , max(c), sum(c), avg(c), sum(d), avg(d)," +
 +                           "max(e), min(e), sum(e), avg(e)," +
 +                           "max(f), min(f), sum(f), avg(f)" +
 +                           " FROM %s"),
 +                   row(3, 1, 6, 2, 11.5, 30.0, 10.0, new BigDecimal("15.0"), new BigDecimal("5.0"),
 +                       (short)3, (short)1, (short)6, (short)2,
 +                       (byte)3, (byte)1, (byte)6, (byte)2));
 +
 +        execute("INSERT INTO %s (a, b, d) VALUES (1, 5, 1.0)");
 +        assertRows(execute("SELECT COUNT(*) FROM %s"), row(4L));
 +        assertRows(execute("SELECT COUNT(1) FROM %s"), row(4L));
 +        assertRows(execute("SELECT COUNT(b), count(c), count(e), count(f) FROM %s"), row(4L, 3L, 3L, 3L));
 +        // Makes sure that LIMIT does not affect the result of aggregates
 +        assertRows(execute("SELECT COUNT(b), count(c), count(e), count(f) FROM %s LIMIT 2"), row(4L, 3L, 3L, 3L));
 +        assertRows(execute("SELECT COUNT(b), count(c), count(e), count(f) FROM %s WHERE a = 1 LIMIT 2"),
 +                   row(4L, 3L, 3L, 3L));
 +    }
 +
 +    @Test
 +    public void testCountStarFunction() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int, b int, c double, primary key (a, b))");
 +
 +        // Test with empty table
 +        assertColumnNames(execute("SELECT COUNT(*) FROM %s"), "count");
 +        assertRows(execute("SELECT COUNT(*) FROM %s"), row(0L));
 +        assertColumnNames(execute("SELECT COUNT(1) FROM %s"), "count");
 +        assertRows(execute("SELECT COUNT(1) FROM %s"), row(0L));
 +        assertColumnNames(execute("SELECT COUNT(*), COUNT(*) FROM %s"), "count", "count");
 +        assertRows(execute("SELECT COUNT(*), COUNT(*) FROM %s"), row(0L, 0L));
 +
 +        // Test with alias
 +        assertColumnNames(execute("SELECT COUNT(*) as myCount FROM %s"), "mycount");
 +        assertRows(execute("SELECT COUNT(*) as myCount FROM %s"), row(0L));
 +        assertColumnNames(execute("SELECT COUNT(1) as myCount FROM %s"), "mycount");
 +        assertRows(execute("SELECT COUNT(1) as myCount FROM %s"), row(0L));
 +
 +        // Test invalid call
 +        assertInvalidSyntaxMessage("Only COUNT(1) is supported, got COUNT(2)", "SELECT COUNT(2) FROM %s");
 +
 +        // Test with other aggregates
 +        assertColumnNames(execute("SELECT COUNT(*), max(b), b FROM %s"), "count", "system.max(b)", "b");
 +        assertRows(execute("SELECT COUNT(*), max(b), b  FROM %s"), row(0L, null, null));
 +        assertColumnNames(execute("SELECT COUNT(1), max(b), b FROM %s"), "count", "system.max(b)", "b");
 +        assertRows(execute("SELECT COUNT(1), max(b), b  FROM %s"), row(0L, null, null));
 +
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 1, 11.5)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 2, 9.5)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 3, 9.0)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 5, 1.0)");
 +
 +        assertRows(execute("SELECT COUNT(*) FROM %s"), row(4L));
 +        assertRows(execute("SELECT COUNT(1) FROM %s"), row(4L));
 +        assertRows(execute("SELECT max(b), b, COUNT(*) FROM %s"), row(5, 1, 4L));
 +        assertRows(execute("SELECT max(b), COUNT(1), b FROM %s"), row(5, 4L, 1));
 +        // Makes sure that LIMIT does not affect the result of aggregates
 +        assertRows(execute("SELECT max(b), COUNT(1), b FROM %s LIMIT 2"), row(5, 4L, 1));
 +        assertRows(execute("SELECT max(b), COUNT(1), b FROM %s WHERE a = 1 LIMIT 2"), row(5, 4L, 1));
 +    }
 +
 +    @Test
 +    public void testAggregateWithColumns() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int, b int, c int, primary key (a, b))");
 +
 +        // Test with empty table
 +        assertColumnNames(execute("SELECT count(b), max(b) as max, b, c as first FROM %s"),
 +                          "system.count(b)", "max", "b", "first");
 +        assertRows(execute("SELECT count(b), max(b) as max, b, c as first FROM %s"),
 +                           row(0L, null, null, null));
 +
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 2, null)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (2, 4, 6)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (4, 8, 12)");
 +
 +        assertRows(execute("SELECT count(b), max(b) as max, b, c as first FROM %s"),
 +                   row(3L, 8, 2, null));
 +    }
 +
 +    @Test
 +    public void testAggregateWithUdtFields() throws Throwable
 +    {
 +        String myType = createType("CREATE TYPE %s (x int)");
 +        createTable("CREATE TABLE %s (a int primary key, b frozen<" + myType + ">, c frozen<" + myType + ">)");
 +
 +        // Test with empty table
 +        assertColumnNames(execute("SELECT count(b.x), max(b.x) as max, b.x, c.x as first FROM %s"),
 +                          "system.count(b.x)", "max", "b.x", "first");
 +        assertRows(execute("SELECT count(b.x), max(b.x) as max, b.x, c.x as first FROM %s"),
 +                           row(0L, null, null, null));
 +
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, {x:2}, null)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (2, {x:4}, {x:6})");
 +        execute("INSERT INTO %s (a, b, c) VALUES (4, {x:8}, {x:12})");
 +
 +        assertRows(execute("SELECT count(b.x), max(b.x) as max, b.x, c.x as first FROM %s"),
 +                   row(3L, 8, 2, null));
 +
 +        assertInvalidMessage("Invalid field selection: max(b) of type blob is not a user type",
 +                             "SELECT max(b).x as max FROM %s");
 +    }
 +
 +    @Test
 +    public void testAggregateWithFunctions() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int, b double, c double, primary key(a, b))");
 +
 +        String copySign = createFunction(KEYSPACE,
 +                                         "double, double",
 +                                         "CREATE OR REPLACE FUNCTION %s(magnitude double, sign double) " +
 +                                         "RETURNS NULL ON NULL INPUT " +
 +                                         "RETURNS double " +
 +                                         "LANGUAGE JAVA " +
 +                                         "AS 'return Double.valueOf(Math.copySign(magnitude, sign));';");
 +
 +        // Test with empty table
 +        assertColumnNames(execute("SELECT count(b), max(b) as max, " + copySign + "(b, c), " + copySign + "(c, b) as first FROM %s"),
 +                          "system.count(b)", "max", copySign + "(b, c)", "first");
 +        assertRows(execute("SELECT count(b), max(b) as max, " + copySign + "(b, c), " + copySign + "(c, b) as first FROM %s"),
 +                           row(0L, null, null, null));
 +
 +        execute("INSERT INTO %s (a, b, c) VALUES (0, -1.2, 2.1)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (0, 1.3, -3.4)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (0, 1.4, 1.2)");
 +
 +        assertRows(execute("SELECT count(b), max(b) as max, " + copySign + "(b, c), " + copySign + "(c, b) as first FROM %s"),
 +                   row(3L, 1.4, 1.2, -2.1));
 +
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, -1.2, null)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 1.3, -3.4)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 1.4, 1.2)");
 +        assertRows(execute("SELECT count(b), max(b) as max, " + copySign + "(b, c), " + copySign + "(c, b) as first FROM %s WHERE a = 1"),
 +                   row(3L, 1.4, null, null));
 +    }
 +
 +    @Test
 +    public void testAggregateWithWriteTimeOrTTL() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int primary key, b int, c int)");
 +
 +        // Test with empty table
 +        assertColumnNames(execute("SELECT count(writetime(b)), min(ttl(b)) as min, writetime(b), ttl(c) as first FROM %s"),
 +                          "system.count(writetime(b))", "min", "writetime(b)", "first");
 +        assertRows(execute("SELECT count(writetime(b)), min(ttl(b)) as min, writetime(b), ttl(c) as first FROM %s"),
 +                           row(0L, null, null, null));
 +
 +        long today = System.currentTimeMillis() * 1000;
 +        long yesterday = today - (DateUtils.MILLIS_PER_DAY * 1000);
 +
 +        final int secondsPerMinute = 60;
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 2, null) USING TTL " + (20 * secondsPerMinute));
 +        execute("INSERT INTO %s (a, b, c) VALUES (2, 4, 6) USING TTL " + (10 * secondsPerMinute));
 +        execute("INSERT INTO %s (a, b, c) VALUES (4, 8, 12) USING TIMESTAMP " + yesterday );
 +
 +        assertRows(execute("SELECT count(writetime(b)), count(ttl(b)) FROM %s"),
 +                   row(3L, 2L));
 +
 +        UntypedResultSet resultSet = execute("SELECT min(ttl(b)), ttl(b) FROM %s");
 +        assertEquals(1, resultSet.size());
 +        Row row = resultSet.one();
 +        assertTrue(row.getInt("ttl(b)") > (10 * secondsPerMinute));
 +        assertTrue(row.getInt("system.min(ttl(b))") <= (10 * secondsPerMinute));
 +
 +        resultSet = execute("SELECT min(writetime(b)), writetime(b) FROM %s");
 +        assertEquals(1, resultSet.size());
 +        row = resultSet.one();
 +
 +        assertTrue(row.getLong("writetime(b)") >= today);
 +        assertTrue(row.getLong("system.min(writetime(b))") == yesterday);
 +    }
 +
 +    @Test
 +    public void testFunctionsWithCompactStorage() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int , b int, c double, primary key(a, b) ) WITH COMPACT STORAGE");
 +
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 1, 11.5)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 2, 9.5)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 3, 9.0)");
 +
 +        assertRows(execute("SELECT max(b), min(b), sum(b), avg(b) , max(c), sum(c), avg(c) FROM %s"),
 +                   row(3, 1, 6, 2, 11.5, 30.0, 10.0));
 +
 +        assertRows(execute("SELECT COUNT(*) FROM %s"), row(3L));
 +        assertRows(execute("SELECT COUNT(1) FROM %s"), row(3L));
 +        assertRows(execute("SELECT COUNT(*) FROM %s WHERE a = 1 AND b > 1"), row(2L));
 +        assertRows(execute("SELECT COUNT(1) FROM %s WHERE a = 1 AND b > 1"), row(2L));
 +        assertRows(execute("SELECT max(b), min(b), sum(b), avg(b) , max(c), sum(c), avg(c) FROM %s WHERE a = 1 AND b > 1"),
 +                   row(3, 2, 5, 2, 9.5, 18.5, 9.25));
 +    }
 +
 +    @Test
 +    public void testInvalidCalls() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int, b int, c int, primary key (a, b))");
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 1, 10)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 2, 9)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 3, 8)");
 +
 +        assertInvalidSyntax("SELECT max(b), max(c) FROM %s WHERE max(a) = 1");
 +        assertInvalidMessage("aggregate functions cannot be used as arguments of aggregate functions", "SELECT max(sum(c)) FROM %s");
 +        assertInvalidSyntax("SELECT COUNT(2) FROM %s");
 +    }
 +
 +    @Test
 +    public void testReversedType() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int, b int, c int, primary key (a, b)) WITH CLUSTERING ORDER BY (b DESC)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 1, 10)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 2, 9)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 3, 8)");
 +        execute("INSERT INTO %s (a, b, c) VALUES (1, 4, 7)");
 +
 +        assertRows(execute("SELECT max(c), min(c), avg(c) FROM %s WHERE a = 1 AND b > 1"), row(9, 7, 8));
 +    }
 +
 +    @Test
 +    public void testNestedFunctions() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int primary key, b timeuuid, c double, d double)");
 +
 +        String copySign = createFunction(KEYSPACE,
 +                                         "double, double",
 +                                         "CREATE OR REPLACE FUNCTION %s(magnitude double, sign double) " +
 +                                         "RETURNS NULL ON NULL INPUT " +
 +                                         "RETURNS double " +
 +                                         "LANGUAGE JAVA " +
 +                                         "AS 'return Double.valueOf(Math.copySign(magnitude, sign));';");
 +
 +        assertColumnNames(execute("SELECT max(a), max(toUnixTimestamp(b)) FROM %s"), "system.max(a)", "system.max(system.tounixtimestamp(b))");
 +        assertRows(execute("SELECT max(a), max(toUnixTimestamp(b)) FROM %s"), row(null, null));
 +        assertColumnNames(execute("SELECT max(a), toUnixTimestamp(max(b)) FROM %s"), "system.max(a)", "system.tounixtimestamp(system.max(b))");
 +        assertRows(execute("SELECT max(a), toUnixTimestamp(max(b)) FROM %s"), row(null, null));
 +
 +        assertColumnNames(execute("SELECT max(" + copySign + "(c, d)) FROM %s"), "system.max(" + copySign + "(c, d))");
 +        assertRows(execute("SELECT max(" + copySign + "(c, d)) FROM %s"), row((Object) null));
 +
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (1, maxTimeuuid('2011-02-03 04:05:00+0000'), -1.2, 2.1)");
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (2, maxTimeuuid('2011-02-03 04:06:00+0000'), 1.3, -3.4)");
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (3, maxTimeuuid('2011-02-03 04:10:00+0000'), 1.4, 1.2)");
 +
 +        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
 +        format.setTimeZone(TimeZone.getTimeZone("GMT"));
 +        Date date = format.parse("2011-02-03 04:10:00");
 +        date = DateUtils.truncate(date, Calendar.MILLISECOND);
 +
 +        assertRows(execute("SELECT max(a), max(toUnixTimestamp(b)) FROM %s"), row(3, date.getTime()));
 +        assertRows(execute("SELECT max(a), toUnixTimestamp(max(b)) FROM %s"), row(3, date.getTime()));
 +
 +        assertRows(execute("SELECT " + copySign + "(max(c), min(c)) FROM %s"), row(-1.4));
 +        assertRows(execute("SELECT " + copySign + "(c, d) FROM %s"), row(1.2), row(-1.3), row(1.4));
 +        assertRows(execute("SELECT max(" + copySign + "(c, d)) FROM %s"), row(1.4));
 +        assertRows(execute("SELECT " + copySign + "(c, max(c)) FROM %s"), row(1.2));
 +        assertRows(execute("SELECT " + copySign + "(max(c), c) FROM %s"), row(-1.4));;
 +    }
 +
 +    @Test
 +    public void testSchemaChange() throws Throwable
 +    {
 +        String f = createFunction(KEYSPACE,
 +                                  "double, double",
 +                                  "CREATE OR REPLACE FUNCTION %s(state double, val double) " +
 +                                  "RETURNS NULL ON NULL INPUT " +
 +                                  "RETURNS double " +
 +                                  "LANGUAGE javascript " +
 +                                  "AS '\"string\";';");
 +
 +        createFunctionOverload(f,
 +                               "double, double",
 +                               "CREATE OR REPLACE FUNCTION %s(state int, val int) " +
 +                               "RETURNS NULL ON NULL INPUT " +
 +                               "RETURNS int " +
 +                               "LANGUAGE javascript " +
 +                               "AS '\"string\";';");
 +
 +        String a = createAggregate(KEYSPACE,
 +                                   "double",
 +                                   "CREATE OR REPLACE AGGREGATE %s(double) " +
 +                                   "SFUNC " + shortFunctionName(f) + " " +
 +                                   "STYPE double " +
 +                                   "INITCOND 0");
 +
 +        assertLastSchemaChange(Event.SchemaChange.Change.CREATED, Event.SchemaChange.Target.AGGREGATE,
 +                               KEYSPACE, parseFunctionName(a).name,
 +                               "double");
 +
 +        schemaChange("CREATE OR REPLACE AGGREGATE " + a + "(double) " +
 +                     "SFUNC " + shortFunctionName(f) + " " +
 +                     "STYPE double " +
 +                     "INITCOND 0");
 +
 +        assertLastSchemaChange(Event.SchemaChange.Change.UPDATED, Event.SchemaChange.Target.AGGREGATE,
 +                               KEYSPACE, parseFunctionName(a).name,
 +                               "double");
 +
 +        createAggregateOverload(a,
 +                                "int",
 +                                "CREATE OR REPLACE AGGREGATE %s(int) " +
 +                                "SFUNC " + shortFunctionName(f) + " " +
 +                                "STYPE int " +
 +                                "INITCOND 0");
 +
 +        assertLastSchemaChange(Event.SchemaChange.Change.CREATED, Event.SchemaChange.Target.AGGREGATE,
 +                               KEYSPACE, parseFunctionName(a).name,
 +                               "int");
 +
 +        schemaChange("DROP AGGREGATE " + a + "(double)");
 +
 +        assertLastSchemaChange(Event.SchemaChange.Change.DROPPED, Event.SchemaChange.Target.AGGREGATE,
 +                               KEYSPACE, parseFunctionName(a).name,
 +                               "double");
 +    }
 +
 +    @Test
 +    public void testDropStatements() throws Throwable
 +    {
 +        String f = createFunction(KEYSPACE,
 +                                  "double, double",
 +                                  "CREATE OR REPLACE FUNCTION %s(state double, val double) " +
 +                                  "RETURNS NULL ON NULL INPUT " +
 +                                  "RETURNS double " +
 +                                  "LANGUAGE javascript " +
 +                                  "AS '\"string\";';");
 +
 +        createFunctionOverload(f,
 +                               "double, double",
 +                               "CREATE OR REPLACE FUNCTION %s(state int, val int) " +
 +                               "RETURNS NULL ON NULL INPUT " +
 +                               "RETURNS int " +
 +                               "LANGUAGE javascript " +
 +                               "AS '\"string\";';");
 +
 +        // DROP AGGREGATE must not succeed against a scalar
 +        assertInvalidMessage("matches multiple function definitions", "DROP AGGREGATE " + f);
 +        assertInvalidMessage("non existing", "DROP AGGREGATE " + f + "(double, double)");
 +
 +        String a = createAggregate(KEYSPACE,
 +                                   "double",
 +                                   "CREATE OR REPLACE AGGREGATE %s(double) " +
 +                                   "SFUNC " + shortFunctionName(f) + " " +
 +                                   "STYPE double " +
 +                                   "INITCOND 0");
 +        createAggregateOverload(a,
 +                                "int",
 +                                "CREATE OR REPLACE AGGREGATE %s(int) " +
 +                                "SFUNC " + shortFunctionName(f) + " " +
 +                                "STYPE int " +
 +                                "INITCOND 0");
 +
 +        // DROP FUNCTION must not succeed against an aggregate
 +        assertInvalidMessage("matches multiple function definitions", "DROP FUNCTION " + a);
 +        assertInvalidMessage("non existing function", "DROP FUNCTION " + a + "(double)");
 +
 +        // ambigious
 +        assertInvalidMessage("matches multiple function definitions", "DROP AGGREGATE " + a);
 +        assertInvalidMessage("matches multiple function definitions", "DROP AGGREGATE IF EXISTS " + a);
 +
 +        execute("DROP AGGREGATE IF EXISTS " + KEYSPACE + ".non_existing");
 +        execute("DROP AGGREGATE IF EXISTS " + a + "(int, text)");
 +
 +        execute("DROP AGGREGATE " + a + "(double)");
 +
 +        execute("DROP AGGREGATE IF EXISTS " + a + "(double)");
 +    }
 +
 +    @Test
 +    public void testDropReferenced() throws Throwable
 +    {
 +        String f = createFunction(KEYSPACE,
 +                                  "double, double",
 +                                  "CREATE OR REPLACE FUNCTION %s(state double, val double) " +
 +                                  "RETURNS NULL ON NULL INPUT " +
 +                                  "RETURNS double " +
 +                                  "LANGUAGE javascript " +
 +                                  "AS '\"string\";';");
 +
 +        String a = createAggregate(KEYSPACE,
 +                                   "double",
 +                                   "CREATE OR REPLACE AGGREGATE %s(double) " +
 +                                   "SFUNC " + shortFunctionName(f) + " " +
 +                                   "STYPE double " +
 +                                   "INITCOND 0");
 +
 +        // DROP FUNCTION must not succeed because the function is still referenced by the aggregate
 +        assertInvalidMessage("still referenced by", "DROP FUNCTION " + f);
 +
 +        execute("DROP AGGREGATE " + a + "(double)");
 +    }
 +
 +    @Test
 +    public void testJavaAggregateNoInit() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int primary key, b int)");
 +        execute("INSERT INTO %s (a, b) VALUES (1, 1)");
 +        execute("INSERT INTO %s (a, b) VALUES (2, 2)");
 +        execute("INSERT INTO %s (a, b) VALUES (3, 3)");
 +
 +        String fState = createFunction(KEYSPACE,
 +                                       "int, int",
 +                                       "CREATE FUNCTION %s(a int, b int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS int " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return Integer.valueOf((a!=null?a.intValue():0) + b.intValue());'");
 +
 +        String fFinal = createFunction(KEYSPACE,
 +                                       "int",
 +                                       "CREATE FUNCTION %s(a int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS text " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return a.toString();'");
 +
 +        String a = createAggregate(KEYSPACE,
 +                                   "int",
 +                                   "CREATE AGGREGATE %s(int) " +
 +                                   "SFUNC " + shortFunctionName(fState) + " " +
 +                                   "STYPE int " +
 +                                   "FINALFUNC " + shortFunctionName(fFinal));
 +
 +        // 1 + 2 + 3 = 6
 +        assertRows(execute("SELECT " + a + "(b) FROM %s"), row("6"));
 +
 +        execute("DROP AGGREGATE " + a + "(int)");
 +
 +        assertInvalidMessage("Unknown function", "SELECT " + a + "(b) FROM %s");
 +    }
 +
 +    @Test
 +    public void testJavaAggregateNullInitcond() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int primary key, b int)");
 +        execute("INSERT INTO %s (a, b) VALUES (1, 1)");
 +        execute("INSERT INTO %s (a, b) VALUES (2, 2)");
 +        execute("INSERT INTO %s (a, b) VALUES (3, 3)");
 +
 +        String fState = createFunction(KEYSPACE,
 +                                       "int, int",
 +                                       "CREATE FUNCTION %s(a int, b int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS int " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return Integer.valueOf((a!=null?a.intValue():0) + b.intValue());'");
 +
 +        String fFinal = createFunction(KEYSPACE,
 +                                       "int",
 +                                       "CREATE FUNCTION %s(a int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS text " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return a.toString();'");
 +
 +        String a = createAggregate(KEYSPACE,
 +                                   "int",
 +                                   "CREATE AGGREGATE %s(int) " +
 +                                   "SFUNC " + shortFunctionName(fState) + " " +
 +                                   "STYPE int " +
 +                                   "FINALFUNC " + shortFunctionName(fFinal) + " " +
 +                                   "INITCOND null");
 +
 +        // 1 + 2 + 3 = 6
 +        assertRows(execute("SELECT " + a + "(b) FROM %s"), row("6"));
 +
 +        execute("DROP AGGREGATE " + a + "(int)");
 +
 +        assertInvalidMessage("Unknown function", "SELECT " + a + "(b) FROM %s");
 +    }
 +
 +    @Test
 +    public void testJavaAggregateInvalidInitcond() throws Throwable
 +    {
 +        String fState = createFunction(KEYSPACE,
 +                                       "int, int",
 +                                       "CREATE FUNCTION %s(a int, b int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS int " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return Integer.valueOf((a!=null?a.intValue():0) + b.intValue());'");
 +
 +        String fFinal = createFunction(KEYSPACE,
 +                                       "int",
 +                                       "CREATE FUNCTION %s(a int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS text " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return a.toString();'");
 +
 +        assertInvalidMessage("Invalid STRING constant (foobar)",
 +                             "CREATE AGGREGATE " + KEYSPACE + ".aggrInvalid(int)" +
 +                             "SFUNC " + shortFunctionName(fState) + " " +
 +                             "STYPE int " +
 +                             "FINALFUNC " + shortFunctionName(fFinal) + " " +
 +                             "INITCOND 'foobar'");
 +    }
 +
 +    @Test
 +    public void testJavaAggregateIncompatibleTypes() throws Throwable
 +    {
 +        String fState = createFunction(KEYSPACE,
 +                                       "int, int",
 +                                       "CREATE FUNCTION %s(a int, b int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS int " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return Integer.valueOf((a!=null?a.intValue():0) + b.intValue());'");
 +
 +        String fFinal = createFunction(KEYSPACE,
 +                                       "int",
 +                                       "CREATE FUNCTION %s(a int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS text " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return a.toString();'");
 +
 +        String fState2 = createFunction(KEYSPACE,
 +                                        "int, int",
 +                                        "CREATE FUNCTION %s(a double, b double) " +
 +                                        "CALLED ON NULL INPUT " +
 +                                        "RETURNS double " +
 +                                        "LANGUAGE java " +
 +                                        "AS 'return Double.valueOf((a!=null?a.doubleValue():0d) + b.doubleValue());'");
 +
 +        String fFinal2 = createFunction(KEYSPACE,
 +                                        "int",
 +                                        "CREATE FUNCTION %s(a double) " +
 +                                        "CALLED ON NULL INPUT " +
 +                                        "RETURNS text " +
 +                                        "LANGUAGE java " +
 +                                        "AS 'return a.toString();'");
 +
 +        assertInvalidMessage("does not exist or is not a scalar function",
 +                             "CREATE AGGREGATE " + KEYSPACE + ".aggrInvalid(double)" +
 +                             "SFUNC " + shortFunctionName(fState) + " " +
 +                             "STYPE double " +
 +                             "FINALFUNC " + shortFunctionName(fFinal));
 +        assertInvalidMessage("does not exist or is not a scalar function",
 +                             "CREATE AGGREGATE " + KEYSPACE + ".aggrInvalid(int)" +
 +                             "SFUNC " + shortFunctionName(fState) + " " +
 +                             "STYPE double " +
 +                             "FINALFUNC " + shortFunctionName(fFinal));
 +        assertInvalidMessage("does not exist or is not a scalar function",
 +                             "CREATE AGGREGATE " + KEYSPACE + ".aggrInvalid(double)" +
 +                             "SFUNC " + shortFunctionName(fState) + " " +
 +                             "STYPE int " +
 +                             "FINALFUNC " + shortFunctionName(fFinal));
 +        assertInvalidMessage("does not exist or is not a scalar function",
 +                             "CREATE AGGREGATE " + KEYSPACE + ".aggrInvalid(double)" +
 +                             "SFUNC " + shortFunctionName(fState) + " " +
 +                             "STYPE int");
 +        assertInvalidMessage("does not exist or is not a scalar function",
 +                             "CREATE AGGREGATE " + KEYSPACE + ".aggrInvalid(int)" +
 +                             "SFUNC " + shortFunctionName(fState) + " " +
 +                             "STYPE double");
 +
 +        assertInvalidMessage("does not exist or is not a scalar function",
 +                             "CREATE AGGREGATE " + KEYSPACE + ".aggrInvalid(double)" +
 +                             "SFUNC " + shortFunctionName(fState2) + " " +
 +                             "STYPE double " +
 +                             "FINALFUNC " + shortFunctionName(fFinal));
 +
 +        assertInvalidMessage("does not exist or is not a scalar function",
 +                             "CREATE AGGREGATE " + KEYSPACE + ".aggrInvalid(double)" +
 +                             "SFUNC " + shortFunctionName(fState) + " " +
 +                             "STYPE double " +
 +                             "FINALFUNC " + shortFunctionName(fFinal2));
 +    }
 +
 +    @Test
 +    public void testJavaAggregateNonExistingFuncs() throws Throwable
 +    {
 +        String fState = createFunction(KEYSPACE,
 +                                       "int, int",
 +                                       "CREATE FUNCTION %s(a int, b int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS int " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return Integer.valueOf((a!=null?a.intValue():0) + b.intValue());'");
 +
 +        String fFinal = createFunction(KEYSPACE,
 +                                       "int",
 +                                       "CREATE FUNCTION %s(a int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS text " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return a.toString();'");
 +
 +        assertInvalidMessage("does not exist or is not a scalar function",
 +                             "CREATE AGGREGATE " + KEYSPACE + ".aggrInvalid(int)" +
 +                             "SFUNC " + shortFunctionName(fState) + "_not_there " +
 +                             "STYPE int " +
 +                             "FINALFUNC " + shortFunctionName(fFinal));
 +
 +        assertInvalidMessage("does not exist or is not a scalar function",
 +                             "CREATE AGGREGATE " + KEYSPACE + ".aggrInvalid(int)" +
 +                             "SFUNC " + shortFunctionName(fState) + " " +
 +                             "STYPE int " +
 +                             "FINALFUNC " + shortFunctionName(fFinal) + "_not_there");
 +
 +        execute("CREATE AGGREGATE " + KEYSPACE + ".aggrInvalid(int)" +
 +                "SFUNC " + shortFunctionName(fState) + " " +
 +                "STYPE int " +
 +                "FINALFUNC " + shortFunctionName(fFinal));
 +        execute("DROP AGGREGATE " + KEYSPACE + ".aggrInvalid(int)");
 +    }
 +
 +    @Test
 +    public void testJavaAggregateFailingFuncs() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int primary key, b int)");
 +        execute("INSERT INTO %s (a, b) VALUES (1, 1)");
 +        execute("INSERT INTO %s (a, b) VALUES (2, 2)");
 +        execute("INSERT INTO %s (a, b) VALUES (3, 3)");
 +
 +        String fState = createFunction(KEYSPACE,
 +                                       "int, int",
 +                                       "CREATE FUNCTION %s(a int, b int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS int " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'throw new RuntimeException(\"thrown to unit test - not a bug\");'");
 +
 +        String fStateOK = createFunction(KEYSPACE,
 +                                       "int, int",
 +                                       "CREATE FUNCTION %s(a int, b int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS int " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return Integer.valueOf(42);'");
 +
 +        String fFinal = createFunction(KEYSPACE,
 +                                       "int",
 +                                       "CREATE FUNCTION %s(a int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS text " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'throw new RuntimeException(\"thrown to unit test - not a bug\");'");
 +
 +        String fFinalOK = createFunction(KEYSPACE,
 +                                       "int",
 +                                       "CREATE FUNCTION %s(a int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS text " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return \"foobar\";'");
 +
 +        String a0 = createAggregate(KEYSPACE,
 +                                    "int",
 +                                    "CREATE AGGREGATE %s(int) " +
 +                                    "SFUNC " + shortFunctionName(fState) + " " +
 +                                    "STYPE int " +
 +                                    "FINALFUNC " + shortFunctionName(fFinal) + " " +
 +                                    "INITCOND null");
 +        String a1 = createAggregate(KEYSPACE,
 +                                    "int",
 +                                    "CREATE AGGREGATE %s(int) " +
 +                                    "SFUNC " + shortFunctionName(fStateOK) + " " +
 +                                    "STYPE int " +
 +                                    "FINALFUNC " + shortFunctionName(fFinal) + " " +
 +                                    "INITCOND null");
 +        String a2 = createAggregate(KEYSPACE,
 +                                    "int",
 +                                    "CREATE AGGREGATE %s(int) " +
 +                                    "SFUNC " + shortFunctionName(fStateOK) + " " +
 +                                    "STYPE int " +
 +                                    "FINALFUNC " + shortFunctionName(fFinalOK) + " " +
 +                                    "INITCOND null");
 +
 +        assertInvalidThrowMessage("java.lang.RuntimeException", FunctionExecutionException.class, "SELECT " + a0 + "(b) FROM %s");
 +        assertInvalidThrowMessage("java.lang.RuntimeException", FunctionExecutionException.class, "SELECT " + a1 + "(b) FROM %s");
 +        assertRows(execute("SELECT " + a2 + "(b) FROM %s"), row("foobar"));
 +    }
 +
 +    @Test
 +    public void testJavaAggregateWithoutStateOrFinal() throws Throwable
 +    {
 +        assertInvalidMessage("does not exist or is not a scalar function",
 +                             "CREATE AGGREGATE " + KEYSPACE + ".jSumFooNE1(int) " +
 +                             "SFUNC jSumFooNEstate " +
 +                             "STYPE int");
 +
 +        String f = createFunction(KEYSPACE,
 +                                  "int, int",
 +                                  "CREATE FUNCTION %s(a int, b int) " +
 +                                  "RETURNS NULL ON NULL INPUT " +
 +                                  "RETURNS int " +
 +                                  "LANGUAGE java " +
 +                                  "AS 'return Integer.valueOf(a + b);'");
 +
 +        assertInvalidMessage("does not exist or is not a scalar function",
 +                             "CREATE AGGREGATE " + KEYSPACE + ".jSumFooNE2(int) " +
 +                             "SFUNC " + shortFunctionName(f) + " " +
 +                             "STYPE int " +
 +                             "FINALFUNC jSumFooNEfinal");
 +
 +        execute("DROP FUNCTION " + f + "(int, int)");
 +    }
 +
 +    @Test
 +    public void testJavaAggregate() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int primary key, b int)");
 +        execute("INSERT INTO %s (a, b) VALUES (1, 1)");
 +        execute("INSERT INTO %s (a, b) VALUES (2, 2)");
 +        execute("INSERT INTO %s (a, b) VALUES (3, 3)");
 +
 +        String fState = createFunction(KEYSPACE,
 +                                       "int, int",
 +                                       "CREATE FUNCTION %s(a int, b int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS int " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return Integer.valueOf((a!=null?a.intValue():0) + b.intValue());'");
 +
 +        String fFinal = createFunction(KEYSPACE,
 +                                       "int",
 +                                       "CREATE FUNCTION %s(a int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS text " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return a.toString();'");
 +
 +        String a = createAggregate(KEYSPACE,
 +                                   "int",
 +                                   "CREATE AGGREGATE %s(int) " +
 +                                   "SFUNC " + shortFunctionName(fState) + " " +
 +                                   "STYPE int " +
 +                                   "FINALFUNC " + shortFunctionName(fFinal) + " " +
 +                                   "INITCOND 42");
 +
 +        // 42 + 1 + 2 + 3 = 48
 +        assertRows(execute("SELECT " + a + "(b) FROM %s"), row("48"));
 +
 +        execute("DROP AGGREGATE " + a + "(int)");
 +
 +        execute("DROP FUNCTION " + fFinal + "(int)");
 +        execute("DROP FUNCTION " + fState + "(int, int)");
 +
 +        assertInvalidMessage("Unknown function", "SELECT " + a + "(b) FROM %s");
 +    }
 +
 +    @Test
 +    public void testJavaAggregateSimple() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int primary key, b int)");
 +        execute("INSERT INTO %s (a, b) VALUES (1, 1)");
 +        execute("INSERT INTO %s (a, b) VALUES (2, 2)");
 +        execute("INSERT INTO %s (a, b) VALUES (3, 3)");
 +
 +        String fState = createFunction(KEYSPACE,
 +                                       "int, int",
 +                                       "CREATE FUNCTION %s(a int, b int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS int " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return Integer.valueOf((a!=null?a.intValue():0) + b.intValue());'");
 +
 +        String a = createAggregate(KEYSPACE,
 +                                   "int, int",
 +                                   "CREATE AGGREGATE %s(int) " +
 +                                   "SFUNC " + shortFunctionName(fState) + " " +
 +                                   "STYPE int");
 +
 +        // 1 + 2 + 3 = 6
 +        assertRows(execute("SELECT " + a + "(b) FROM %s"), row(6));
 +
 +        execute("DROP AGGREGATE " + a + "(int)");
 +
 +        execute("DROP FUNCTION " + fState + "(int, int)");
 +
 +        assertInvalidMessage("Unknown function", "SELECT " + a + "(b) FROM %s");
 +    }
 +
 +    @Test
 +    public void testJavaAggregateComplex() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int primary key, b int)");
 +        execute("INSERT INTO %s (a, b) VALUES (1, 1)");
 +        execute("INSERT INTO %s (a, b) VALUES (2, 2)");
 +        execute("INSERT INTO %s (a, b) VALUES (3, 3)");
 +
 +        // build an average aggregation function using
 +        // tuple<bigint,int> as state
 +        // double as finaltype
 +
 +        String fState = createFunction(KEYSPACE,
 +                                       "tuple<bigint, int>, int",
 +                                       "CREATE FUNCTION %s(a tuple<bigint, int>, b int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS tuple<bigint, int> " +
 +                                       "LANGUAGE java " +
 +                                       "AS '" +
 +                                       "a.setLong(0, a.getLong(0) + b.intValue());" +
 +                                       "a.setInt(1, a.getInt(1) + 1);" +
 +                                       "return a;" +
 +                                       "'");
 +
 +        String fFinal = createFunction(KEYSPACE,
 +                                       "tuple<bigint, int>",
 +                                       "CREATE FUNCTION %s(a tuple<bigint, int>) " +
 +                                       "RETURNS NULL ON NULL INPUT " +
 +                                       "RETURNS double " +
 +                                       "LANGUAGE java " +
 +                                       "AS '" +
 +                                       "double r = a.getLong(0);" +
 +                                       "r /= a.getInt(1);" +
 +                                       "return Double.valueOf(r);" +
 +                                       "'");
 +
 +        String a = createAggregate(KEYSPACE,
 +                                   "int",
 +                                   "CREATE AGGREGATE %s(int) " +
 +                                   "SFUNC " + shortFunctionName(fState) + " " +
 +                                   "STYPE tuple<bigint, int> "+
 +                                   "FINALFUNC " + shortFunctionName(fFinal) + " " +
 +                                   "INITCOND (0, 0)");
 +
 +        // 1 + 2 + 3 = 6 / 3 = 2
 +        assertRows(execute("SELECT " + a + "(b) FROM %s"), row(2d));
 +
 +    }
 +
 +    @Test
 +    public void testJavascriptAggregate() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int primary key, b int)");
 +        execute("INSERT INTO %s (a, b) VALUES (1, 1)");
 +        execute("INSERT INTO %s (a, b) VALUES (2, 2)");
 +        execute("INSERT INTO %s (a, b) VALUES (3, 3)");
 +
 +        String fState = createFunction(KEYSPACE,
 +                                       "int, int",
 +                                       "CREATE FUNCTION %s(a int, b int) " +
 +                                       "RETURNS NULL ON NULL INPUT " +
 +                                       "RETURNS int " +
 +                                       "LANGUAGE javascript " +
 +                                       "AS 'a + b;'");
 +
 +        String fFinal = createFunction(KEYSPACE,
 +                                       "int",
 +                                       "CREATE FUNCTION %s(a int) " +
 +                                       "RETURNS NULL ON NULL INPUT " +
 +                                       "RETURNS text " +
 +                                       "LANGUAGE javascript " +
 +                                       "AS '\"\"+a'");
 +
 +        String a = createFunction(KEYSPACE,
 +                                  "int",
 +                                  "CREATE AGGREGATE %s(int) " +
 +                                  "SFUNC " + shortFunctionName(fState) + " " +
 +                                  "STYPE int " +
 +                                  "FINALFUNC " + shortFunctionName(fFinal) + " " +
 +                                  "INITCOND 42");
 +
 +        // 42 + 1 + 2 + 3 = 48
 +        assertRows(execute("SELECT " + a + "(b) FROM %s"), row("48"));
 +
 +        execute("DROP AGGREGATE " + a + "(int)");
 +
 +        execute("DROP FUNCTION " + fFinal + "(int)");
 +        execute("DROP FUNCTION " + fState + "(int, int)");
 +
 +        assertInvalidMessage("Unknown function", "SELECT " + a + "(b) FROM %s");
 +    }
 +
 +    @Test
 +    public void testJavascriptAggregateSimple() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int primary key, b int)");
 +        execute("INSERT INTO %s (a, b) VALUES (1, 1)");
 +        execute("INSERT INTO %s (a, b) VALUES (2, 2)");
 +        execute("INSERT INTO %s (a, b) VALUES (3, 3)");
 +
 +        String fState = createFunction(KEYSPACE,
 +                                       "int, int",
 +                                       "CREATE FUNCTION %s(a int, b int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS int " +
 +                                       "LANGUAGE javascript " +
 +                                       "AS 'a + b;'");
 +
 +        String a = createAggregate(KEYSPACE,
 +                                   "int, int",
 +                                   "CREATE AGGREGATE %s(int) " +
 +                                   "SFUNC " + shortFunctionName(fState) + " " +
 +                                   "STYPE int ");
 +
 +        // 1 + 2 + 3 = 6
 +        assertRows(execute("SELECT " + a + "(b) FROM %s"), row(6));
 +
 +        execute("DROP AGGREGATE " + a + "(int)");
 +
 +        execute("DROP FUNCTION " + fState + "(int, int)");
 +
 +        assertInvalidMessage("Unknown function", "SELECT " + a + "(b) FROM %s");
 +    }
 +
 +    @Test
 +    public void testFunctionDropPreparedStatement() throws Throwable
 +    {
 +        String otherKS = "cqltest_foo";
 +
 +        execute("CREATE KEYSPACE IF NOT EXISTS " + otherKS + " WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 3};");
 +        try
 +        {
 +            execute("CREATE TABLE " + otherKS + ".jsdp (a int primary key, b int)");
 +
 +            String fState = createFunction(otherKS,
 +                                           "int, int",
 +                                           "CREATE FUNCTION %s(a int, b int) " +
 +                                           "CALLED ON NULL INPUT " +
 +                                           "RETURNS int " +
 +                                           "LANGUAGE javascript " +
 +                                           "AS 'a + b;'");
 +
 +            String a = createAggregate(otherKS,
 +                                       "int",
 +                                       "CREATE AGGREGATE %s(int) " +
 +                                       "SFUNC " + shortFunctionName(fState) + " " +
 +                                       "STYPE int");
 +
 +            ResultMessage.Prepared prepared = QueryProcessor.prepare("SELECT " + a + "(b) FROM " + otherKS + ".jsdp", ClientState.forInternalCalls(), false);
 +            assertNotNull(QueryProcessor.instance.getPrepared(prepared.statementId));
 +
 +            execute("DROP AGGREGATE " + a + "(int)");
 +            assertNull(QueryProcessor.instance.getPrepared(prepared.statementId));
 +
 +            //
 +
 +            execute("CREATE AGGREGATE " + a + "(int) " +
 +                    "SFUNC " + shortFunctionName(fState) + " " +
 +                    "STYPE int");
 +
 +            prepared = QueryProcessor.prepare("SELECT " + a + "(b) FROM " + otherKS + ".jsdp", ClientState.forInternalCalls(), false);
 +            assertNotNull(QueryProcessor.instance.getPrepared(prepared.statementId));
 +
 +            execute("DROP KEYSPACE " + otherKS + ";");
 +
 +            assertNull(QueryProcessor.instance.getPrepared(prepared.statementId));
 +        }
 +        finally
 +        {
 +            execute("DROP KEYSPACE IF EXISTS " + otherKS + ";");
 +        }
 +    }
 +
 +    @Test
 +    public void testAggregatesReferencedInAggregates() throws Throwable
 +    {
 +
 +        String fState = createFunction(KEYSPACE,
 +                                       "int, int",
 +                                       "CREATE FUNCTION %s(a int, b int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS int " +
 +                                       "LANGUAGE javascript " +
 +                                       "AS 'a + b;'");
 +
 +        String a = createAggregate(KEYSPACE,
 +                                   "int",
 +                                   "CREATE AGGREGATE %s(int) " +
 +                                   "SFUNC " + shortFunctionName(fState) + " " +
 +                                   "STYPE int ");
 +
 +        assertInvalidMessage("does not exist or is not a scalar function",
 +                             "CREATE AGGREGATE " + KEYSPACE + ".aggInv(int) " +
 +                             "SFUNC " + shortFunctionName(a) + " " +
 +                             "STYPE int ");
 +
 +        assertInvalidMessage("does not exist or is not a scalar function",
 +                             "CREATE AGGREGATE " + KEYSPACE + ".aggInv(int) " +
 +                             "SFUNC " + shortFunctionName(fState) + " " +
 +                             "STYPE int " +
 +                             "FINALFUNC " + shortFunctionName(a));
 +    }
 +
 +    @Test
 +    public void testCalledOnNullInput() throws Throwable
 +    {
 +        String fStateNonNull = createFunction(KEYSPACE,
 +                                              "int, int",
 +                                              "CREATE OR REPLACE FUNCTION %s(state int, val int) " +
 +                                              "RETURNS NULL ON NULL INPUT " +
 +                                              "RETURNS int " +
 +                                              "LANGUAGE java\n" +
 +                                              "AS 'return Integer.valueOf(state + val);';");
 +        String fStateNull = createFunction(KEYSPACE,
 +                                           "int, int",
 +                                           "CREATE OR REPLACE FUNCTION %s(state int, val int) " +
 +                                           "CALLED ON NULL INPUT " +
 +                                           "RETURNS int " +
 +                                           "LANGUAGE java\n" +
 +                                           "AS 'return Integer.valueOf(" +
 +                                           "   (state != null ? state.intValue() : 0) " +
 +                                           "   + (val != null ? val.intValue() : 0));';");
 +        String fStateAlwaysNull = createFunction(KEYSPACE,
 +                                           "int, int",
 +                                           "CREATE OR REPLACE FUNCTION %s(state int, val int) " +
 +                                           "CALLED ON NULL INPUT " +
 +                                           "RETURNS int " +
 +                                           "LANGUAGE java\n" +
 +                                           "AS 'return null;';");
 +        String fFinalNonNull = createFunction(KEYSPACE,
 +                                              "int",
 +                                              "CREATE OR REPLACE FUNCTION %s(state int) " +
 +                                              "RETURNS NULL ON NULL INPUT " +
 +                                              "RETURNS int " +
 +                                              "LANGUAGE java\n" +
 +                                              "AS 'return Integer.valueOf(state);';");
 +        String fFinalNull = createFunction(KEYSPACE,
 +                                           "int",
 +                                           "CREATE OR REPLACE FUNCTION %s(state int) " +
 +                                           "CALLED ON NULL INPUT " +
 +                                           "RETURNS int " +
 +                                           "LANGUAGE java\n" +
 +                                           "AS 'return state;';");
 +
 +        assertInvalid("CREATE AGGREGATE " + KEYSPACE + ".invAggr(int) " +
 +                      "SFUNC " + shortFunctionName(fStateNonNull) + " " +
 +                      "STYPE int");
 +        assertInvalid("CREATE AGGREGATE " + KEYSPACE + ".invAggr(int) " +
 +                      "SFUNC " + shortFunctionName(fStateNonNull) + " " +
 +                      "STYPE int " +
 +                      "FINALFUNC " + shortFunctionName(fFinalNonNull));
 +
 +        String aStateNull = createAggregate(KEYSPACE,
 +                                               "int",
 +                                               "CREATE AGGREGATE %s(int) " +
 +                                               "SFUNC " + shortFunctionName(fStateNull) + " " +
 +                                               "STYPE int");
 +        String aStateNullFinalNull = createAggregate(KEYSPACE,
 +                                                        "int",
 +                                                        "CREATE AGGREGATE %s(int) " +
 +                                                        "SFUNC " + shortFunctionName(fStateNull) + " " +
 +                                                        "STYPE int " +
 +                                                        "FINALFUNC " + shortFunctionName(fFinalNull));
 +        String aStateNullFinalNonNull = createAggregate(KEYSPACE,
 +                                                        "int",
 +                                                        "CREATE AGGREGATE %s(int) " +
 +                                                        "SFUNC " + shortFunctionName(fStateNull) + " " +
 +                                                        "STYPE int " +
 +                                                        "FINALFUNC " + shortFunctionName(fFinalNonNull));
 +        String aStateNonNull = createAggregate(KEYSPACE,
 +                                               "int",
 +                                               "CREATE AGGREGATE %s(int) " +
 +                                               "SFUNC " + shortFunctionName(fStateNonNull) + " " +
 +                                               "STYPE int " +
 +                                               "INITCOND 0");
 +        String aStateNonNullFinalNull = createAggregate(KEYSPACE,
 +                                                        "int",
 +                                                        "CREATE AGGREGATE %s(int) " +
 +                                                        "SFUNC " + shortFunctionName(fStateNonNull) + " " +
 +                                                        "STYPE int " +
 +                                                        "FINALFUNC " + shortFunctionName(fFinalNull) + " " +
 +                                                        "INITCOND 0");
 +        String aStateNonNullFinalNonNull = createAggregate(KEYSPACE,
 +                                                           "int",
 +                                                           "CREATE AGGREGATE %s(int) " +
 +                                                           "SFUNC " + shortFunctionName(fStateNonNull) + " " +
 +                                                           "STYPE int " +
 +                                                           "FINALFUNC " + shortFunctionName(fFinalNonNull) + " " +
 +                                                           "INITCOND 0");
 +        String aStateAlwaysNullFinalNull = createAggregate(KEYSPACE,
 +                                                           "int",
 +                                                           "CREATE AGGREGATE %s(int) " +
 +                                                           "SFUNC " + shortFunctionName(fStateAlwaysNull) + " " +
 +                                                           "STYPE int " +
 +                                                           "FINALFUNC " + shortFunctionName(fFinalNull));
 +        String aStateAlwaysNullFinalNonNull = createAggregate(KEYSPACE,
 +                                                           "int",
 +                                                           "CREATE AGGREGATE %s(int) " +
 +                                                           "SFUNC " + shortFunctionName(fStateAlwaysNull) + " " +
 +                                                           "STYPE int " +
 +                                                           "FINALFUNC " + shortFunctionName(fFinalNonNull));
 +
 +        createTable("CREATE TABLE %s (key int PRIMARY KEY, i int)");
 +
 +        execute("INSERT INTO %s (key, i) VALUES (0, null)");
 +        execute("INSERT INTO %s (key, i) VALUES (1, 1)");
 +        execute("INSERT INTO %s (key, i) VALUES (2, 2)");
 +        execute("INSERT INTO %s (key, i) VALUES (3, 3)");
 +
 +        assertRows(execute("SELECT " + aStateNull + "(i) FROM %s WHERE key = 0"), row(0));
 +        assertRows(execute("SELECT " + aStateNullFinalNull + "(i) FROM %s WHERE key = 0"), row(0));
 +        assertRows(execute("SELECT " + aStateNullFinalNonNull + "(i) FROM %s WHERE key = 0"), row(0));
 +        assertRows(execute("SELECT " + aStateNonNull + "(i) FROM %s WHERE key = 0"), row(0));
 +        assertRows(execute("SELECT " + aStateNonNullFinalNull + "(i) FROM %s WHERE key = 0"), row(0));
 +        assertRows(execute("SELECT " + aStateNonNullFinalNonNull + "(i) FROM %s WHERE key = 0"), row(0));
 +        assertRows(execute("SELECT " + aStateAlwaysNullFinalNull + "(i) FROM %s WHERE key = 0"), row(new Object[]{null}));
 +        assertRows(execute("SELECT " + aStateAlwaysNullFinalNonNull + "(i) FROM %s WHERE key = 0"), row(new Object[]{null}));
 +
 +        assertRows(execute("SELECT " + aStateNull + "(i) FROM %s WHERE key = 1"), row(1));
 +        assertRows(execute("SELECT " + aStateNullFinalNull + "(i) FROM %s WHERE key = 1"), row(1));
 +        assertRows(execute("SELECT " + aStateNullFinalNonNull + "(i) FROM %s WHERE key = 1"), row(1));
 +        assertRows(execute("SELECT " + aStateNonNull + "(i) FROM %s WHERE key = 1"), row(1));
 +        assertRows(execute("SELECT " + aStateNonNullFinalNull + "(i) FROM %s WHERE key = 1"), row(1));
 +        assertRows(execute("SELECT " + aStateNonNullFinalNonNull + "(i) FROM %s WHERE key = 1"), row(1));
 +        assertRows(execute("SELECT " + aStateAlwaysNullFinalNull + "(i) FROM %s WHERE key = 1"), row(new Object[]{null}));
 +        assertRows(execute("SELECT " + aStateAlwaysNullFinalNonNull + "(i) FROM %s WHERE key = 1"), row(new Object[]{null}));
 +
 +        assertRows(execute("SELECT " + aStateNull + "(i) FROM %s WHERE key IN (1, 2, 3)"), row(6));
 +        assertRows(execute("SELECT " + aStateNullFinalNull + "(i) FROM %s WHERE key IN (1, 2, 3)"), row(6));
 +        assertRows(execute("SELECT " + aStateNullFinalNonNull + "(i) FROM %s WHERE key IN (1, 2, 3)"), row(6));
 +        assertRows(execute("SELECT " + aStateNonNull + "(i) FROM %s WHERE key IN (1, 2, 3)"), row(6));
 +        assertRows(execute("SELECT " + aStateNonNullFinalNull + "(i) FROM %s WHERE key IN (1, 2, 3)"), row(6));
 +        assertRows(execute("SELECT " + aStateNonNullFinalNonNull + "(i) FROM %s WHERE key IN (1, 2, 3)"), row(6));
 +        assertRows(execute("SELECT " + aStateAlwaysNullFinalNull + "(i) FROM %s WHERE key IN (1, 2, 3)"), row(new Object[]{null}));
 +        assertRows(execute("SELECT " + aStateAlwaysNullFinalNonNull + "(i) FROM %s WHERE key IN (1, 2, 3)"), row(new Object[]{null}));
 +    }
 +
 +    @Test
 +    public void testBrokenAggregate() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (key int primary key, val int)");
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1);
 +
 +        String fState = createFunction(KEYSPACE,
 +                                       "int, int",
 +                                       "CREATE FUNCTION %s(a int, b int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS int " +
 +                                       "LANGUAGE javascript " +
 +                                       "AS 'a + b;'");
 +
 +        String a = createAggregate(KEYSPACE,
 +                                   "int",
 +                                   "CREATE AGGREGATE %s(int) " +
 +                                   "SFUNC " + shortFunctionName(fState) + " " +
 +                                   "STYPE int ");
 +
 +        UDAggregate f = (UDAggregate) Functions.find(parseFunctionName(a)).get(0);
 +
 +        Functions.addOrReplaceFunction(UDAggregate.createBroken(f.name(), f.argTypes(), f.returnType(),
 +                                                                null, new InvalidRequestException("foo bar is broken")));
 +
 +        assertInvalidThrowMessage("foo bar is broken", InvalidRequestException.class,
 +                                  "SELECT " + a + "(val) FROM %s");
 +    }
 +
 +    @Test
 +    public void testWrongStateType() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (key int primary key, val int)");
 +        execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1);
 +
 +        String fState = createFunction(KEYSPACE,
 +                                       "int, int",
 +                                       "CREATE FUNCTION %s(a int, b int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS double " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return Double.valueOf(1.0);'");
 +
 +        String fFinal = createFunction(KEYSPACE,
 +                                       "int",
 +                                       "CREATE FUNCTION %s(a int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS int " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return Integer.valueOf(1);';");
 +
 +        assertInvalidMessage("return type must be the same as the first argument type - check STYPE, argument and return types",
 +                             "CREATE AGGREGATE %s(int) " +
 +                             "SFUNC " + shortFunctionName(fState) + ' ' +
 +                             "STYPE int " +
 +                             "FINALFUNC " + shortFunctionName(fFinal) + ' ' +
 +                             "INITCOND 1");
 +    }
 +
 +    @Test
 +    public void testWrongKeyspace() throws Throwable
 +    {
 +        String typeName = createType("CREATE TYPE %s (txt text, i int)");
 +        String type = KEYSPACE + '.' + typeName;
 +
 +        String fState = createFunction(KEYSPACE_PER_TEST,
 +                                       "int, int",
 +                                       "CREATE FUNCTION %s(a int, b int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS double " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return Double.valueOf(1.0);'");
 +
 +        String fFinal = createFunction(KEYSPACE_PER_TEST,
 +                                       "int",
 +                                       "CREATE FUNCTION %s(a int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS int " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return Integer.valueOf(1);';");
 +
 +        String fStateWrong = createFunction(KEYSPACE,
 +                                       "int, int",
 +                                       "CREATE FUNCTION %s(a int, b int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS double " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return Double.valueOf(1.0);'");
 +
 +        String fFinalWrong = createFunction(KEYSPACE,
 +                                       "int",
 +                                       "CREATE FUNCTION %s(a int) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS int " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return Integer.valueOf(1);';");
 +
 +        assertInvalidMessage(String.format("Statement on keyspace %s cannot refer to a user type in keyspace %s; user types can only be used in the keyspace they are defined in",
 +                                           KEYSPACE_PER_TEST, KEYSPACE),
 +                             "CREATE AGGREGATE " + KEYSPACE_PER_TEST + ".test_wrong_ks(int) " +
 +                             "SFUNC " + shortFunctionName(fState) + ' ' +
 +                             "STYPE " + type + " " +
 +                             "FINALFUNC " + shortFunctionName(fFinal) + ' ' +
 +                             "INITCOND 1");
 +
 +        assertInvalidMessage("mismatched input", // specifying a function using "keyspace.functionname" is a syntax error
 +                             "CREATE AGGREGATE " + KEYSPACE_PER_TEST + ".test_wrong_ks(int) " +
 +                             "SFUNC " + fStateWrong + ' ' +
 +                             "STYPE " + type + " " +
 +                             "FINALFUNC " + shortFunctionName(fFinal) + ' ' +
 +                             "INITCOND 1");
 +
 +        assertInvalidMessage("missing EOF", // specifying a function using "keyspace.functionname" is a syntax error
 +                             "CREATE AGGREGATE " + KEYSPACE_PER_TEST + ".test_wrong_ks(int) " +
 +                             "SFUNC " + shortFunctionName(fState) + ' ' +
 +                             "STYPE " + type + " " +
 +                             "FINALFUNC " + fFinalWrong + ' ' +
 +                             "INITCOND 1");
 +
 +        assertInvalidMessage("missing EOF", // specifying a function using "keyspace.functionname" is a syntax error
 +                             "CREATE AGGREGATE " + KEYSPACE_PER_TEST + ".test_wrong_ks(int) " +
 +                             "SFUNC " + shortFunctionName(fState) + ' ' +
 +                             "STYPE " + type + ' ' +
 +                             "FINALFUNC " + SystemKeyspace.NAME + ".min " +
 +                             "INITCOND 1");
 +    }
 +
 +    @Test
 +    public void testFunctionWithFrozenSetType() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int PRIMARY KEY, b frozen<set<int>>)");
 +        createIndex("CREATE INDEX ON %s (FULL(b))");
 +
 +        execute("INSERT INTO %s (a, b) VALUES (?, ?)", 0, set());
 +        execute("INSERT INTO %s (a, b) VALUES (?, ?)", 1, set(1, 2, 3));
 +        execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, set(4, 5, 6));
 +        execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, set(7, 8, 9));
 +
 +        String fState = createFunction(KEYSPACE,
 +                                       "set<int>",
 +                                       "CREATE FUNCTION %s (state set<int>, values set<int>) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS set<int> " +
 +                                       "LANGUAGE java\n" +
 +                                       "AS 'return values;';");
 +
 +        String fFinal = createFunction(KEYSPACE,
 +                                       "set<int>",
 +                                       "CREATE FUNCTION %s(state set<int>) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS set<int> " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return state;'");
 +
 +        assertInvalidMessage("The function state type should not be frozen",
 +                             "CREATE AGGREGATE %s(set<int>) " +
 +                             "SFUNC " + parseFunctionName(fState).name + ' ' +
 +                             "STYPE frozen<set<int>> " +
 +                             "FINALFUNC " + parseFunctionName(fFinal).name + ' ' +
 +                             "INITCOND null");
 +
 +        String aggregation = createAggregate(KEYSPACE,
 +                                             "set<int>",
 +                                             "CREATE AGGREGATE %s(set<int>) " +
 +                                             "SFUNC " + parseFunctionName(fState).name + ' ' +
 +                                             "STYPE set<int> " +
 +                                             "FINALFUNC " + parseFunctionName(fFinal).name + ' ' +
 +                                             "INITCOND null");
 +
 +        assertRows(execute("SELECT " + aggregation + "(b) FROM %s"),
 +                   row(set(7, 8, 9)));
 +
 +        assertInvalidMessage("The function arguments should not be frozen",
 +                             "DROP AGGREGATE %s (frozen<set<int>>);");
 +    }
 +
 +    @Test
 +    public void testFunctionWithFrozenListType() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int PRIMARY KEY, b frozen<list<int>>)");
 +        createIndex("CREATE INDEX ON %s (FULL(b))");
 +
 +        execute("INSERT INTO %s (a, b) VALUES (?, ?)", 0, list());
 +        execute("INSERT INTO %s (a, b) VALUES (?, ?)", 1, list(1, 2, 3));
 +        execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, list(4, 5, 6));
 +        execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, list(7, 8, 9));
 +
 +        String fState = createFunction(KEYSPACE,
 +                                       "list<int>",
 +                                       "CREATE FUNCTION %s (state list<int>, values list<int>) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS list<int> " +
 +                                       "LANGUAGE java\n" +
 +                                       "AS 'return values;';");
 +
 +        String fFinal = createFunction(KEYSPACE,
 +                                       "list<int>",
 +                                       "CREATE FUNCTION %s(state list<int>) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS list<int> " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return state;'");
 +
 +        assertInvalidMessage("The function state type should not be frozen",
 +                             "CREATE AGGREGATE %s(list<int>) " +
 +                             "SFUNC " + parseFunctionName(fState).name + ' ' +
 +                             "STYPE frozen<list<int>> " +
 +                             "FINALFUNC " + parseFunctionName(fFinal).name + " " +
 +                             "INITCOND null");
 +
 +        String aggregation = createAggregate(KEYSPACE,
 +                                             "list<int>",
 +                                             "CREATE AGGREGATE %s(list<int>) " +
 +                                             "SFUNC " + parseFunctionName(fState).name + ' ' +
 +                                             "STYPE list<int> " +
 +                                             "FINALFUNC " + parseFunctionName(fFinal).name + ' ' +
 +                                             "INITCOND null");
 +
 +        assertRows(execute("SELECT " + aggregation + "(b) FROM %s"),
 +                   row(list(7, 8, 9)));
 +
 +        assertInvalidMessage("The function arguments should not be frozen",
 +                             "DROP AGGREGATE %s (frozen<list<int>>);");
 +    }
 +
 +    @Test
 +    public void testFunctionWithFrozenMapType() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int PRIMARY KEY, b frozen<map<int, int>>)");
 +        createIndex("CREATE INDEX ON %s (FULL(b))");
 +
 +        execute("INSERT INTO %s (a, b) VALUES (?, ?)", 0, map());
 +        execute("INSERT INTO %s (a, b) VALUES (?, ?)", 1, map(1, 2, 3, 4));
 +        execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 5, 6, 7));
 +        execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 8, 9, 10));
 +
 +        String fState = createFunction(KEYSPACE,
 +                                       "map<int, int>",
 +                                       "CREATE FUNCTION %s (state map<int, int>, values map<int, int>) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS map<int, int> " +
 +                                       "LANGUAGE java\n" +
 +                                       "AS 'return values;';");
 +
 +        String fFinal = createFunction(KEYSPACE,
 +                                       "map<int, int>",
 +                                       "CREATE FUNCTION %s(state map<int, int>) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS map<int, int> " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return state;'");
 +
 +        assertInvalidMessage("The function state type should not be frozen",
 +                             "CREATE AGGREGATE %s(map<int, int>) " +
 +                             "SFUNC " + parseFunctionName(fState).name + ' ' +
 +                             "STYPE frozen<map<int, int>> " +
 +                             "FINALFUNC " + parseFunctionName(fFinal).name + ' ' +
 +                             "INITCOND null");
 +
 +        String aggregation = createAggregate(KEYSPACE,
 +                                             "map<int, int>",
 +                                             "CREATE AGGREGATE %s(map<int, int>) " +
 +                                             "SFUNC " + parseFunctionName(fState).name + ' ' +
 +                                             "STYPE map<int, int> " +
 +                                             "FINALFUNC " + parseFunctionName(fFinal).name + ' ' +
 +                                             "INITCOND null");
 +
 +        assertRows(execute("SELECT " + aggregation + "(b) FROM %s"),
 +                   row(map(7, 8, 9, 10)));
 +
 +        assertInvalidMessage("The function arguments should not be frozen",
 +                             "DROP AGGREGATE %s (frozen<map<int, int>>);");
 +    }
 +
 +    @Test
 +    public void testFunctionWithFrozenTupleType() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int PRIMARY KEY, b frozen<tuple<int, int>>)");
 +        createIndex("CREATE INDEX ON %s (b)");
 +
 +        execute("INSERT INTO %s (a, b) VALUES (?, ?)", 0, tuple());
 +        execute("INSERT INTO %s (a, b) VALUES (?, ?)", 1, tuple(1, 2));
 +        execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, tuple(4, 5));
 +        execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, tuple(7, 8));
 +
 +        String fState = createFunction(KEYSPACE,
 +                                       "tuple<int, int>",
 +                                       "CREATE FUNCTION %s (state tuple<int, int>, values tuple<int, int>) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS tuple<int, int> " +
 +                                       "LANGUAGE java\n" +
 +                                       "AS 'return values;';");
 +
 +        String fFinal = createFunction(KEYSPACE,
 +                                       "tuple<int, int>",
 +                                       "CREATE FUNCTION %s(state tuple<int, int>) " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS tuple<int, int> " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return state;'");
 +
 +        assertInvalidMessage("The function state type should not be frozen",
 +                             "CREATE AGGREGATE %s(tuple<int, int>) " +
 +                             "SFUNC " + parseFunctionName(fState).name + ' ' +
 +                             "STYPE frozen<tuple<int, int>> " +
 +                             "FINALFUNC " + parseFunctionName(fFinal).name + ' ' +
 +                             "INITCOND null");
 +
 +        String aggregation = createAggregate(KEYSPACE,
 +                                             "tuple<int, int>",
 +                                             "CREATE AGGREGATE %s(tuple<int, int>) " +
 +                                             "SFUNC " + parseFunctionName(fState).name + ' ' +
 +                                             "STYPE tuple<int, int> " +
 +                                             "FINALFUNC " + parseFunctionName(fFinal).name + ' ' +
 +                                             "INITCOND null");
 +
 +        assertRows(execute("SELECT " + aggregation + "(b) FROM %s"),
 +                   row(tuple(7, 8)));
 +
 +        assertInvalidMessage("The function arguments should not be frozen",
 +                             "DROP AGGREGATE %s (frozen<tuple<int, int>>);");
 +    }
 +
 +    @Test
 +    public void testFunctionWithFrozenUDFType() throws Throwable
 +    {
 +        String myType = createType("CREATE TYPE %s (f int)");
 +        createTable("CREATE TABLE %s (a int PRIMARY KEY, b frozen<" + myType + ">)");
 +        createIndex("CREATE INDEX ON %s (b)");
 +
 +        execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 0, 1);
 +        execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 2);
 +        execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
 +        execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
 +
 +        String fState = createFunction(KEYSPACE,
 +                                       myType + ',' + myType,
 +                                       "CREATE FUNCTION %s (state " + myType + ", values " + myType + ") " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS " + myType + " " +
 +                                       "LANGUAGE java\n" +
 +                                       "AS 'return values;';");
 +
 +        String fFinal = createFunction(KEYSPACE,
 +                                       myType,
 +                                       "CREATE FUNCTION %s(state " + myType + ") " +
 +                                       "CALLED ON NULL INPUT " +
 +                                       "RETURNS " + myType + " " +
 +                                       "LANGUAGE java " +
 +                                       "AS 'return state;'");
 +
 +        assertInvalidMessage("The function state type should not be frozen",
 +                             "CREATE AGGREGATE %s(" + myType + ") " +
 +                             "SFUNC " + parseFunctionName(fState).name + ' ' +
 +                             "STYPE frozen<" + myType + "> " +
 +                             "FINALFUNC " + parseFunctionName(fFinal).name + ' ' +
 +                             "INITCOND null");
 +
 +        String aggregation = createAggregate(KEYSPACE,
 +                                             myType,
 +                                             "CREATE AGGREGATE %s(" + myType + ") " +
 +                                             "SFUNC " + parseFunctionName(fState).name + ' ' +
 +                                             "STYPE " + myType + ' ' +
 +                                             "FINALFUNC " + parseFunctionName(fFinal).name + ' ' +
 +                                             "INITCOND null");
 +
 +        assertRows(execute("SELECT " + aggregation + "(b).f FROM %s"),
 +                   row(7));
 +
 +        assertInvalidMessage("The function arguments should not be frozen",
 +                             "DROP AGGREGATE %s (frozen<" + myType + ">);");
 +    }
 +
 +    @Test
 +    public void testEmptyValues() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int primary key, b text)");
 +        execute("INSERT INTO %s (a, b) VALUES (1, '')");
 +        execute("INSERT INTO %s (a, b) VALUES (2, '')");
 +        execute("INSERT INTO %s (a, b) VALUES (3, '')");
 +
 +        String fCON = createFunction(KEYSPACE,
 +                                     "text, text",
 +                                     "CREATE FUNCTION %s(a text, b text) " +
 +                                     "CALLED ON NULL INPUT " +
 +                                     "RETURNS text " +
 +                                     "LANGUAGE java " +
 +                                     "AS 'return a + \"x\" + b + \"y\";'");
 +
 +        String fCONf = createFunction(KEYSPACE,
 +                                     "text",
 +                                     "CREATE FUNCTION %s(a text) " +
 +                                     "CALLED ON NULL INPUT " +
 +                                     "RETURNS text " +
 +                                     "LANGUAGE java " +
 +                                     "AS 'return \"fin\" + a;'");
 +
 +        String aCON = createAggregate(KEYSPACE,
 +                                      "text",
 +                                      "CREATE AGGREGATE %s(text) " +
 +                                      "SFUNC " + shortFunctionName(fCON) + ' ' +
 +                                      "STYPE text " +
 +                                      "FINALFUNC " + shortFunctionName(fCONf) + ' ' +
 +                                      "INITCOND ''");
 +
 +        String fRNON = createFunction(KEYSPACE,
 +                                      "text, text",
 +                                      "CREATE FUNCTION %s(a text, b text) " +
 +                                      "RETURNS NULL ON NULL INPUT " +
 +                                      "RETURNS text " +
 +                                      "LANGUAGE java " +
 +                                      "AS 'return a + \"x\" + b + \"y\";'");
 +
 +        String fRNONf = createFunction(KEYSPACE,
 +                                      "text",
 +                                      "CREATE FUNCTION %s(a text) " +
 +                                      "RETURNS 

<TRUNCATED>