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>