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 2016/12/07 12:38:36 UTC
[01/25] cassandra git commit: testall failure in
org.apache.cassandra.cql3.validation.entities.UFTest.testAllNativeTypes
Repository: cassandra
Updated Branches:
refs/heads/cassandra-2.2 2e93398ce -> 0b97c5d1f
refs/heads/cassandra-3.0 95d0b671d -> 3aefe3565
refs/heads/cassandra-3.X 57c2003de -> d7b6b7a34
refs/heads/trunk 8253912a6 -> d2a92e4b1
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0b97c5d1/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
index bcfe871..d4d2a10 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
@@ -17,9 +17,6 @@
*/
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;
@@ -34,14 +31,9 @@ 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;
@@ -50,13 +42,11 @@ 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
@@ -295,7 +285,7 @@ public class UFTest extends CQLTester
return prepared;
}
- public void checkDelayedValuesCorrectlyIdentifyFunctionsInUse(boolean dropKeyspace) throws Throwable
+ private void checkDelayedValuesCorrectlyIdentifyFunctionsInUse(boolean dropKeyspace) throws Throwable
{
// prepare a statement which doesn't use any function for a control
createTable("CREATE TABLE %s (" +
@@ -584,164 +574,6 @@ public class UFTest extends CQLTester
}
@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 testJavaFunctionCounter() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val counter)");
-
- String fName = createFunction(KEYSPACE, "counter",
- "CREATE OR REPLACE FUNCTION %s(val counter) " +
- "CALLED ON NULL INPUT " +
- "RETURNS bigint " +
- "LANGUAGE JAVA " +
- "AS 'return val + 1;';");
-
- execute("UPDATE %s SET val = val + 1 WHERE key = 1");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 1L, 2L));
- execute("UPDATE %s SET val = val + 1 WHERE key = 1");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 2L, 3L));
- execute("UPDATE %s SET val = val + 2 WHERE key = 1");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 4L, 5L));
- execute("UPDATE %s SET val = val - 2 WHERE key = 1");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 2L, 3L));
- }
-
- @Test
public void testFunctionInTargetKeyspace() throws Throwable
{
createTable("CREATE TABLE %s (key int primary key, val double)");
@@ -869,140 +701,6 @@ public class UFTest extends CQLTester
}
@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)");
@@ -1135,206 +833,6 @@ public class UFTest extends CQLTester
}
@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)");
@@ -1372,686 +870,22 @@ public class UFTest extends CQLTester
}
@Test
- public void testJavaUserTypeRenameField() throws Throwable
+ public void testDuplicateArgNames() throws Throwable
{
- String type = KEYSPACE + '.' + createType("CREATE TYPE %s (txt text, i int)");
+ assertInvalidMessage("duplicate argument names for given function",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double, val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS '\"foo bar\";';");
+ }
- 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"),
- row(1d));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup3 + "(tup) FROM %s WHERE key = 1"),
- row(list));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup4 + "(tup) FROM %s WHERE key = 1"),
- row(set));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup5 + "(tup) FROM %s WHERE key = 1"),
- row(map));
- }
- }
-
- @Test
- public void testJavascriptUserType() throws Throwable
- {
- String type = createType("CREATE TYPE %s (txt text, i int)");
-
- createTable("CREATE TABLE %s (key int primary key, udt frozen<" + type + ">)");
-
- String fUdt1 = createFunction(KEYSPACE, type,
- "CREATE FUNCTION %s( udt " + type + " ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS " + type + " " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " udt;$$;");
- String fUdt2 = createFunction(KEYSPACE, type,
- "CREATE FUNCTION %s( udt " + type + " ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " udt.getString(\"txt\");$$;");
- String fUdt3 = createFunction(KEYSPACE, type,
- "CREATE FUNCTION %s( udt " + type + " ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " udt.getInt(\"i\");$$;");
-
- execute("INSERT INTO %s (key, udt) VALUES (1, {txt: 'one', i:1})");
-
- UntypedResultSet rows = execute("SELECT " + fUdt1 + "(udt) FROM %s WHERE key = 1");
- Assert.assertEquals(1, rows.size());
- assertRows(execute("SELECT " + fUdt2 + "(udt) FROM %s WHERE key = 1"),
- row("one"));
- assertRows(execute("SELECT " + fUdt3 + "(udt) FROM %s WHERE key = 1"),
- row(1));
- }
-
- @Test
- public void testJavascriptUTCollections() throws Throwable
- {
- String type = 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 fName = createFunction(KEYSPACE, "list<frozen<" + type + ">>",
- "CREATE FUNCTION %s( lst list<frozen<" + type + ">> ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " lst.get(1).getString(\"txt\");$$;");
- createFunctionOverload(fName, "set<frozen<" + type + ">>",
- "CREATE FUNCTION %s( st set<frozen<" + type + ">> ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " st.iterator().next().getString(\"txt\");$$;");
- createFunctionOverload(fName, "map<int, frozen<" + type + ">>",
- "CREATE FUNCTION %s( mp map<int, frozen<" + type + ">> ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " mp.get(java.lang.Integer.valueOf(3)).getString(\"txt\");$$;");
-
- execute("INSERT INTO %s (key, lst, st, mp) values (1, " +
- // list<frozen<UDT>>
- "[ {txt: 'one', i:1}, {txt: 'three', i:1}, {txt: 'one', i:1} ] , " +
- // set<frozen<UDT>>
- "{ {txt: 'one', i:1}, {txt: 'three', i:3}, {txt: 'two', i:2} }, " +
- // map<int, frozen<UDT>>
- "{ 1: {txt: 'one', i:1}, 2: {txt: 'one', i:3}, 3: {txt: 'two', i:2} })");
-
- assertRows(execute("SELECT " + fName + "(lst) FROM %s WHERE key = 1"),
- row("three"));
- assertRows(execute("SELECT " + fName + "(st) FROM %s WHERE key = 1"),
- row("one"));
- assertRows(execute("SELECT " + fName + "(mp) FROM %s WHERE key = 1"),
- row("two"));
-
- String cqlSelect = "SELECT " + fName + "(lst), " + fName + "(st), " + fName + "(mp) FROM %s WHERE key = 1";
- assertRows(execute(cqlSelect),
- row("three", "one", "two"));
-
- // same test - but via native protocol
- for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
- assertRowsNet(version,
- executeNet(version, cqlSelect),
- row("three", "one", "two"));
- }
-
- @Test
- public void testJavascriptFunction() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val double)");
-
- String functionBody = '\n' +
- " Math.sin(val);\n";
-
- String fName = createFunction(KEYSPACE, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\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("javascript", 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 testJavascriptBadReturnType() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val double)");
-
- String fName = createFunction(KEYSPACE, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS '\"string\";';");
-
- execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
- // throws IRE with ClassCastException
- assertInvalidMessage("Invalid value for CQL type double", "SELECT key, val, " + fName + "(val) FROM %s");
- }
-
- @Test
- public void testJavascriptThrow() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val double)");
-
- String fName = createFunction(KEYSPACE, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS 'throw \"fool\";';");
-
- execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
- // throws IRE with ScriptException
- assertInvalidThrowMessage("fool", FunctionExecutionException.class,
- "SELECT key, val, " + fName + "(val) FROM %s");
- }
-
- @Test
- public void testDuplicateArgNames() throws Throwable
- {
- assertInvalidMessage("duplicate argument names for given function",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double, val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS '\"foo bar\";';");
- }
-
- @Test
- public void testJavascriptCompileFailure() throws Throwable
- {
- assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS 'foo bar';");
- }
-
- @Test
- public void testScriptInvalidLanguage() throws Throwable
- {
- assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE artificial_intelligence\n" +
- "AS 'question for 42?';");
- }
-
- @Test
- public void testScriptReturnTypeCasting() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val double)");
- execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
-
- Object[][] variations = {
- new Object[] { "true", "boolean", true },
- new Object[] { "false", "boolean", false },
- new Object[] { "100", "tinyint", (byte)100 },
- new Object[] { "100.", "tinyint", (byte)100 },
- new Object[] { "100", "smallint", (short)100 },
- new Object[] { "100.", "smallint", (short)100 },
- new Object[] { "100", "int", 100 },
- new Object[] { "100.", "int", 100 },
- new Object[] { "100", "double", 100d },
- new Object[] { "100.", "double", 100d },
- new Object[] { "100", "bigint", 100L },
- new Object[] { "100.", "bigint", 100L },
- new Object[] { "100", "varint", BigInteger.valueOf(100L) },
- new Object[] { "100.", "varint", BigInteger.valueOf(100L) },
- new Object[] { "parseInt(\"100\");", "decimal", BigDecimal.valueOf(100d) },
- new Object[] { "100.", "decimal", BigDecimal.valueOf(100d) },
- };
-
- for (Object[] variation : variations)
- {
- Object functionBody = variation[0];
- Object returnType = variation[1];
- Object expectedResult = variation[2];
-
- String fName = createFunction(KEYSPACE, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS " +returnType + ' ' +
- "LANGUAGE javascript " +
- "AS '" + functionBody + ";';");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 1d, expectedResult));
- }
- }
-
- @Test
- public void testScriptParamReturnTypes() throws Throwable
- {
- UUID ruuid = UUID.randomUUID();
- UUID tuuid = UUIDGen.getTimeUUID();
-
- createTable("CREATE TABLE %s (key int primary key, " +
- "tival tinyint, sival smallint, ival int, lval bigint, fval float, dval double, vval varint, ddval decimal, " +
- "timval time, dtval date, tsval timestamp, uval uuid, tuval timeuuid)");
- execute("INSERT INTO %s (key, tival, sival, ival, lval, fval, dval, vval, ddval, timval, dtval, tsval, uval, tuval) VALUES " +
- "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 1,
- (byte)1, (short)1, 1, 1L, 1f, 1d, BigInteger.valueOf(1L), BigDecimal.valueOf(1d), 1L, Integer.MAX_VALUE, new Date(1), ruuid, tuuid);
-
- Object[][] variations = {
- new Object[] { "tinyint", "tival", (byte)1, (byte)2 },
- new Object[] { "smallint", "sival", (short)1, (short)2 },
- new Object[] { "int", "ival", 1, 2 },
- new Object[] { "bigint", "lval", 1L, 2L },
- new Object[] { "float", "fval", 1f, 2f },
- new Object[] { "double", "dval", 1d, 2d },
- new Object[] { "varint", "vval", BigInteger.valueOf(1L), BigInteger.valueOf(2L) },
- new Object[] { "decimal", "ddval", BigDecimal.valueOf(1d), BigDecimal.valueOf(2d) },
- new Object[] { "time", "timval", 1L, 2L },
- };
-
- for (Object[] variation : variations)
- {
- Object type = variation[0];
- Object col = variation[1];
- Object expected1 = variation[2];
- Object expected2 = variation[3];
- String fName = createFunction(KEYSPACE, type.toString(),
- "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS " + type + ' ' +
- "LANGUAGE javascript " +
- "AS 'val+1;';");
- assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
- row(1, expected1, expected2));
- }
-
- variations = new Object[][] {
- new Object[] { "timestamp","tsval", new Date(1), new Date(1) },
- new Object[] { "uuid", "uval", ruuid, ruuid },
- new Object[] { "timeuuid", "tuval", tuuid, tuuid },
- new Object[] { "date", "dtval", Integer.MAX_VALUE, Integer.MAX_VALUE },
- };
-
- for (Object[] variation : variations)
- {
- Object type = variation[0];
- Object col = variation[1];
- Object expected1 = variation[2];
- Object expected2 = variation[3];
- String fName = createFunction(KEYSPACE, type.toString(),
- "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS " + type + ' ' +
- "LANGUAGE javascript " +
- "AS 'val;';");
- assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
- row(1, expected1, expected2));
- }
- }
-
- static class TypesTestDef
- {
- final String udfType;
- final String tableType;
- final String columnName;
- final Object referenceValue;
+ private static class TypesTestDef
+ {
+ final String udfType;
+ final String tableType;
+ final String columnName;
+ final Object referenceValue;
String fCheckArgAndReturn;
@@ -2274,416 +1108,4 @@ public class UFTest extends CQLTester
}
}
}
-
- @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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<set<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS set<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<list<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS list<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<map<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS map<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<tuple<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, "(null, null)"),
- row(1, "(1, 2)"),
- row(2, "(4, 5)"),
- row(3, "(7, 8)"));
-
- functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS tuple<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
- }
-
- @Test
- public void testFunctionWithFrozenUDType() 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, 0);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<" + myType + "> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, "{f:0}"),
- row(1, "{f:1}"),
- row(2, "{f:4}"),
- row(3, "{f:7}"));
-
- functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS " + myType + " " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
- }
-
- @Test
- public void testEmptyString() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, sval text, aval ascii, bval blob, empty_int int)");
- execute("INSERT INTO %s (key, sval, aval, bval, empty_int) VALUES (?, ?, ?, ?, blobAsInt(0x))", 1, "", "", ByteBuffer.allocate(0));
-
- String fNameSRC = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameSCC = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return \"\";'");
-
- String fNameSRN = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameSCN = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return \"\";'");
-
- String fNameBRC = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "CALLED ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameBCC = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "CALLED ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return ByteBuffer.allocate(0);'");
-
- String fNameBRN = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameBCN = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return ByteBuffer.allocate(0);'");
-
- String fNameIRC = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameICC = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- String fNameIRN = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameICN = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- assertRows(execute("SELECT " + fNameSRC + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRN + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCC + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCN + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRC + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRN + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCC + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCN + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameBRC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBRN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBCC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBCN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameIRC + "(empty_int) FROM %s"), row(new Object[]{null}));
- assertRows(execute("SELECT " + fNameIRN + "(empty_int) FROM %s"), row(new Object[]{null}));
- assertRows(execute("SELECT " + fNameICC + "(empty_int) FROM %s"), row(0));
- assertRows(execute("SELECT " + fNameICN + "(empty_int) FROM %s"), row(new Object[]{null}));
- }
-
- @Test
- public void testAllNativeTypes() throws Throwable
- {
- StringBuilder sig = new StringBuilder();
- StringBuilder args = new StringBuilder();
- for (CQL3Type.Native type : CQL3Type.Native.values())
- {
- if (sig.length() > 0)
- sig.append(',');
- sig.append(type.toString());
-
- if (args.length() > 0)
- args.append(',');
- args.append("arg").append(type.toString()).append(' ').append(type.toString());
- }
- createFunction(KEYSPACE, sig.toString(),
- "CREATE OR REPLACE FUNCTION %s(" + args + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- for (CQL3Type.Native type : CQL3Type.Native.values())
- {
- createFunction(KEYSPACE_PER_TEST, type.toString(),
- "CREATE OR REPLACE FUNCTION %s(val " + type.toString() + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
- }
- }
}
[05/25] cassandra git commit: testall failure in
org.apache.cassandra.cql3.validation.entities.UFTest.testAllNativeTypes
Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0b97c5d1/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
index bcfe871..d4d2a10 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
@@ -17,9 +17,6 @@
*/
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;
@@ -34,14 +31,9 @@ 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;
@@ -50,13 +42,11 @@ 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
@@ -295,7 +285,7 @@ public class UFTest extends CQLTester
return prepared;
}
- public void checkDelayedValuesCorrectlyIdentifyFunctionsInUse(boolean dropKeyspace) throws Throwable
+ private void checkDelayedValuesCorrectlyIdentifyFunctionsInUse(boolean dropKeyspace) throws Throwable
{
// prepare a statement which doesn't use any function for a control
createTable("CREATE TABLE %s (" +
@@ -584,164 +574,6 @@ public class UFTest extends CQLTester
}
@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 testJavaFunctionCounter() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val counter)");
-
- String fName = createFunction(KEYSPACE, "counter",
- "CREATE OR REPLACE FUNCTION %s(val counter) " +
- "CALLED ON NULL INPUT " +
- "RETURNS bigint " +
- "LANGUAGE JAVA " +
- "AS 'return val + 1;';");
-
- execute("UPDATE %s SET val = val + 1 WHERE key = 1");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 1L, 2L));
- execute("UPDATE %s SET val = val + 1 WHERE key = 1");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 2L, 3L));
- execute("UPDATE %s SET val = val + 2 WHERE key = 1");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 4L, 5L));
- execute("UPDATE %s SET val = val - 2 WHERE key = 1");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 2L, 3L));
- }
-
- @Test
public void testFunctionInTargetKeyspace() throws Throwable
{
createTable("CREATE TABLE %s (key int primary key, val double)");
@@ -869,140 +701,6 @@ public class UFTest extends CQLTester
}
@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)");
@@ -1135,206 +833,6 @@ public class UFTest extends CQLTester
}
@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)");
@@ -1372,686 +870,22 @@ public class UFTest extends CQLTester
}
@Test
- public void testJavaUserTypeRenameField() throws Throwable
+ public void testDuplicateArgNames() throws Throwable
{
- String type = KEYSPACE + '.' + createType("CREATE TYPE %s (txt text, i int)");
+ assertInvalidMessage("duplicate argument names for given function",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double, val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS '\"foo bar\";';");
+ }
- 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"),
- row(1d));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup3 + "(tup) FROM %s WHERE key = 1"),
- row(list));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup4 + "(tup) FROM %s WHERE key = 1"),
- row(set));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup5 + "(tup) FROM %s WHERE key = 1"),
- row(map));
- }
- }
-
- @Test
- public void testJavascriptUserType() throws Throwable
- {
- String type = createType("CREATE TYPE %s (txt text, i int)");
-
- createTable("CREATE TABLE %s (key int primary key, udt frozen<" + type + ">)");
-
- String fUdt1 = createFunction(KEYSPACE, type,
- "CREATE FUNCTION %s( udt " + type + " ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS " + type + " " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " udt;$$;");
- String fUdt2 = createFunction(KEYSPACE, type,
- "CREATE FUNCTION %s( udt " + type + " ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " udt.getString(\"txt\");$$;");
- String fUdt3 = createFunction(KEYSPACE, type,
- "CREATE FUNCTION %s( udt " + type + " ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " udt.getInt(\"i\");$$;");
-
- execute("INSERT INTO %s (key, udt) VALUES (1, {txt: 'one', i:1})");
-
- UntypedResultSet rows = execute("SELECT " + fUdt1 + "(udt) FROM %s WHERE key = 1");
- Assert.assertEquals(1, rows.size());
- assertRows(execute("SELECT " + fUdt2 + "(udt) FROM %s WHERE key = 1"),
- row("one"));
- assertRows(execute("SELECT " + fUdt3 + "(udt) FROM %s WHERE key = 1"),
- row(1));
- }
-
- @Test
- public void testJavascriptUTCollections() throws Throwable
- {
- String type = 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 fName = createFunction(KEYSPACE, "list<frozen<" + type + ">>",
- "CREATE FUNCTION %s( lst list<frozen<" + type + ">> ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " lst.get(1).getString(\"txt\");$$;");
- createFunctionOverload(fName, "set<frozen<" + type + ">>",
- "CREATE FUNCTION %s( st set<frozen<" + type + ">> ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " st.iterator().next().getString(\"txt\");$$;");
- createFunctionOverload(fName, "map<int, frozen<" + type + ">>",
- "CREATE FUNCTION %s( mp map<int, frozen<" + type + ">> ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " mp.get(java.lang.Integer.valueOf(3)).getString(\"txt\");$$;");
-
- execute("INSERT INTO %s (key, lst, st, mp) values (1, " +
- // list<frozen<UDT>>
- "[ {txt: 'one', i:1}, {txt: 'three', i:1}, {txt: 'one', i:1} ] , " +
- // set<frozen<UDT>>
- "{ {txt: 'one', i:1}, {txt: 'three', i:3}, {txt: 'two', i:2} }, " +
- // map<int, frozen<UDT>>
- "{ 1: {txt: 'one', i:1}, 2: {txt: 'one', i:3}, 3: {txt: 'two', i:2} })");
-
- assertRows(execute("SELECT " + fName + "(lst) FROM %s WHERE key = 1"),
- row("three"));
- assertRows(execute("SELECT " + fName + "(st) FROM %s WHERE key = 1"),
- row("one"));
- assertRows(execute("SELECT " + fName + "(mp) FROM %s WHERE key = 1"),
- row("two"));
-
- String cqlSelect = "SELECT " + fName + "(lst), " + fName + "(st), " + fName + "(mp) FROM %s WHERE key = 1";
- assertRows(execute(cqlSelect),
- row("three", "one", "two"));
-
- // same test - but via native protocol
- for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
- assertRowsNet(version,
- executeNet(version, cqlSelect),
- row("three", "one", "two"));
- }
-
- @Test
- public void testJavascriptFunction() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val double)");
-
- String functionBody = '\n' +
- " Math.sin(val);\n";
-
- String fName = createFunction(KEYSPACE, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\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("javascript", 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 testJavascriptBadReturnType() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val double)");
-
- String fName = createFunction(KEYSPACE, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS '\"string\";';");
-
- execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
- // throws IRE with ClassCastException
- assertInvalidMessage("Invalid value for CQL type double", "SELECT key, val, " + fName + "(val) FROM %s");
- }
-
- @Test
- public void testJavascriptThrow() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val double)");
-
- String fName = createFunction(KEYSPACE, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS 'throw \"fool\";';");
-
- execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
- // throws IRE with ScriptException
- assertInvalidThrowMessage("fool", FunctionExecutionException.class,
- "SELECT key, val, " + fName + "(val) FROM %s");
- }
-
- @Test
- public void testDuplicateArgNames() throws Throwable
- {
- assertInvalidMessage("duplicate argument names for given function",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double, val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS '\"foo bar\";';");
- }
-
- @Test
- public void testJavascriptCompileFailure() throws Throwable
- {
- assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS 'foo bar';");
- }
-
- @Test
- public void testScriptInvalidLanguage() throws Throwable
- {
- assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE artificial_intelligence\n" +
- "AS 'question for 42?';");
- }
-
- @Test
- public void testScriptReturnTypeCasting() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val double)");
- execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
-
- Object[][] variations = {
- new Object[] { "true", "boolean", true },
- new Object[] { "false", "boolean", false },
- new Object[] { "100", "tinyint", (byte)100 },
- new Object[] { "100.", "tinyint", (byte)100 },
- new Object[] { "100", "smallint", (short)100 },
- new Object[] { "100.", "smallint", (short)100 },
- new Object[] { "100", "int", 100 },
- new Object[] { "100.", "int", 100 },
- new Object[] { "100", "double", 100d },
- new Object[] { "100.", "double", 100d },
- new Object[] { "100", "bigint", 100L },
- new Object[] { "100.", "bigint", 100L },
- new Object[] { "100", "varint", BigInteger.valueOf(100L) },
- new Object[] { "100.", "varint", BigInteger.valueOf(100L) },
- new Object[] { "parseInt(\"100\");", "decimal", BigDecimal.valueOf(100d) },
- new Object[] { "100.", "decimal", BigDecimal.valueOf(100d) },
- };
-
- for (Object[] variation : variations)
- {
- Object functionBody = variation[0];
- Object returnType = variation[1];
- Object expectedResult = variation[2];
-
- String fName = createFunction(KEYSPACE, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS " +returnType + ' ' +
- "LANGUAGE javascript " +
- "AS '" + functionBody + ";';");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 1d, expectedResult));
- }
- }
-
- @Test
- public void testScriptParamReturnTypes() throws Throwable
- {
- UUID ruuid = UUID.randomUUID();
- UUID tuuid = UUIDGen.getTimeUUID();
-
- createTable("CREATE TABLE %s (key int primary key, " +
- "tival tinyint, sival smallint, ival int, lval bigint, fval float, dval double, vval varint, ddval decimal, " +
- "timval time, dtval date, tsval timestamp, uval uuid, tuval timeuuid)");
- execute("INSERT INTO %s (key, tival, sival, ival, lval, fval, dval, vval, ddval, timval, dtval, tsval, uval, tuval) VALUES " +
- "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 1,
- (byte)1, (short)1, 1, 1L, 1f, 1d, BigInteger.valueOf(1L), BigDecimal.valueOf(1d), 1L, Integer.MAX_VALUE, new Date(1), ruuid, tuuid);
-
- Object[][] variations = {
- new Object[] { "tinyint", "tival", (byte)1, (byte)2 },
- new Object[] { "smallint", "sival", (short)1, (short)2 },
- new Object[] { "int", "ival", 1, 2 },
- new Object[] { "bigint", "lval", 1L, 2L },
- new Object[] { "float", "fval", 1f, 2f },
- new Object[] { "double", "dval", 1d, 2d },
- new Object[] { "varint", "vval", BigInteger.valueOf(1L), BigInteger.valueOf(2L) },
- new Object[] { "decimal", "ddval", BigDecimal.valueOf(1d), BigDecimal.valueOf(2d) },
- new Object[] { "time", "timval", 1L, 2L },
- };
-
- for (Object[] variation : variations)
- {
- Object type = variation[0];
- Object col = variation[1];
- Object expected1 = variation[2];
- Object expected2 = variation[3];
- String fName = createFunction(KEYSPACE, type.toString(),
- "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS " + type + ' ' +
- "LANGUAGE javascript " +
- "AS 'val+1;';");
- assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
- row(1, expected1, expected2));
- }
-
- variations = new Object[][] {
- new Object[] { "timestamp","tsval", new Date(1), new Date(1) },
- new Object[] { "uuid", "uval", ruuid, ruuid },
- new Object[] { "timeuuid", "tuval", tuuid, tuuid },
- new Object[] { "date", "dtval", Integer.MAX_VALUE, Integer.MAX_VALUE },
- };
-
- for (Object[] variation : variations)
- {
- Object type = variation[0];
- Object col = variation[1];
- Object expected1 = variation[2];
- Object expected2 = variation[3];
- String fName = createFunction(KEYSPACE, type.toString(),
- "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS " + type + ' ' +
- "LANGUAGE javascript " +
- "AS 'val;';");
- assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
- row(1, expected1, expected2));
- }
- }
-
- static class TypesTestDef
- {
- final String udfType;
- final String tableType;
- final String columnName;
- final Object referenceValue;
+ private static class TypesTestDef
+ {
+ final String udfType;
+ final String tableType;
+ final String columnName;
+ final Object referenceValue;
String fCheckArgAndReturn;
@@ -2274,416 +1108,4 @@ public class UFTest extends CQLTester
}
}
}
-
- @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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<set<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS set<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<list<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS list<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<map<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS map<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<tuple<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, "(null, null)"),
- row(1, "(1, 2)"),
- row(2, "(4, 5)"),
- row(3, "(7, 8)"));
-
- functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS tuple<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
- }
-
- @Test
- public void testFunctionWithFrozenUDType() 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, 0);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<" + myType + "> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, "{f:0}"),
- row(1, "{f:1}"),
- row(2, "{f:4}"),
- row(3, "{f:7}"));
-
- functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS " + myType + " " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
- }
-
- @Test
- public void testEmptyString() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, sval text, aval ascii, bval blob, empty_int int)");
- execute("INSERT INTO %s (key, sval, aval, bval, empty_int) VALUES (?, ?, ?, ?, blobAsInt(0x))", 1, "", "", ByteBuffer.allocate(0));
-
- String fNameSRC = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameSCC = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return \"\";'");
-
- String fNameSRN = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameSCN = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return \"\";'");
-
- String fNameBRC = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "CALLED ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameBCC = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "CALLED ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return ByteBuffer.allocate(0);'");
-
- String fNameBRN = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameBCN = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return ByteBuffer.allocate(0);'");
-
- String fNameIRC = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameICC = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- String fNameIRN = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameICN = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- assertRows(execute("SELECT " + fNameSRC + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRN + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCC + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCN + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRC + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRN + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCC + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCN + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameBRC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBRN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBCC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBCN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameIRC + "(empty_int) FROM %s"), row(new Object[]{null}));
- assertRows(execute("SELECT " + fNameIRN + "(empty_int) FROM %s"), row(new Object[]{null}));
- assertRows(execute("SELECT " + fNameICC + "(empty_int) FROM %s"), row(0));
- assertRows(execute("SELECT " + fNameICN + "(empty_int) FROM %s"), row(new Object[]{null}));
- }
-
- @Test
- public void testAllNativeTypes() throws Throwable
- {
- StringBuilder sig = new StringBuilder();
- StringBuilder args = new StringBuilder();
- for (CQL3Type.Native type : CQL3Type.Native.values())
- {
- if (sig.length() > 0)
- sig.append(',');
- sig.append(type.toString());
-
- if (args.length() > 0)
- args.append(',');
- args.append("arg").append(type.toString()).append(' ').append(type.toString());
- }
- createFunction(KEYSPACE, sig.toString(),
- "CREATE OR REPLACE FUNCTION %s(" + args + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- for (CQL3Type.Native type : CQL3Type.Native.values())
- {
- createFunction(KEYSPACE_PER_TEST, type.toString(),
- "CREATE OR REPLACE FUNCTION %s(val " + type.toString() + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
- }
- }
}
[23/25] cassandra git commit: Merge branch 'cassandra-3.0' into
cassandra-3.X
Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/d7b6b7a3/test/unit/org/apache/cassandra/cql3/validation/entities/UFTypesTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFTypesTest.java
index 0000000,de98748..3f1bcb1
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTypesTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTypesTest.java
@@@ -1,0 -1,549 +1,550 @@@
+ /*
+ * 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.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.Test;
+
+ import com.datastax.driver.core.Row;
+ import org.apache.cassandra.cql3.CQLTester;
+ import org.apache.cassandra.cql3.UntypedResultSet;
++import org.apache.cassandra.transport.ProtocolVersion;
+ import org.apache.cassandra.utils.UUIDGen;
+
+ public class UFTypesTest extends CQLTester
+ {
+
+ @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 : PROTOCOL_VERSIONS)
++ for (ProtocolVersion version : PROTOCOL_VERSIONS)
+ {
+ 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"));
+ }
+ }
+
+ private static class TypesTestDef
+ {
+ final String udfType;
+ final String tableType;
+ final String columnName;
+ final Object referenceValue;
+
+ String fCheckArgAndReturn;
+
+ String fCalledOnNull;
+ String fReturnsNullOnNull;
+
+ TypesTestDef(String udfType, String tableType, String columnName, Object referenceValue)
+ {
+ this.udfType = udfType;
+ this.tableType = tableType;
+ this.columnName = columnName;
+ this.referenceValue = referenceValue;
+ }
+ }
+
+ @Test
+ public void testTypesWithAndWithoutNulls() throws Throwable
+ {
+ // test various combinations of types against UDFs with CALLED ON NULL or RETURNS NULL ON NULL
+
+ String type = createType("CREATE TYPE %s (txt text, i int)");
+
+ TypesTestDef[] typeDefs =
+ {
+ // udf type, table type, column, reference value
+ new TypesTestDef("timestamp", "timestamp", "ts", new Date()),
+ new TypesTestDef("date", "date", "dt", 12345),
+ new TypesTestDef("time", "time", "tim", 12345L),
+ new TypesTestDef("uuid", "uuid", "uu", UUID.randomUUID()),
+ new TypesTestDef("timeuuid", "timeuuid", "tu", UUIDGen.getTimeUUID()),
+ new TypesTestDef("tinyint", "tinyint", "ti", (byte) 42),
+ new TypesTestDef("smallint", "smallint", "si", (short) 43),
+ new TypesTestDef("int", "int", "i", 44),
+ new TypesTestDef("bigint", "bigint", "b", 45L),
+ new TypesTestDef("float", "float", "f", 46f),
+ new TypesTestDef("double", "double", "d", 47d),
+ new TypesTestDef("boolean", "boolean", "x", true),
+ new TypesTestDef("ascii", "ascii", "a", "tqbfjutld"),
+ new TypesTestDef("text", "text", "t", "k\u00f6lsche jung"),
+ //new TypesTestDef(type, "frozen<" + type + '>', "u", null),
+ new TypesTestDef("tuple<int, text>", "frozen<tuple<int, text>>", "tup", tuple(1, "foo"))
+ };
+
+ String createTableDDL = "CREATE TABLE %s (key int PRIMARY KEY";
+ String insertDML = "INSERT INTO %s (key";
+ List<Object> values = new ArrayList<>();
+ for (TypesTestDef typeDef : typeDefs)
+ {
+ createTableDDL += ", " + typeDef.columnName + ' ' + typeDef.tableType;
+ insertDML += ", " + typeDef.columnName;
+ String typeName = typeDef.udfType;
+ typeDef.fCheckArgAndReturn = createFunction(KEYSPACE,
+ typeName,
+ "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS " + typeName + ' ' +
+ "LANGUAGE java\n" +
+ "AS 'return val;';");
+ typeDef.fCalledOnNull = createFunction(KEYSPACE,
+ typeName,
+ "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return \"called\";';");
+ typeDef.fReturnsNullOnNull = createFunction(KEYSPACE,
+ typeName,
+ "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return \"called\";';");
+ values.add(typeDef.referenceValue);
+ }
+
+ createTableDDL += ')';
+ createTable(createTableDDL);
+
+ insertDML += ") VALUES (1";
+ for (TypesTestDef ignored : typeDefs)
+ insertDML += ", ?";
+ insertDML += ')';
+
+ execute(insertDML, values.toArray());
+
+ // second row with null values
+ for (int i = 0; i < values.size(); i++)
+ values.set(i, null);
+ execute(insertDML.replace('1', '2'), values.toArray());
+
+ // check argument input + return
+ for (TypesTestDef typeDef : typeDefs)
+ {
+ assertRows(execute("SELECT " + typeDef.fCheckArgAndReturn + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
+ row(new Object[]{ typeDef.referenceValue }));
+ }
+
+ // check for CALLED ON NULL INPUT with non-null arguments
+ for (TypesTestDef typeDef : typeDefs)
+ {
+ assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
+ row(new Object[]{ "called" }));
+ }
+
+ // check for CALLED ON NULL INPUT with null arguments
+ for (TypesTestDef typeDef : typeDefs)
+ {
+ assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
+ row(new Object[]{ "called" }));
+ }
+
+ // check for RETURNS NULL ON NULL INPUT with non-null arguments
+ for (TypesTestDef typeDef : typeDefs)
+ {
+ assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
+ row(new Object[]{ "called" }));
+ }
+
+ // check for RETURNS NULL ON NULL INPUT with null arguments
+ for (TypesTestDef typeDef : typeDefs)
+ {
+ assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
+ row(new Object[]{ null }));
+ }
+
+ }
+
+ @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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<set<int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "set<int>",
+ "CREATE FUNCTION %s (values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "set<int>",
+ "CREATE FUNCTION %s (values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS set<int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<list<int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "list<int>",
+ "CREATE FUNCTION %s (values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "list<int>",
+ "CREATE FUNCTION %s (values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS list<int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
+ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
+ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<map<int, int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "map<int, int>",
+ "CREATE FUNCTION %s (values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "map<int, int>",
+ "CREATE FUNCTION %s (values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS map<int, int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<tuple<int, int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "tuple<int, int>",
+ "CREATE FUNCTION %s (values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, "(NULL,NULL)"));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, "(1,2)"));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, "(4,5)"));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, "(7,8)"));
+
+ functionName = createFunction(KEYSPACE,
+ "tuple<int, int>",
+ "CREATE FUNCTION %s (values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS tuple<int, int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
+ }
+
+ @Test
+ public void testFunctionWithFrozenUDType() 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, 0);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<" + myType + "> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ myType,
+ "CREATE FUNCTION %s (values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, "{f:0}"));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, "{f:1}"));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, "{f:4}"));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, "{f:7}"));
+
+ functionName = createFunction(KEYSPACE,
+ myType,
+ "CREATE FUNCTION %s (values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS " + myType + " " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
+ }
+ }
[18/25] 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/3aefe356/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
index c52e178,d4d2a10..8a743ea
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
@@@ -17,44 -17,37 +17,29 @@@
*/
package org.apache.cassandra.cql3.validation.entities;
+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 java.security.AccessControlException;
import org.junit.Assert;
-import org.junit.BeforeClass;
import org.junit.Test;
- import com.datastax.driver.core.*;
-import com.datastax.driver.core.Row;
import com.datastax.driver.core.exceptions.InvalidQueryException;
--import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.config.Schema;
- 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.config.Config;
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.cql3.functions.UDHelper;
import org.apache.cassandra.db.marshal.CollectionType;
- import org.apache.cassandra.exceptions.FunctionExecutionException;
-import org.apache.cassandra.dht.ByteOrderedPartitioner;
import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.schema.KeyspaceMetadata;
import org.apache.cassandra.service.ClientState;
- import org.apache.cassandra.service.ClientWarn;
import org.apache.cassandra.transport.Event;
import org.apache.cassandra.transport.Server;
import org.apache.cassandra.transport.messages.ResultMessage;
-import org.apache.cassandra.utils.UUIDGen;
+import org.apache.cassandra.utils.ByteBufferUtil;
- import org.apache.cassandra.utils.UUIDGen;
public class UFTest extends CQLTester
{
@@@ -1017,320 -724,115 +710,6 @@@
}
@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 : PROTOCOL_VERSIONS)
- 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));
-
- // same test - but via native protocol
- // we use protocol V3 here to encode the expected version because the server
- // always serializes Collections using V3 - see CollectionSerializer's
- // serialize and deserialize methods.
- TupleType tType = tupleTypeOf(Server.VERSION_3,
- 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 : PROTOCOL_VERSIONS)
- {
- 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 : PROTOCOL_VERSIONS)
- {
- 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 : PROTOCOL_VERSIONS)
- {
- 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)");
@@@ -1593,162 -880,140 +757,7 @@@
"AS '\"foo bar\";';");
}
- private static class TypesTestDef
- {
- final String udfType;
- final String tableType;
- final String columnName;
- final Object referenceValue;
-
- String fCheckArgAndReturn;
-
- String fCalledOnNull;
- String fReturnsNullOnNull;
-
- TypesTestDef(String udfType, String tableType, String columnName, Object referenceValue)
- {
- this.udfType = udfType;
- this.tableType = tableType;
- this.columnName = columnName;
- this.referenceValue = referenceValue;
- }
- }
-
- @Test
- public void testTypesWithAndWithoutNulls() throws Throwable
- {
- // test various combinations of types against UDFs with CALLED ON NULL or RETURNS NULL ON NULL
-
- String type = createType("CREATE TYPE %s (txt text, i int)");
-
- TypesTestDef[] typeDefs =
- {
- // udf type, table type, column, reference value
- new TypesTestDef("timestamp", "timestamp", "ts", new Date()),
- new TypesTestDef("date", "date", "dt", 12345),
- new TypesTestDef("time", "time", "tim", 12345L),
- new TypesTestDef("uuid", "uuid", "uu", UUID.randomUUID()),
- new TypesTestDef("timeuuid", "timeuuid", "tu", UUIDGen.getTimeUUID()),
- new TypesTestDef("tinyint", "tinyint", "ti", (byte) 42),
- new TypesTestDef("smallint", "smallint", "si", (short) 43),
- new TypesTestDef("int", "int", "i", 44),
- new TypesTestDef("bigint", "bigint", "b", 45L),
- new TypesTestDef("float", "float", "f", 46f),
- new TypesTestDef("double", "double", "d", 47d),
- new TypesTestDef("boolean", "boolean", "x", true),
- new TypesTestDef("ascii", "ascii", "a", "tqbfjutld"),
- new TypesTestDef("text", "text", "t", "k\u00f6lsche jung"),
- //new TypesTestDef(type, "frozen<" + type + '>', "u", null),
- new TypesTestDef("tuple<int, text>", "frozen<tuple<int, text>>", "tup", tuple(1, "foo"))
- };
-
- String createTableDDL = "CREATE TABLE %s (key int PRIMARY KEY";
- String insertDML = "INSERT INTO %s (key";
- List<Object> values = new ArrayList<>();
- for (TypesTestDef typeDef : typeDefs)
- {
- createTableDDL += ", " + typeDef.columnName + ' ' + typeDef.tableType;
- insertDML += ", " + typeDef.columnName;
- String typeName = typeDef.udfType;
- typeDef.fCheckArgAndReturn = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS " + typeName + ' ' +
- "LANGUAGE java\n" +
- "AS 'return val;';");
- typeDef.fCalledOnNull = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return \"called\";';");
- typeDef.fReturnsNullOnNull = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return \"called\";';");
- values.add(typeDef.referenceValue);
- }
-
- createTableDDL += ')';
- createTable(createTableDDL);
-
- insertDML += ") VALUES (1";
- for (TypesTestDef ignored : typeDefs)
- insertDML += ", ?";
- insertDML += ')';
-
- execute(insertDML, values.toArray());
-
- // second row with null values
- for (int i = 0; i < values.size(); i++)
- values.set(i, null);
- execute(insertDML.replace('1', '2'), values.toArray());
-
- // check argument input + return
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCheckArgAndReturn + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ typeDef.referenceValue }));
- }
-
- // check for CALLED ON NULL INPUT with non-null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ "called" }));
- }
-
- // check for CALLED ON NULL INPUT with null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
- row(new Object[]{ "called" }));
- }
-
- // check for RETURNS NULL ON NULL INPUT with non-null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ "called" }));
- }
-
- // check for RETURNS NULL ON NULL INPUT with null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
- row(new Object[]{ null }));
- }
-
- }
-
@Test
- public void testJavascriptCompileFailure() throws Throwable
- {
- assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS 'foo bar';");
- }
-
- @Test
- public void testScriptInvalidLanguage() throws Throwable
- {
- assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE artificial_intelligence\n" +
- "AS 'question for 42?';");
- }
-
- static class TypesTestDef
- {
- final String udfType;
- final String tableType;
- final String columnName;
- final Object referenceValue;
-
- String fCheckArgAndReturn;
-
- String fCalledOnNull;
- String fReturnsNullOnNull;
-
- TypesTestDef(String udfType, String tableType, String columnName, Object referenceValue)
- {
- this.udfType = udfType;
- this.tableType = tableType;
- this.columnName = columnName;
- this.referenceValue = referenceValue;
- }
- }
-
- @Test
- public void testTypesWithAndWithoutNulls() throws Throwable
- {
- // test various combinations of types against UDFs with CALLED ON NULL or RETURNS NULL ON NULL
-
- String type = createType("CREATE TYPE %s (txt text, i int)");
-
- TypesTestDef[] typeDefs =
- {
- // udf type, table type, column, reference value
- new TypesTestDef("timestamp", "timestamp", "ts", new Date()),
- new TypesTestDef("date", "date", "dt", 12345),
- new TypesTestDef("time", "time", "tim", 12345L),
- new TypesTestDef("uuid", "uuid", "uu", UUID.randomUUID()),
- new TypesTestDef("timeuuid", "timeuuid", "tu", UUIDGen.getTimeUUID()),
- new TypesTestDef("tinyint", "tinyint", "ti", (byte) 42),
- new TypesTestDef("smallint", "smallint", "si", (short) 43),
- new TypesTestDef("int", "int", "i", 44),
- new TypesTestDef("bigint", "bigint", "b", 45L),
- new TypesTestDef("float", "float", "f", 46f),
- new TypesTestDef("double", "double", "d", 47d),
- new TypesTestDef("boolean", "boolean", "x", true),
- new TypesTestDef("ascii", "ascii", "a", "tqbfjutld"),
- new TypesTestDef("text", "text", "t", "k\u00f6lsche jung"),
- //new TypesTestDef(type, "frozen<" + type + '>', "u", null),
- new TypesTestDef("tuple<int, text>", "frozen<tuple<int, text>>", "tup", tuple(1, "foo"))
- };
-
- String createTableDDL = "CREATE TABLE %s (key int PRIMARY KEY";
- String insertDML = "INSERT INTO %s (key";
- List<Object> values = new ArrayList<>();
- for (TypesTestDef typeDef : typeDefs)
- {
- createTableDDL += ", " + typeDef.columnName + ' ' + typeDef.tableType;
- insertDML += ", " + typeDef.columnName;
- String typeName = typeDef.udfType;
- typeDef.fCheckArgAndReturn = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS " + typeName + ' ' +
- "LANGUAGE java\n" +
- "AS 'return val;';");
- typeDef.fCalledOnNull = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return \"called\";';");
- typeDef.fReturnsNullOnNull = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return \"called\";';");
- values.add(typeDef.referenceValue);
- }
-
- createTableDDL += ')';
- createTable(createTableDDL);
-
- insertDML += ") VALUES (1";
- for (TypesTestDef ignored : typeDefs)
- insertDML += ", ?";
- insertDML += ')';
-
- execute(insertDML, values.toArray());
-
- // second row with null values
- for (int i = 0; i < values.size(); i++)
- values.set(i, null);
- execute(insertDML.replace('1', '2'), values.toArray());
-
- // check argument input + return
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCheckArgAndReturn + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ typeDef.referenceValue }));
- }
-
- // check for CALLED ON NULL INPUT with non-null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ "called" }));
- }
-
- // check for CALLED ON NULL INPUT with null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
- row(new Object[]{ "called" }));
- }
-
- // check for RETURNS NULL ON NULL INPUT with non-null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ "called" }));
- }
-
- // check for RETURNS NULL ON NULL INPUT with null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
- row(new Object[]{ null }));
- }
-
- }
-
- @Test
public void testReplaceAllowNulls() throws Throwable
{
String fNulls = createFunction(KEYSPACE,
@@@ -1851,638 -1108,4 +860,112 @@@
}
}
}
- @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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<set<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS set<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<list<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS list<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<map<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS map<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<tuple<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, "(NULL,NULL)"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, "(1,2)"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, "(4,5)"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, "(7,8)"));
-
- functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS tuple<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
- }
-
- @Test
- public void testFunctionWithFrozenUDType() 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, 0);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<" + myType + "> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, "{f:0}"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, "{f:1}"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, "{f:4}"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, "{f:7}"));
-
- functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS " + myType + " " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
- }
+
+ @Test
+ public void testEmptyString() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, sval text, aval ascii, bval blob, empty_int int)");
+ execute("INSERT INTO %s (key, sval, aval, bval, empty_int) VALUES (?, ?, ?, ?, blobAsInt(0x))", 1, "", "", ByteBuffer.allocate(0));
+
+ String fNameSRC = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameSCC = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return \"\";'");
+
+ String fNameSRN = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameSCN = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return \"\";'");
+
+ String fNameBRC = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameBCC = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return ByteBuffer.allocate(0);'");
+
+ String fNameBRN = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameBCN = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return ByteBuffer.allocate(0);'");
+
+ String fNameIRC = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameICC = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ String fNameIRN = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameICN = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ assertRows(execute("SELECT " + fNameSRC + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRN + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCC + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCN + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRC + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRN + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCC + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCN + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameBRC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBRN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBCC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBCN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameIRC + "(empty_int) FROM %s"), row(new Object[]{ null }));
+ assertRows(execute("SELECT " + fNameIRN + "(empty_int) FROM %s"), row(new Object[]{ null }));
+ assertRows(execute("SELECT " + fNameICC + "(empty_int) FROM %s"), row(0));
+ assertRows(execute("SELECT " + fNameICN + "(empty_int) FROM %s"), row(new Object[]{ null }));
+ }
-
- @Test
- public void testAllNativeTypes() throws Throwable
- {
- StringBuilder sig = new StringBuilder();
- StringBuilder args = new StringBuilder();
- for (CQL3Type.Native type : CQL3Type.Native.values())
- {
- if (type == CQL3Type.Native.EMPTY)
- continue;
-
- if (sig.length() > 0)
- sig.append(',');
- sig.append(type.toString());
-
- if (args.length() > 0)
- args.append(',');
- args.append("arg").append(type.toString()).append(' ').append(type.toString());
- }
- createFunction(KEYSPACE, sig.toString(),
- "CREATE OR REPLACE FUNCTION %s(" + args + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- for (CQL3Type.Native type : CQL3Type.Native.values())
- {
- if (type == CQL3Type.Native.EMPTY)
- continue;
-
- createFunction(KEYSPACE_PER_TEST, type.toString(),
- "CREATE OR REPLACE FUNCTION %s(val " + type.toString() + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
- }
- }
-
- @Test
- public void testSecurityPermissions() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, dval double)");
- execute("INSERT INTO %s (key, dval) VALUES (?, ?)", 1, 1d);
-
- // Java UDFs
-
- try
- {
- 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 'System.getProperty(\"foo.bar.baz\"); return 0d;';");
- execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
- Assert.fail();
- }
- catch (FunctionExecutionException e)
- {
- assertAccessControlException("System.getProperty(\"foo.bar.baz\"); return 0d;", e);
- }
-
- String[][] typesAndSources =
- {
- {"", "try { Class.forName(\"" + UDHelper.class.getName() + "\"); } catch (Exception e) { throw new RuntimeException(e); } return 0d;"},
- {"sun.misc.Unsafe", "sun.misc.Unsafe.getUnsafe(); return 0d;"},
- {"", "try { Class.forName(\"sun.misc.Unsafe\"); } catch (Exception e) { throw new RuntimeException(e); } return 0d;"},
- {"java.nio.file.FileSystems", "try {" +
- " java.nio.file.FileSystems.getDefault(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.nio.channels.FileChannel", "try {" +
- " java.nio.channels.FileChannel.open(java.nio.file.FileSystems.getDefault().getPath(\"/etc/passwd\")).close(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.nio.channels.SocketChannel", "try {" +
- " java.nio.channels.SocketChannel.open().close(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.io.FileInputStream", "try {" +
- " new java.io.FileInputStream(\"./foobar\").close(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.lang.Runtime", "try {" +
- " java.lang.Runtime.getRuntime(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"org.apache.cassandra.service.StorageService",
- "try {" +
- " org.apache.cassandra.service.StorageService v = org.apache.cassandra.service.StorageService.instance; v.isShutdown(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.net.ServerSocket", "try {" +
- " new java.net.ServerSocket().bind(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.io.FileOutputStream","try {" +
- " new java.io.FileOutputStream(\".foo\"); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.lang.Runtime", "try {" +
- " java.lang.Runtime.getRuntime().exec(\"/tmp/foo\"); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'}
- };
-
- for (String[] typeAndSource : typesAndSources)
- {
- assertInvalidMessage(typeAndSource[0] + " cannot be resolved",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".invalid_class_access(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE JAVA\n" +
- "AS '" + typeAndSource[1] + "';");
- }
-
- // JavaScript UDFs
-
- try
- {
- String fName = createFunction(KEYSPACE_PER_TEST, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS 'org.apache.cassandra.service.StorageService.instance.isShutdown(); 0;';");
- execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
- Assert.fail("Javascript security check failed");
- }
- catch (FunctionExecutionException e)
- {
- assertAccessControlException("", e);
- }
-
- String[] javascript =
- {
- "java.lang.management.ManagmentFactory.getThreadMXBean(); 0;",
- "new java.io.FileInputStream(\"/tmp/foo\"); 0;",
- "new java.io.FileOutputStream(\"/tmp/foo\"); 0;",
- "java.nio.file.FileSystems.getDefault().createFileExclusively(\"./foo_bar_baz\"); 0;",
- "java.nio.channels.FileChannel.open(java.nio.file.FileSystems.getDefault().getPath(\"/etc/passwd\")); 0;",
- "java.nio.channels.SocketChannel.open(); 0;",
- "new java.net.ServerSocket().bind(null); 0;",
- "var thread = new java.lang.Thread(); thread.start(); 0;",
- "java.lang.System.getProperty(\"foo.bar.baz\"); 0;",
- "java.lang.Class.forName(\"java.lang.System\"); 0;",
- "java.lang.Runtime.getRuntime().exec(\"/tmp/foo\"); 0;",
- "java.lang.Runtime.getRuntime().loadLibrary(\"foobar\"); 0;",
- "java.lang.Runtime.getRuntime().loadLibrary(\"foobar\"); 0;",
- // TODO these (ugly) calls are still possible - these can consume CPU (as one could do with an evil loop, too)
- // "java.lang.Runtime.getRuntime().traceMethodCalls(true); 0;",
- // "java.lang.Runtime.getRuntime().gc(); 0;",
- // "java.lang.Runtime.getRuntime(); 0;",
- };
-
- for (String script : javascript)
- {
- try
- {
- String fName = createFunction(KEYSPACE_PER_TEST, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS '" + script + "';");
- execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
- Assert.fail("Javascript security check failed: " + script);
- }
- catch (FunctionExecutionException e)
- {
- assertAccessControlException(script, e);
- }
- }
- }
-
- private static void assertAccessControlException(String script, FunctionExecutionException e)
- {
- for (Throwable t = e; t != null && t != t.getCause(); t = t.getCause())
- if (t instanceof AccessControlException)
- return;
- Assert.fail("no AccessControlException for " + script + " (got " + e + ')');
- }
-
- @Test
- public void testAmokUDF() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, dval double)");
- execute("INSERT INTO %s (key, dval) VALUES (?, ?)", 1, 1d);
-
- long udfWarnTimeout = DatabaseDescriptor.getUserDefinedFunctionWarnTimeout();
- long udfFailTimeout = DatabaseDescriptor.getUserDefinedFunctionFailTimeout();
- int maxTries = 5;
- for (int i = 1; i <= maxTries; i++)
- {
- try
- {
- // short timeout
- DatabaseDescriptor.setUserDefinedFunctionWarnTimeout(10);
- DatabaseDescriptor.setUserDefinedFunctionFailTimeout(250);
- // don't kill the unit test... - default policy is "die"
- DatabaseDescriptor.setUserFunctionTimeoutPolicy(Config.UserFunctionTimeoutPolicy.ignore);
-
- ClientWarn.instance.captureWarnings();
- 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 'long t=System.currentTimeMillis()+110; while (t>System.currentTimeMillis()) { }; return 0d;'");
- execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
- List<String> warnings = ClientWarn.instance.getWarnings();
- Assert.assertNotNull(warnings);
- Assert.assertFalse(warnings.isEmpty());
- ClientWarn.instance.resetWarnings();
-
- // Java UDF
-
- fName = createFunction(KEYSPACE_PER_TEST, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE JAVA\n" +
- "AS 'long t=System.currentTimeMillis()+500; while (t>System.currentTimeMillis()) { }; return 0d;';");
- assertInvalidMessage("ran longer than 250ms", "SELECT " + fName + "(dval) FROM %s WHERE key=1");
-
- // Javascript UDF
-
- fName = createFunction(KEYSPACE_PER_TEST, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE JAVASCRIPT\n" +
- "AS 'var t=java.lang.System.currentTimeMillis()+500; while (t>java.lang.System.currentTimeMillis()) { }; 0;';");
- assertInvalidMessage("ran longer than 250ms", "SELECT " + fName + "(dval) FROM %s WHERE key=1");
-
- return;
- }
- catch (Error | RuntimeException e)
- {
- if (i == maxTries)
- throw e;
- }
- finally
- {
- // reset to defaults
- DatabaseDescriptor.setUserDefinedFunctionWarnTimeout(udfWarnTimeout);
- DatabaseDescriptor.setUserDefinedFunctionFailTimeout(udfFailTimeout);
- }
- }
- }
}
[20/25] 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/3aefe356
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/3aefe356
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/3aefe356
Branch: refs/heads/trunk
Commit: 3aefe356545bcc2f5c4453e0d9d704bef339a008
Parents: 95d0b67 0b97c5d
Author: Robert Stupp <sn...@snazy.de>
Authored: Wed Dec 7 13:08:35 2016 +0100
Committer: Robert Stupp <sn...@snazy.de>
Committed: Wed Dec 7 13:08:35 2016 +0100
----------------------------------------------------------------------
.../cql3/validation/entities/UFJavaTest.java | 797 +++++++++
.../validation/entities/UFPureScriptTest.java | 406 -----
.../cql3/validation/entities/UFScriptTest.java | 428 +++++
.../validation/entities/UFSecurityTest.java | 258 +++
.../cql3/validation/entities/UFTest.java | 1519 +-----------------
.../cql3/validation/entities/UFTypesTest.java | 549 +++++++
6 files changed, 2033 insertions(+), 1924 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/3aefe356/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
index 0000000,caef808..15c8e18
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
@@@ -1,0 -1,1177 +1,797 @@@
+ /*
+ * 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.nio.ByteBuffer;
+ import java.util.Arrays;
+ import java.util.List;
+ import java.util.Map;
+ import java.util.Set;
+ import java.util.TreeMap;
+ import java.util.TreeSet;
+
+ 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 org.apache.cassandra.config.DatabaseDescriptor;
++import org.apache.cassandra.config.Schema;
+ import org.apache.cassandra.cql3.CQL3Type;
+ import org.apache.cassandra.cql3.CQLTester;
+ import org.apache.cassandra.cql3.UntypedResultSet;
+ import org.apache.cassandra.cql3.functions.FunctionName;
-import org.apache.cassandra.cql3.functions.Functions;
-import org.apache.cassandra.dht.ByteOrderedPartitioner;
+ import org.apache.cassandra.exceptions.FunctionExecutionException;
+ import org.apache.cassandra.exceptions.InvalidRequestException;
+ import org.apache.cassandra.transport.Server;
-import org.apache.cassandra.utils.ByteBufferUtil;
+
+ public class UFJavaTest extends CQLTester
+ {
- @BeforeClass
- public static void setUp()
- {
- DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance);
- }
-
-
+ @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=?",
++ 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=?",
++ 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 testJavaFunctionCounter() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val counter)");
+
+ String fName = createFunction(KEYSPACE, "counter",
+ "CREATE OR REPLACE FUNCTION %s(val counter) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS bigint " +
+ "LANGUAGE JAVA " +
+ "AS 'return val + 1;';");
+
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1L, 2L));
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ execute("UPDATE %s SET val = val + 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 4L, 5L));
+ execute("UPDATE %s SET val = val - 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ }
+
+ @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=?",
++ 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=?",
++ 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=?",
++ 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++)
++ for (int version : PROTOCOL_VERSIONS)
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fList + "(lst), " + fSet + "(st), " + fMap + "(mp) FROM %s WHERE key = 1"),
+ row(list, set, map));
+ }
+
+ @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()));
++ // same test - but via native protocol
++ // we use protocol V3 here to encode the expected version because the server
++ // always serializes Collections using V3 - see CollectionSerializer's
++ // serialize and deserialize methods.
++ TupleType tType = tupleTypeOf(Server.VERSION_3,
++ 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++)
++ for (int version : PROTOCOL_VERSIONS)
+ {
+ 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++)
++ for (int version : PROTOCOL_VERSIONS)
+ {
+ 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++)
++ for (int version : PROTOCOL_VERSIONS)
+ {
+ 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 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());
++ Assert.assertEquals(1, Schema.instance.getFunctions(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());
++ Assert.assertEquals(1, Schema.instance.getFunctions(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());
++ Assert.assertEquals(1, Schema.instance.getFunctions(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());
++ Assert.assertEquals(1, Schema.instance.getFunctions(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++)
++ for (int version : PROTOCOL_VERSIONS)
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fName1 + "(lst), " + fName2 + "(st), " + fName3 + "(mp) FROM %s WHERE key = 1"),
+ row("three", "one", "two"));
+ }
+
+ @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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<set<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS set<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<list<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS list<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<map<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS map<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<tuple<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, "(null, null)"),
- row(1, "(1, 2)"),
- row(2, "(4, 5)"),
- row(3, "(7, 8)"));
-
- functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS tuple<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
- }
-
- @Test
- public void testFunctionWithFrozenUDType() 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, 0);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<" + myType + "> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, "{f:0}"),
- row(1, "{f:1}"),
- row(2, "{f:4}"),
- row(3, "{f:7}"));
-
- functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS " + myType + " " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
- }
-
- @Test
- public void testEmptyString() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, sval text, aval ascii, bval blob, empty_int int)");
- execute("INSERT INTO %s (key, sval, aval, bval, empty_int) VALUES (?, ?, ?, ?, blobAsInt(0x))", 1, "", "", ByteBuffer.allocate(0));
-
- String fNameSRC = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameSCC = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return \"\";'");
-
- String fNameSRN = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameSCN = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return \"\";'");
-
- String fNameBRC = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "CALLED ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameBCC = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "CALLED ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return ByteBuffer.allocate(0);'");
-
- String fNameBRN = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameBCN = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return ByteBuffer.allocate(0);'");
-
- String fNameIRC = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameICC = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- String fNameIRN = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameICN = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- assertRows(execute("SELECT " + fNameSRC + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRN + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCC + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCN + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRC + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRN + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCC + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCN + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameBRC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBRN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBCC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBCN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameIRC + "(empty_int) FROM %s"), row(new Object[]{null}));
- assertRows(execute("SELECT " + fNameIRN + "(empty_int) FROM %s"), row(new Object[]{null}));
- assertRows(execute("SELECT " + fNameICC + "(empty_int) FROM %s"), row(0));
- assertRows(execute("SELECT " + fNameICN + "(empty_int) FROM %s"), row(new Object[]{null}));
- }
-
- @Test
+ public void testAllNativeTypes() throws Throwable
+ {
+ StringBuilder sig = new StringBuilder();
+ StringBuilder args = new StringBuilder();
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
++ if (type == CQL3Type.Native.EMPTY)
++ continue;
++
+ if (sig.length() > 0)
+ sig.append(',');
+ sig.append(type.toString());
+
+ if (args.length() > 0)
+ args.append(',');
+ args.append("arg").append(type.toString()).append(' ').append(type.toString());
+ }
+ createFunction(KEYSPACE, sig.toString(),
+ "CREATE OR REPLACE FUNCTION %s(" + args + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
++ if (type == CQL3Type.Native.EMPTY)
++ continue;
++
+ createFunction(KEYSPACE_PER_TEST, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type.toString() + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+ }
+ }
+ }
[25/25] cassandra git commit: Merge branch 'cassandra-3.X' into trunk
Posted by sn...@apache.org.
Merge branch 'cassandra-3.X' into trunk
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/d2a92e4b
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/d2a92e4b
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/d2a92e4b
Branch: refs/heads/trunk
Commit: d2a92e4b154cf4d2cb87a8731e6101031fba78c2
Parents: 8253912 d7b6b7a
Author: Robert Stupp <sn...@snazy.de>
Authored: Wed Dec 7 13:24:08 2016 +0100
Committer: Robert Stupp <sn...@snazy.de>
Committed: Wed Dec 7 13:24:08 2016 +0100
----------------------------------------------------------------------
.../cql3/validation/entities/UFJavaTest.java | 798 ++++++++
.../validation/entities/UFPureScriptTest.java | 407 ----
.../cql3/validation/entities/UFScriptTest.java | 429 +++++
.../validation/entities/UFSecurityTest.java | 258 +++
.../cql3/validation/entities/UFTest.java | 1739 +-----------------
.../cql3/validation/entities/UFTypesTest.java | 550 ++++++
6 files changed, 2036 insertions(+), 2145 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/d2a92e4b/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
index 0000000,4d46b8b..a7c09b1
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
@@@ -1,0 -1,797 +1,798 @@@
+ /*
+ * 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.util.Arrays;
+ import java.util.List;
+ import java.util.Map;
+ import java.util.Set;
+ import java.util.TreeMap;
+ import java.util.TreeSet;
+
+ import org.junit.Assert;
+ 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 org.apache.cassandra.config.Schema;
+ import org.apache.cassandra.cql3.CQL3Type;
+ import org.apache.cassandra.cql3.CQLTester;
+ import org.apache.cassandra.cql3.UntypedResultSet;
+ import org.apache.cassandra.cql3.functions.FunctionName;
+ import org.apache.cassandra.exceptions.FunctionExecutionException;
+ import org.apache.cassandra.exceptions.InvalidRequestException;
+ import org.apache.cassandra.transport.ProtocolVersion;
++import org.apache.cassandra.transport.Server;
+
+ public class UFJavaTest extends CQLTester
+ {
+ @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 testJavaFunctionCounter() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val counter)");
+
+ String fName = createFunction(KEYSPACE, "counter",
+ "CREATE OR REPLACE FUNCTION %s(val counter) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS bigint " +
+ "LANGUAGE JAVA " +
+ "AS 'return val + 1;';");
+
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1L, 2L));
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ execute("UPDATE %s SET val = val + 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 4L, 5L));
+ execute("UPDATE %s SET val = val - 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ }
+
+ @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 (ProtocolVersion version : PROTOCOL_VERSIONS)
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fList + "(lst), " + fSet + "(st), " + fMap + "(mp) FROM %s WHERE key = 1"),
+ row(list, set, map));
+ }
+
+ @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));
+
+ // same test - but via native protocol
+ // we use protocol V3 here to encode the expected version because the server
+ // always serializes Collections using V3 - see CollectionSerializer's
+ // serialize and deserialize methods.
+ TupleType tType = tupleTypeOf(ProtocolVersion.V3,
+ 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 (ProtocolVersion version : PROTOCOL_VERSIONS)
+ {
+ 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 (ProtocolVersion version : PROTOCOL_VERSIONS)
+ {
+ 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 (ProtocolVersion version : PROTOCOL_VERSIONS)
+ {
+ 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 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, Schema.instance.getFunctions(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, Schema.instance.getFunctions(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, Schema.instance.getFunctions(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, Schema.instance.getFunctions(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 (ProtocolVersion version : PROTOCOL_VERSIONS)
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fName1 + "(lst), " + fName2 + "(st), " + fName3 + "(mp) FROM %s WHERE key = 1"),
+ row("three", "one", "two"));
+ }
+
+ @Test
+ public void testAllNativeTypes() throws Throwable
+ {
+ StringBuilder sig = new StringBuilder();
+ StringBuilder args = new StringBuilder();
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
+ if (type == CQL3Type.Native.EMPTY)
+ continue;
+
+ if (sig.length() > 0)
+ sig.append(',');
+ sig.append(type.toString());
+
+ if (args.length() > 0)
+ args.append(',');
+ args.append("arg").append(type.toString()).append(' ').append(type.toString());
+ }
+ createFunction(KEYSPACE, sig.toString(),
+ "CREATE OR REPLACE FUNCTION %s(" + args + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
+ if (type == CQL3Type.Native.EMPTY)
+ continue;
+
+ createFunction(KEYSPACE_PER_TEST, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type.toString() + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+ }
+ }
+ }
[14/25] 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/3aefe356/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
index c52e178,d4d2a10..8a743ea
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
@@@ -17,44 -17,37 +17,29 @@@
*/
package org.apache.cassandra.cql3.validation.entities;
+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 java.security.AccessControlException;
import org.junit.Assert;
-import org.junit.BeforeClass;
import org.junit.Test;
- import com.datastax.driver.core.*;
-import com.datastax.driver.core.Row;
import com.datastax.driver.core.exceptions.InvalidQueryException;
--import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.config.Schema;
- 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.config.Config;
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.cql3.functions.UDHelper;
import org.apache.cassandra.db.marshal.CollectionType;
- import org.apache.cassandra.exceptions.FunctionExecutionException;
-import org.apache.cassandra.dht.ByteOrderedPartitioner;
import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.schema.KeyspaceMetadata;
import org.apache.cassandra.service.ClientState;
- import org.apache.cassandra.service.ClientWarn;
import org.apache.cassandra.transport.Event;
import org.apache.cassandra.transport.Server;
import org.apache.cassandra.transport.messages.ResultMessage;
-import org.apache.cassandra.utils.UUIDGen;
+import org.apache.cassandra.utils.ByteBufferUtil;
- import org.apache.cassandra.utils.UUIDGen;
public class UFTest extends CQLTester
{
@@@ -1017,320 -724,115 +710,6 @@@
}
@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 : PROTOCOL_VERSIONS)
- 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));
-
- // same test - but via native protocol
- // we use protocol V3 here to encode the expected version because the server
- // always serializes Collections using V3 - see CollectionSerializer's
- // serialize and deserialize methods.
- TupleType tType = tupleTypeOf(Server.VERSION_3,
- 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 : PROTOCOL_VERSIONS)
- {
- 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 : PROTOCOL_VERSIONS)
- {
- 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 : PROTOCOL_VERSIONS)
- {
- 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)");
@@@ -1593,162 -880,140 +757,7 @@@
"AS '\"foo bar\";';");
}
- private static class TypesTestDef
- {
- final String udfType;
- final String tableType;
- final String columnName;
- final Object referenceValue;
-
- String fCheckArgAndReturn;
-
- String fCalledOnNull;
- String fReturnsNullOnNull;
-
- TypesTestDef(String udfType, String tableType, String columnName, Object referenceValue)
- {
- this.udfType = udfType;
- this.tableType = tableType;
- this.columnName = columnName;
- this.referenceValue = referenceValue;
- }
- }
-
- @Test
- public void testTypesWithAndWithoutNulls() throws Throwable
- {
- // test various combinations of types against UDFs with CALLED ON NULL or RETURNS NULL ON NULL
-
- String type = createType("CREATE TYPE %s (txt text, i int)");
-
- TypesTestDef[] typeDefs =
- {
- // udf type, table type, column, reference value
- new TypesTestDef("timestamp", "timestamp", "ts", new Date()),
- new TypesTestDef("date", "date", "dt", 12345),
- new TypesTestDef("time", "time", "tim", 12345L),
- new TypesTestDef("uuid", "uuid", "uu", UUID.randomUUID()),
- new TypesTestDef("timeuuid", "timeuuid", "tu", UUIDGen.getTimeUUID()),
- new TypesTestDef("tinyint", "tinyint", "ti", (byte) 42),
- new TypesTestDef("smallint", "smallint", "si", (short) 43),
- new TypesTestDef("int", "int", "i", 44),
- new TypesTestDef("bigint", "bigint", "b", 45L),
- new TypesTestDef("float", "float", "f", 46f),
- new TypesTestDef("double", "double", "d", 47d),
- new TypesTestDef("boolean", "boolean", "x", true),
- new TypesTestDef("ascii", "ascii", "a", "tqbfjutld"),
- new TypesTestDef("text", "text", "t", "k\u00f6lsche jung"),
- //new TypesTestDef(type, "frozen<" + type + '>', "u", null),
- new TypesTestDef("tuple<int, text>", "frozen<tuple<int, text>>", "tup", tuple(1, "foo"))
- };
-
- String createTableDDL = "CREATE TABLE %s (key int PRIMARY KEY";
- String insertDML = "INSERT INTO %s (key";
- List<Object> values = new ArrayList<>();
- for (TypesTestDef typeDef : typeDefs)
- {
- createTableDDL += ", " + typeDef.columnName + ' ' + typeDef.tableType;
- insertDML += ", " + typeDef.columnName;
- String typeName = typeDef.udfType;
- typeDef.fCheckArgAndReturn = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS " + typeName + ' ' +
- "LANGUAGE java\n" +
- "AS 'return val;';");
- typeDef.fCalledOnNull = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return \"called\";';");
- typeDef.fReturnsNullOnNull = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return \"called\";';");
- values.add(typeDef.referenceValue);
- }
-
- createTableDDL += ')';
- createTable(createTableDDL);
-
- insertDML += ") VALUES (1";
- for (TypesTestDef ignored : typeDefs)
- insertDML += ", ?";
- insertDML += ')';
-
- execute(insertDML, values.toArray());
-
- // second row with null values
- for (int i = 0; i < values.size(); i++)
- values.set(i, null);
- execute(insertDML.replace('1', '2'), values.toArray());
-
- // check argument input + return
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCheckArgAndReturn + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ typeDef.referenceValue }));
- }
-
- // check for CALLED ON NULL INPUT with non-null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ "called" }));
- }
-
- // check for CALLED ON NULL INPUT with null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
- row(new Object[]{ "called" }));
- }
-
- // check for RETURNS NULL ON NULL INPUT with non-null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ "called" }));
- }
-
- // check for RETURNS NULL ON NULL INPUT with null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
- row(new Object[]{ null }));
- }
-
- }
-
@Test
- public void testJavascriptCompileFailure() throws Throwable
- {
- assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS 'foo bar';");
- }
-
- @Test
- public void testScriptInvalidLanguage() throws Throwable
- {
- assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE artificial_intelligence\n" +
- "AS 'question for 42?';");
- }
-
- static class TypesTestDef
- {
- final String udfType;
- final String tableType;
- final String columnName;
- final Object referenceValue;
-
- String fCheckArgAndReturn;
-
- String fCalledOnNull;
- String fReturnsNullOnNull;
-
- TypesTestDef(String udfType, String tableType, String columnName, Object referenceValue)
- {
- this.udfType = udfType;
- this.tableType = tableType;
- this.columnName = columnName;
- this.referenceValue = referenceValue;
- }
- }
-
- @Test
- public void testTypesWithAndWithoutNulls() throws Throwable
- {
- // test various combinations of types against UDFs with CALLED ON NULL or RETURNS NULL ON NULL
-
- String type = createType("CREATE TYPE %s (txt text, i int)");
-
- TypesTestDef[] typeDefs =
- {
- // udf type, table type, column, reference value
- new TypesTestDef("timestamp", "timestamp", "ts", new Date()),
- new TypesTestDef("date", "date", "dt", 12345),
- new TypesTestDef("time", "time", "tim", 12345L),
- new TypesTestDef("uuid", "uuid", "uu", UUID.randomUUID()),
- new TypesTestDef("timeuuid", "timeuuid", "tu", UUIDGen.getTimeUUID()),
- new TypesTestDef("tinyint", "tinyint", "ti", (byte) 42),
- new TypesTestDef("smallint", "smallint", "si", (short) 43),
- new TypesTestDef("int", "int", "i", 44),
- new TypesTestDef("bigint", "bigint", "b", 45L),
- new TypesTestDef("float", "float", "f", 46f),
- new TypesTestDef("double", "double", "d", 47d),
- new TypesTestDef("boolean", "boolean", "x", true),
- new TypesTestDef("ascii", "ascii", "a", "tqbfjutld"),
- new TypesTestDef("text", "text", "t", "k\u00f6lsche jung"),
- //new TypesTestDef(type, "frozen<" + type + '>', "u", null),
- new TypesTestDef("tuple<int, text>", "frozen<tuple<int, text>>", "tup", tuple(1, "foo"))
- };
-
- String createTableDDL = "CREATE TABLE %s (key int PRIMARY KEY";
- String insertDML = "INSERT INTO %s (key";
- List<Object> values = new ArrayList<>();
- for (TypesTestDef typeDef : typeDefs)
- {
- createTableDDL += ", " + typeDef.columnName + ' ' + typeDef.tableType;
- insertDML += ", " + typeDef.columnName;
- String typeName = typeDef.udfType;
- typeDef.fCheckArgAndReturn = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS " + typeName + ' ' +
- "LANGUAGE java\n" +
- "AS 'return val;';");
- typeDef.fCalledOnNull = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return \"called\";';");
- typeDef.fReturnsNullOnNull = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return \"called\";';");
- values.add(typeDef.referenceValue);
- }
-
- createTableDDL += ')';
- createTable(createTableDDL);
-
- insertDML += ") VALUES (1";
- for (TypesTestDef ignored : typeDefs)
- insertDML += ", ?";
- insertDML += ')';
-
- execute(insertDML, values.toArray());
-
- // second row with null values
- for (int i = 0; i < values.size(); i++)
- values.set(i, null);
- execute(insertDML.replace('1', '2'), values.toArray());
-
- // check argument input + return
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCheckArgAndReturn + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ typeDef.referenceValue }));
- }
-
- // check for CALLED ON NULL INPUT with non-null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ "called" }));
- }
-
- // check for CALLED ON NULL INPUT with null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
- row(new Object[]{ "called" }));
- }
-
- // check for RETURNS NULL ON NULL INPUT with non-null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ "called" }));
- }
-
- // check for RETURNS NULL ON NULL INPUT with null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
- row(new Object[]{ null }));
- }
-
- }
-
- @Test
public void testReplaceAllowNulls() throws Throwable
{
String fNulls = createFunction(KEYSPACE,
@@@ -1851,638 -1108,4 +860,112 @@@
}
}
}
- @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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<set<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS set<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<list<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS list<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<map<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS map<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<tuple<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, "(NULL,NULL)"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, "(1,2)"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, "(4,5)"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, "(7,8)"));
-
- functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS tuple<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
- }
-
- @Test
- public void testFunctionWithFrozenUDType() 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, 0);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<" + myType + "> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, "{f:0}"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, "{f:1}"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, "{f:4}"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, "{f:7}"));
-
- functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS " + myType + " " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
- }
+
+ @Test
+ public void testEmptyString() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, sval text, aval ascii, bval blob, empty_int int)");
+ execute("INSERT INTO %s (key, sval, aval, bval, empty_int) VALUES (?, ?, ?, ?, blobAsInt(0x))", 1, "", "", ByteBuffer.allocate(0));
+
+ String fNameSRC = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameSCC = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return \"\";'");
+
+ String fNameSRN = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameSCN = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return \"\";'");
+
+ String fNameBRC = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameBCC = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return ByteBuffer.allocate(0);'");
+
+ String fNameBRN = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameBCN = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return ByteBuffer.allocate(0);'");
+
+ String fNameIRC = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameICC = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ String fNameIRN = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameICN = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ assertRows(execute("SELECT " + fNameSRC + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRN + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCC + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCN + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRC + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRN + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCC + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCN + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameBRC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBRN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBCC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBCN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameIRC + "(empty_int) FROM %s"), row(new Object[]{ null }));
+ assertRows(execute("SELECT " + fNameIRN + "(empty_int) FROM %s"), row(new Object[]{ null }));
+ assertRows(execute("SELECT " + fNameICC + "(empty_int) FROM %s"), row(0));
+ assertRows(execute("SELECT " + fNameICN + "(empty_int) FROM %s"), row(new Object[]{ null }));
+ }
-
- @Test
- public void testAllNativeTypes() throws Throwable
- {
- StringBuilder sig = new StringBuilder();
- StringBuilder args = new StringBuilder();
- for (CQL3Type.Native type : CQL3Type.Native.values())
- {
- if (type == CQL3Type.Native.EMPTY)
- continue;
-
- if (sig.length() > 0)
- sig.append(',');
- sig.append(type.toString());
-
- if (args.length() > 0)
- args.append(',');
- args.append("arg").append(type.toString()).append(' ').append(type.toString());
- }
- createFunction(KEYSPACE, sig.toString(),
- "CREATE OR REPLACE FUNCTION %s(" + args + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- for (CQL3Type.Native type : CQL3Type.Native.values())
- {
- if (type == CQL3Type.Native.EMPTY)
- continue;
-
- createFunction(KEYSPACE_PER_TEST, type.toString(),
- "CREATE OR REPLACE FUNCTION %s(val " + type.toString() + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
- }
- }
-
- @Test
- public void testSecurityPermissions() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, dval double)");
- execute("INSERT INTO %s (key, dval) VALUES (?, ?)", 1, 1d);
-
- // Java UDFs
-
- try
- {
- 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 'System.getProperty(\"foo.bar.baz\"); return 0d;';");
- execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
- Assert.fail();
- }
- catch (FunctionExecutionException e)
- {
- assertAccessControlException("System.getProperty(\"foo.bar.baz\"); return 0d;", e);
- }
-
- String[][] typesAndSources =
- {
- {"", "try { Class.forName(\"" + UDHelper.class.getName() + "\"); } catch (Exception e) { throw new RuntimeException(e); } return 0d;"},
- {"sun.misc.Unsafe", "sun.misc.Unsafe.getUnsafe(); return 0d;"},
- {"", "try { Class.forName(\"sun.misc.Unsafe\"); } catch (Exception e) { throw new RuntimeException(e); } return 0d;"},
- {"java.nio.file.FileSystems", "try {" +
- " java.nio.file.FileSystems.getDefault(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.nio.channels.FileChannel", "try {" +
- " java.nio.channels.FileChannel.open(java.nio.file.FileSystems.getDefault().getPath(\"/etc/passwd\")).close(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.nio.channels.SocketChannel", "try {" +
- " java.nio.channels.SocketChannel.open().close(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.io.FileInputStream", "try {" +
- " new java.io.FileInputStream(\"./foobar\").close(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.lang.Runtime", "try {" +
- " java.lang.Runtime.getRuntime(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"org.apache.cassandra.service.StorageService",
- "try {" +
- " org.apache.cassandra.service.StorageService v = org.apache.cassandra.service.StorageService.instance; v.isShutdown(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.net.ServerSocket", "try {" +
- " new java.net.ServerSocket().bind(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.io.FileOutputStream","try {" +
- " new java.io.FileOutputStream(\".foo\"); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.lang.Runtime", "try {" +
- " java.lang.Runtime.getRuntime().exec(\"/tmp/foo\"); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'}
- };
-
- for (String[] typeAndSource : typesAndSources)
- {
- assertInvalidMessage(typeAndSource[0] + " cannot be resolved",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".invalid_class_access(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE JAVA\n" +
- "AS '" + typeAndSource[1] + "';");
- }
-
- // JavaScript UDFs
-
- try
- {
- String fName = createFunction(KEYSPACE_PER_TEST, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS 'org.apache.cassandra.service.StorageService.instance.isShutdown(); 0;';");
- execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
- Assert.fail("Javascript security check failed");
- }
- catch (FunctionExecutionException e)
- {
- assertAccessControlException("", e);
- }
-
- String[] javascript =
- {
- "java.lang.management.ManagmentFactory.getThreadMXBean(); 0;",
- "new java.io.FileInputStream(\"/tmp/foo\"); 0;",
- "new java.io.FileOutputStream(\"/tmp/foo\"); 0;",
- "java.nio.file.FileSystems.getDefault().createFileExclusively(\"./foo_bar_baz\"); 0;",
- "java.nio.channels.FileChannel.open(java.nio.file.FileSystems.getDefault().getPath(\"/etc/passwd\")); 0;",
- "java.nio.channels.SocketChannel.open(); 0;",
- "new java.net.ServerSocket().bind(null); 0;",
- "var thread = new java.lang.Thread(); thread.start(); 0;",
- "java.lang.System.getProperty(\"foo.bar.baz\"); 0;",
- "java.lang.Class.forName(\"java.lang.System\"); 0;",
- "java.lang.Runtime.getRuntime().exec(\"/tmp/foo\"); 0;",
- "java.lang.Runtime.getRuntime().loadLibrary(\"foobar\"); 0;",
- "java.lang.Runtime.getRuntime().loadLibrary(\"foobar\"); 0;",
- // TODO these (ugly) calls are still possible - these can consume CPU (as one could do with an evil loop, too)
- // "java.lang.Runtime.getRuntime().traceMethodCalls(true); 0;",
- // "java.lang.Runtime.getRuntime().gc(); 0;",
- // "java.lang.Runtime.getRuntime(); 0;",
- };
-
- for (String script : javascript)
- {
- try
- {
- String fName = createFunction(KEYSPACE_PER_TEST, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS '" + script + "';");
- execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
- Assert.fail("Javascript security check failed: " + script);
- }
- catch (FunctionExecutionException e)
- {
- assertAccessControlException(script, e);
- }
- }
- }
-
- private static void assertAccessControlException(String script, FunctionExecutionException e)
- {
- for (Throwable t = e; t != null && t != t.getCause(); t = t.getCause())
- if (t instanceof AccessControlException)
- return;
- Assert.fail("no AccessControlException for " + script + " (got " + e + ')');
- }
-
- @Test
- public void testAmokUDF() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, dval double)");
- execute("INSERT INTO %s (key, dval) VALUES (?, ?)", 1, 1d);
-
- long udfWarnTimeout = DatabaseDescriptor.getUserDefinedFunctionWarnTimeout();
- long udfFailTimeout = DatabaseDescriptor.getUserDefinedFunctionFailTimeout();
- int maxTries = 5;
- for (int i = 1; i <= maxTries; i++)
- {
- try
- {
- // short timeout
- DatabaseDescriptor.setUserDefinedFunctionWarnTimeout(10);
- DatabaseDescriptor.setUserDefinedFunctionFailTimeout(250);
- // don't kill the unit test... - default policy is "die"
- DatabaseDescriptor.setUserFunctionTimeoutPolicy(Config.UserFunctionTimeoutPolicy.ignore);
-
- ClientWarn.instance.captureWarnings();
- 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 'long t=System.currentTimeMillis()+110; while (t>System.currentTimeMillis()) { }; return 0d;'");
- execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
- List<String> warnings = ClientWarn.instance.getWarnings();
- Assert.assertNotNull(warnings);
- Assert.assertFalse(warnings.isEmpty());
- ClientWarn.instance.resetWarnings();
-
- // Java UDF
-
- fName = createFunction(KEYSPACE_PER_TEST, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE JAVA\n" +
- "AS 'long t=System.currentTimeMillis()+500; while (t>System.currentTimeMillis()) { }; return 0d;';");
- assertInvalidMessage("ran longer than 250ms", "SELECT " + fName + "(dval) FROM %s WHERE key=1");
-
- // Javascript UDF
-
- fName = createFunction(KEYSPACE_PER_TEST, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE JAVASCRIPT\n" +
- "AS 'var t=java.lang.System.currentTimeMillis()+500; while (t>java.lang.System.currentTimeMillis()) { }; 0;';");
- assertInvalidMessage("ran longer than 250ms", "SELECT " + fName + "(dval) FROM %s WHERE key=1");
-
- return;
- }
- catch (Error | RuntimeException e)
- {
- if (i == maxTries)
- throw e;
- }
- finally
- {
- // reset to defaults
- DatabaseDescriptor.setUserDefinedFunctionWarnTimeout(udfWarnTimeout);
- DatabaseDescriptor.setUserDefinedFunctionFailTimeout(udfFailTimeout);
- }
- }
- }
}
[07/25] cassandra git commit: testall failure in
org.apache.cassandra.cql3.validation.entities.UFTest.testAllNativeTypes
Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0b97c5d1/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
index bcfe871..d4d2a10 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
@@ -17,9 +17,6 @@
*/
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;
@@ -34,14 +31,9 @@ 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;
@@ -50,13 +42,11 @@ 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
@@ -295,7 +285,7 @@ public class UFTest extends CQLTester
return prepared;
}
- public void checkDelayedValuesCorrectlyIdentifyFunctionsInUse(boolean dropKeyspace) throws Throwable
+ private void checkDelayedValuesCorrectlyIdentifyFunctionsInUse(boolean dropKeyspace) throws Throwable
{
// prepare a statement which doesn't use any function for a control
createTable("CREATE TABLE %s (" +
@@ -584,164 +574,6 @@ public class UFTest extends CQLTester
}
@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 testJavaFunctionCounter() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val counter)");
-
- String fName = createFunction(KEYSPACE, "counter",
- "CREATE OR REPLACE FUNCTION %s(val counter) " +
- "CALLED ON NULL INPUT " +
- "RETURNS bigint " +
- "LANGUAGE JAVA " +
- "AS 'return val + 1;';");
-
- execute("UPDATE %s SET val = val + 1 WHERE key = 1");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 1L, 2L));
- execute("UPDATE %s SET val = val + 1 WHERE key = 1");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 2L, 3L));
- execute("UPDATE %s SET val = val + 2 WHERE key = 1");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 4L, 5L));
- execute("UPDATE %s SET val = val - 2 WHERE key = 1");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 2L, 3L));
- }
-
- @Test
public void testFunctionInTargetKeyspace() throws Throwable
{
createTable("CREATE TABLE %s (key int primary key, val double)");
@@ -869,140 +701,6 @@ public class UFTest extends CQLTester
}
@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)");
@@ -1135,206 +833,6 @@ public class UFTest extends CQLTester
}
@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)");
@@ -1372,686 +870,22 @@ public class UFTest extends CQLTester
}
@Test
- public void testJavaUserTypeRenameField() throws Throwable
+ public void testDuplicateArgNames() throws Throwable
{
- String type = KEYSPACE + '.' + createType("CREATE TYPE %s (txt text, i int)");
+ assertInvalidMessage("duplicate argument names for given function",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double, val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS '\"foo bar\";';");
+ }
- 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"),
- row(1d));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup3 + "(tup) FROM %s WHERE key = 1"),
- row(list));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup4 + "(tup) FROM %s WHERE key = 1"),
- row(set));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup5 + "(tup) FROM %s WHERE key = 1"),
- row(map));
- }
- }
-
- @Test
- public void testJavascriptUserType() throws Throwable
- {
- String type = createType("CREATE TYPE %s (txt text, i int)");
-
- createTable("CREATE TABLE %s (key int primary key, udt frozen<" + type + ">)");
-
- String fUdt1 = createFunction(KEYSPACE, type,
- "CREATE FUNCTION %s( udt " + type + " ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS " + type + " " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " udt;$$;");
- String fUdt2 = createFunction(KEYSPACE, type,
- "CREATE FUNCTION %s( udt " + type + " ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " udt.getString(\"txt\");$$;");
- String fUdt3 = createFunction(KEYSPACE, type,
- "CREATE FUNCTION %s( udt " + type + " ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " udt.getInt(\"i\");$$;");
-
- execute("INSERT INTO %s (key, udt) VALUES (1, {txt: 'one', i:1})");
-
- UntypedResultSet rows = execute("SELECT " + fUdt1 + "(udt) FROM %s WHERE key = 1");
- Assert.assertEquals(1, rows.size());
- assertRows(execute("SELECT " + fUdt2 + "(udt) FROM %s WHERE key = 1"),
- row("one"));
- assertRows(execute("SELECT " + fUdt3 + "(udt) FROM %s WHERE key = 1"),
- row(1));
- }
-
- @Test
- public void testJavascriptUTCollections() throws Throwable
- {
- String type = 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 fName = createFunction(KEYSPACE, "list<frozen<" + type + ">>",
- "CREATE FUNCTION %s( lst list<frozen<" + type + ">> ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " lst.get(1).getString(\"txt\");$$;");
- createFunctionOverload(fName, "set<frozen<" + type + ">>",
- "CREATE FUNCTION %s( st set<frozen<" + type + ">> ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " st.iterator().next().getString(\"txt\");$$;");
- createFunctionOverload(fName, "map<int, frozen<" + type + ">>",
- "CREATE FUNCTION %s( mp map<int, frozen<" + type + ">> ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " mp.get(java.lang.Integer.valueOf(3)).getString(\"txt\");$$;");
-
- execute("INSERT INTO %s (key, lst, st, mp) values (1, " +
- // list<frozen<UDT>>
- "[ {txt: 'one', i:1}, {txt: 'three', i:1}, {txt: 'one', i:1} ] , " +
- // set<frozen<UDT>>
- "{ {txt: 'one', i:1}, {txt: 'three', i:3}, {txt: 'two', i:2} }, " +
- // map<int, frozen<UDT>>
- "{ 1: {txt: 'one', i:1}, 2: {txt: 'one', i:3}, 3: {txt: 'two', i:2} })");
-
- assertRows(execute("SELECT " + fName + "(lst) FROM %s WHERE key = 1"),
- row("three"));
- assertRows(execute("SELECT " + fName + "(st) FROM %s WHERE key = 1"),
- row("one"));
- assertRows(execute("SELECT " + fName + "(mp) FROM %s WHERE key = 1"),
- row("two"));
-
- String cqlSelect = "SELECT " + fName + "(lst), " + fName + "(st), " + fName + "(mp) FROM %s WHERE key = 1";
- assertRows(execute(cqlSelect),
- row("three", "one", "two"));
-
- // same test - but via native protocol
- for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
- assertRowsNet(version,
- executeNet(version, cqlSelect),
- row("three", "one", "two"));
- }
-
- @Test
- public void testJavascriptFunction() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val double)");
-
- String functionBody = '\n' +
- " Math.sin(val);\n";
-
- String fName = createFunction(KEYSPACE, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\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("javascript", 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 testJavascriptBadReturnType() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val double)");
-
- String fName = createFunction(KEYSPACE, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS '\"string\";';");
-
- execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
- // throws IRE with ClassCastException
- assertInvalidMessage("Invalid value for CQL type double", "SELECT key, val, " + fName + "(val) FROM %s");
- }
-
- @Test
- public void testJavascriptThrow() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val double)");
-
- String fName = createFunction(KEYSPACE, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS 'throw \"fool\";';");
-
- execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
- // throws IRE with ScriptException
- assertInvalidThrowMessage("fool", FunctionExecutionException.class,
- "SELECT key, val, " + fName + "(val) FROM %s");
- }
-
- @Test
- public void testDuplicateArgNames() throws Throwable
- {
- assertInvalidMessage("duplicate argument names for given function",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double, val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS '\"foo bar\";';");
- }
-
- @Test
- public void testJavascriptCompileFailure() throws Throwable
- {
- assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS 'foo bar';");
- }
-
- @Test
- public void testScriptInvalidLanguage() throws Throwable
- {
- assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE artificial_intelligence\n" +
- "AS 'question for 42?';");
- }
-
- @Test
- public void testScriptReturnTypeCasting() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val double)");
- execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
-
- Object[][] variations = {
- new Object[] { "true", "boolean", true },
- new Object[] { "false", "boolean", false },
- new Object[] { "100", "tinyint", (byte)100 },
- new Object[] { "100.", "tinyint", (byte)100 },
- new Object[] { "100", "smallint", (short)100 },
- new Object[] { "100.", "smallint", (short)100 },
- new Object[] { "100", "int", 100 },
- new Object[] { "100.", "int", 100 },
- new Object[] { "100", "double", 100d },
- new Object[] { "100.", "double", 100d },
- new Object[] { "100", "bigint", 100L },
- new Object[] { "100.", "bigint", 100L },
- new Object[] { "100", "varint", BigInteger.valueOf(100L) },
- new Object[] { "100.", "varint", BigInteger.valueOf(100L) },
- new Object[] { "parseInt(\"100\");", "decimal", BigDecimal.valueOf(100d) },
- new Object[] { "100.", "decimal", BigDecimal.valueOf(100d) },
- };
-
- for (Object[] variation : variations)
- {
- Object functionBody = variation[0];
- Object returnType = variation[1];
- Object expectedResult = variation[2];
-
- String fName = createFunction(KEYSPACE, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS " +returnType + ' ' +
- "LANGUAGE javascript " +
- "AS '" + functionBody + ";';");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 1d, expectedResult));
- }
- }
-
- @Test
- public void testScriptParamReturnTypes() throws Throwable
- {
- UUID ruuid = UUID.randomUUID();
- UUID tuuid = UUIDGen.getTimeUUID();
-
- createTable("CREATE TABLE %s (key int primary key, " +
- "tival tinyint, sival smallint, ival int, lval bigint, fval float, dval double, vval varint, ddval decimal, " +
- "timval time, dtval date, tsval timestamp, uval uuid, tuval timeuuid)");
- execute("INSERT INTO %s (key, tival, sival, ival, lval, fval, dval, vval, ddval, timval, dtval, tsval, uval, tuval) VALUES " +
- "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 1,
- (byte)1, (short)1, 1, 1L, 1f, 1d, BigInteger.valueOf(1L), BigDecimal.valueOf(1d), 1L, Integer.MAX_VALUE, new Date(1), ruuid, tuuid);
-
- Object[][] variations = {
- new Object[] { "tinyint", "tival", (byte)1, (byte)2 },
- new Object[] { "smallint", "sival", (short)1, (short)2 },
- new Object[] { "int", "ival", 1, 2 },
- new Object[] { "bigint", "lval", 1L, 2L },
- new Object[] { "float", "fval", 1f, 2f },
- new Object[] { "double", "dval", 1d, 2d },
- new Object[] { "varint", "vval", BigInteger.valueOf(1L), BigInteger.valueOf(2L) },
- new Object[] { "decimal", "ddval", BigDecimal.valueOf(1d), BigDecimal.valueOf(2d) },
- new Object[] { "time", "timval", 1L, 2L },
- };
-
- for (Object[] variation : variations)
- {
- Object type = variation[0];
- Object col = variation[1];
- Object expected1 = variation[2];
- Object expected2 = variation[3];
- String fName = createFunction(KEYSPACE, type.toString(),
- "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS " + type + ' ' +
- "LANGUAGE javascript " +
- "AS 'val+1;';");
- assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
- row(1, expected1, expected2));
- }
-
- variations = new Object[][] {
- new Object[] { "timestamp","tsval", new Date(1), new Date(1) },
- new Object[] { "uuid", "uval", ruuid, ruuid },
- new Object[] { "timeuuid", "tuval", tuuid, tuuid },
- new Object[] { "date", "dtval", Integer.MAX_VALUE, Integer.MAX_VALUE },
- };
-
- for (Object[] variation : variations)
- {
- Object type = variation[0];
- Object col = variation[1];
- Object expected1 = variation[2];
- Object expected2 = variation[3];
- String fName = createFunction(KEYSPACE, type.toString(),
- "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS " + type + ' ' +
- "LANGUAGE javascript " +
- "AS 'val;';");
- assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
- row(1, expected1, expected2));
- }
- }
-
- static class TypesTestDef
- {
- final String udfType;
- final String tableType;
- final String columnName;
- final Object referenceValue;
+ private static class TypesTestDef
+ {
+ final String udfType;
+ final String tableType;
+ final String columnName;
+ final Object referenceValue;
String fCheckArgAndReturn;
@@ -2274,416 +1108,4 @@ public class UFTest extends CQLTester
}
}
}
-
- @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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<set<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS set<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<list<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS list<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<map<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS map<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<tuple<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, "(null, null)"),
- row(1, "(1, 2)"),
- row(2, "(4, 5)"),
- row(3, "(7, 8)"));
-
- functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS tuple<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
- }
-
- @Test
- public void testFunctionWithFrozenUDType() 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, 0);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<" + myType + "> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, "{f:0}"),
- row(1, "{f:1}"),
- row(2, "{f:4}"),
- row(3, "{f:7}"));
-
- functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS " + myType + " " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
- }
-
- @Test
- public void testEmptyString() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, sval text, aval ascii, bval blob, empty_int int)");
- execute("INSERT INTO %s (key, sval, aval, bval, empty_int) VALUES (?, ?, ?, ?, blobAsInt(0x))", 1, "", "", ByteBuffer.allocate(0));
-
- String fNameSRC = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameSCC = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return \"\";'");
-
- String fNameSRN = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameSCN = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return \"\";'");
-
- String fNameBRC = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "CALLED ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameBCC = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "CALLED ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return ByteBuffer.allocate(0);'");
-
- String fNameBRN = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameBCN = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return ByteBuffer.allocate(0);'");
-
- String fNameIRC = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameICC = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- String fNameIRN = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameICN = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- assertRows(execute("SELECT " + fNameSRC + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRN + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCC + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCN + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRC + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRN + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCC + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCN + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameBRC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBRN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBCC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBCN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameIRC + "(empty_int) FROM %s"), row(new Object[]{null}));
- assertRows(execute("SELECT " + fNameIRN + "(empty_int) FROM %s"), row(new Object[]{null}));
- assertRows(execute("SELECT " + fNameICC + "(empty_int) FROM %s"), row(0));
- assertRows(execute("SELECT " + fNameICN + "(empty_int) FROM %s"), row(new Object[]{null}));
- }
-
- @Test
- public void testAllNativeTypes() throws Throwable
- {
- StringBuilder sig = new StringBuilder();
- StringBuilder args = new StringBuilder();
- for (CQL3Type.Native type : CQL3Type.Native.values())
- {
- if (sig.length() > 0)
- sig.append(',');
- sig.append(type.toString());
-
- if (args.length() > 0)
- args.append(',');
- args.append("arg").append(type.toString()).append(' ').append(type.toString());
- }
- createFunction(KEYSPACE, sig.toString(),
- "CREATE OR REPLACE FUNCTION %s(" + args + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- for (CQL3Type.Native type : CQL3Type.Native.values())
- {
- createFunction(KEYSPACE_PER_TEST, type.toString(),
- "CREATE OR REPLACE FUNCTION %s(val " + type.toString() + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
- }
- }
}
[17/25] 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/3aefe356/test/unit/org/apache/cassandra/cql3/validation/entities/UFTypesTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFTypesTest.java
index 0000000,0000000..de98748
new file mode 100644
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTypesTest.java
@@@ -1,0 -1,0 +1,549 @@@
++/*
++ * 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.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.Test;
++
++import com.datastax.driver.core.Row;
++import org.apache.cassandra.cql3.CQLTester;
++import org.apache.cassandra.cql3.UntypedResultSet;
++import org.apache.cassandra.utils.UUIDGen;
++
++public class UFTypesTest extends CQLTester
++{
++
++ @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 : PROTOCOL_VERSIONS)
++ {
++ 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"));
++ }
++ }
++
++ private static class TypesTestDef
++ {
++ final String udfType;
++ final String tableType;
++ final String columnName;
++ final Object referenceValue;
++
++ String fCheckArgAndReturn;
++
++ String fCalledOnNull;
++ String fReturnsNullOnNull;
++
++ TypesTestDef(String udfType, String tableType, String columnName, Object referenceValue)
++ {
++ this.udfType = udfType;
++ this.tableType = tableType;
++ this.columnName = columnName;
++ this.referenceValue = referenceValue;
++ }
++ }
++
++ @Test
++ public void testTypesWithAndWithoutNulls() throws Throwable
++ {
++ // test various combinations of types against UDFs with CALLED ON NULL or RETURNS NULL ON NULL
++
++ String type = createType("CREATE TYPE %s (txt text, i int)");
++
++ TypesTestDef[] typeDefs =
++ {
++ // udf type, table type, column, reference value
++ new TypesTestDef("timestamp", "timestamp", "ts", new Date()),
++ new TypesTestDef("date", "date", "dt", 12345),
++ new TypesTestDef("time", "time", "tim", 12345L),
++ new TypesTestDef("uuid", "uuid", "uu", UUID.randomUUID()),
++ new TypesTestDef("timeuuid", "timeuuid", "tu", UUIDGen.getTimeUUID()),
++ new TypesTestDef("tinyint", "tinyint", "ti", (byte) 42),
++ new TypesTestDef("smallint", "smallint", "si", (short) 43),
++ new TypesTestDef("int", "int", "i", 44),
++ new TypesTestDef("bigint", "bigint", "b", 45L),
++ new TypesTestDef("float", "float", "f", 46f),
++ new TypesTestDef("double", "double", "d", 47d),
++ new TypesTestDef("boolean", "boolean", "x", true),
++ new TypesTestDef("ascii", "ascii", "a", "tqbfjutld"),
++ new TypesTestDef("text", "text", "t", "k\u00f6lsche jung"),
++ //new TypesTestDef(type, "frozen<" + type + '>', "u", null),
++ new TypesTestDef("tuple<int, text>", "frozen<tuple<int, text>>", "tup", tuple(1, "foo"))
++ };
++
++ String createTableDDL = "CREATE TABLE %s (key int PRIMARY KEY";
++ String insertDML = "INSERT INTO %s (key";
++ List<Object> values = new ArrayList<>();
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ createTableDDL += ", " + typeDef.columnName + ' ' + typeDef.tableType;
++ insertDML += ", " + typeDef.columnName;
++ String typeName = typeDef.udfType;
++ typeDef.fCheckArgAndReturn = createFunction(KEYSPACE,
++ typeName,
++ "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS " + typeName + ' ' +
++ "LANGUAGE java\n" +
++ "AS 'return val;';");
++ typeDef.fCalledOnNull = createFunction(KEYSPACE,
++ typeName,
++ "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return \"called\";';");
++ typeDef.fReturnsNullOnNull = createFunction(KEYSPACE,
++ typeName,
++ "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return \"called\";';");
++ values.add(typeDef.referenceValue);
++ }
++
++ createTableDDL += ')';
++ createTable(createTableDDL);
++
++ insertDML += ") VALUES (1";
++ for (TypesTestDef ignored : typeDefs)
++ insertDML += ", ?";
++ insertDML += ')';
++
++ execute(insertDML, values.toArray());
++
++ // second row with null values
++ for (int i = 0; i < values.size(); i++)
++ values.set(i, null);
++ execute(insertDML.replace('1', '2'), values.toArray());
++
++ // check argument input + return
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ assertRows(execute("SELECT " + typeDef.fCheckArgAndReturn + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
++ row(new Object[]{ typeDef.referenceValue }));
++ }
++
++ // check for CALLED ON NULL INPUT with non-null arguments
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
++ row(new Object[]{ "called" }));
++ }
++
++ // check for CALLED ON NULL INPUT with null arguments
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
++ row(new Object[]{ "called" }));
++ }
++
++ // check for RETURNS NULL ON NULL INPUT with non-null arguments
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
++ row(new Object[]{ "called" }));
++ }
++
++ // check for RETURNS NULL ON NULL INPUT with null arguments
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
++ row(new Object[]{ null }));
++ }
++
++ }
++
++ @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));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
++
++ assertInvalidMessage("The function return type should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS frozen<set<int>> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ String functionName = createFunction(KEYSPACE,
++ "set<int>",
++ "CREATE FUNCTION %s (values set<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
++
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
++
++ functionName = createFunction(KEYSPACE,
++ "set<int>",
++ "CREATE FUNCTION %s (values set<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS set<int> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
++ row(1));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "DROP FUNCTION " + functionName + "(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));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
++
++ assertInvalidMessage("The function return type should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS frozen<list<int>> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ String functionName = createFunction(KEYSPACE,
++ "list<int>",
++ "CREATE FUNCTION %s (values list<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
++
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
++
++ functionName = createFunction(KEYSPACE,
++ "list<int>",
++ "CREATE FUNCTION %s (values list<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS list<int> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
++ row(1));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
++ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
++ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
++
++ assertInvalidMessage("The function return type should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS frozen<map<int, int>> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ String functionName = createFunction(KEYSPACE,
++ "map<int, int>",
++ "CREATE FUNCTION %s (values map<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
++
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
++
++ functionName = createFunction(KEYSPACE,
++ "map<int, int>",
++ "CREATE FUNCTION %s (values map<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS map<int, int> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
++ row(1));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "DROP FUNCTION " + functionName + "(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));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return values.toString();';");
++
++ assertInvalidMessage("The function return type should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS frozen<tuple<int, int>> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ String functionName = createFunction(KEYSPACE,
++ "tuple<int, int>",
++ "CREATE FUNCTION %s (values tuple<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return values.toString();';");
++
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, "(NULL,NULL)"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, "(1,2)"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, "(4,5)"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, "(7,8)"));
++
++ functionName = createFunction(KEYSPACE,
++ "tuple<int, int>",
++ "CREATE FUNCTION %s (values tuple<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS tuple<int, int> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
++ row(1));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
++ }
++
++ @Test
++ public void testFunctionWithFrozenUDType() 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, 0);
++ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
++ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
++ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return values.toString();';");
++
++ assertInvalidMessage("The function return type should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS frozen<" + myType + "> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ String functionName = createFunction(KEYSPACE,
++ myType,
++ "CREATE FUNCTION %s (values " + myType + ") " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return values.toString();';");
++
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, "{f:0}"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, "{f:1}"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, "{f:4}"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, "{f:7}"));
++
++ functionName = createFunction(KEYSPACE,
++ myType,
++ "CREATE FUNCTION %s (values " + myType + ") " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS " + myType + " " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
++ row(1));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
++ }
++}
[15/25] 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/3aefe356/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
index 0000000,d3050a5..af3c894
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
@@@ -1,0 -1,504 +1,428 @@@
+ /*
+ * 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.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.TupleType;
-import com.datastax.driver.core.TupleValue;
+ import org.apache.cassandra.config.DatabaseDescriptor;
+ import org.apache.cassandra.cql3.CQLTester;
+ import org.apache.cassandra.cql3.UntypedResultSet;
+ import org.apache.cassandra.cql3.functions.FunctionName;
-import org.apache.cassandra.dht.ByteOrderedPartitioner;
+ import org.apache.cassandra.exceptions.FunctionExecutionException;
-import org.apache.cassandra.transport.Server;
+ import org.apache.cassandra.utils.UUIDGen;
+
+ public class UFScriptTest extends CQLTester
+ {
- @BeforeClass
- public static void setUp()
- {
- DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance);
- }
++ // Just JavaScript UDFs to check how UDF - especially security/class-loading/sandboxing stuff -
++ // behaves, if no Java UDF has been executed before.
++
++ // Do not add any other test here - especially none using Java UDFs
+
+ @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++)
++ for (int version : PROTOCOL_VERSIONS)
+ 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"),
- row(1d));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup3 + "(tup) FROM %s WHERE key = 1"),
- row(list));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup4 + "(tup) FROM %s WHERE key = 1"),
- row(set));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup5 + "(tup) FROM %s WHERE key = 1"),
- row(map));
- }
- }
-
- @Test
+ public void testJavascriptUserType() throws Throwable
+ {
+ String type = createType("CREATE TYPE %s (txt text, i int)");
+
+ createTable("CREATE TABLE %s (key int primary key, udt frozen<" + type + ">)");
+
+ String fUdt1 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
- "RETURNS " + type + " " +
++ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt;$$;");
+ String fUdt2 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getString(\"txt\");$$;");
+ String fUdt3 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getInt(\"i\");$$;");
+
+ execute("INSERT INTO %s (key, udt) VALUES (1, {txt: 'one', i:1})");
+
+ UntypedResultSet rows = execute("SELECT " + fUdt1 + "(udt) FROM %s WHERE key = 1");
+ Assert.assertEquals(1, rows.size());
+ assertRows(execute("SELECT " + fUdt2 + "(udt) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fUdt3 + "(udt) FROM %s WHERE key = 1"),
+ row(1));
+ }
+
+ @Test
+ public void testJavascriptUTCollections() throws Throwable
+ {
+ String type = 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 fName = createFunction(KEYSPACE, "list<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( lst list<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " lst.get(1).getString(\"txt\");$$;");
+ createFunctionOverload(fName, "set<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( st set<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " st.iterator().next().getString(\"txt\");$$;");
+ createFunctionOverload(fName, "map<int, frozen<" + type + ">>",
+ "CREATE FUNCTION %s( mp map<int, frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " mp.get(java.lang.Integer.valueOf(3)).getString(\"txt\");$$;");
+
+ execute("INSERT INTO %s (key, lst, st, mp) values (1, " +
+ // list<frozen<UDT>>
+ "[ {txt: 'one', i:1}, {txt: 'three', i:1}, {txt: 'one', i:1} ] , " +
+ // set<frozen<UDT>>
+ "{ {txt: 'one', i:1}, {txt: 'three', i:3}, {txt: 'two', i:2} }, " +
+ // map<int, frozen<UDT>>
+ "{ 1: {txt: 'one', i:1}, 2: {txt: 'one', i:3}, 3: {txt: 'two', i:2} })");
+
+ assertRows(execute("SELECT " + fName + "(lst) FROM %s WHERE key = 1"),
+ row("three"));
+ assertRows(execute("SELECT " + fName + "(st) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fName + "(mp) FROM %s WHERE key = 1"),
+ row("two"));
+
+ String cqlSelect = "SELECT " + fName + "(lst), " + fName + "(st), " + fName + "(mp) FROM %s WHERE key = 1";
+ assertRows(execute(cqlSelect),
+ row("three", "one", "two"));
+
+ // same test - but via native protocol
- for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
++ for (int version : PROTOCOL_VERSIONS)
+ assertRowsNet(version,
+ executeNet(version, cqlSelect),
+ row("three", "one", "two"));
+ }
+
+ @Test
+ public void testJavascriptFunction() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String functionBody = '\n' +
+ " Math.sin(val);\n";
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS '" + functionBody + "';");
+
+ FunctionName fNameName = parseFunctionName(fName);
+
- assertRows(execute("SELECT language, body FROM system.schema_functions WHERE keyspace_name=? AND function_name=?",
++ assertRows(execute("SELECT language, body FROM system_schema.functions WHERE keyspace_name=? AND function_name=?",
+ fNameName.keyspace, fNameName.name),
+ row("javascript", 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 testJavascriptBadReturnType() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS '\"string\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ClassCastException
+ assertInvalidMessage("Invalid value for CQL type double", "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
+ public void testJavascriptThrow() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS 'throw \"fool\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ScriptException
+ assertInvalidThrowMessage("fool", FunctionExecutionException.class,
+ "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
- public void testJavascriptCompileFailure() throws Throwable
- {
- assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS 'foo bar';");
- }
-
- @Test
- public void testScriptInvalidLanguage() throws Throwable
- {
- assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE artificial_intelligence\n" +
- "AS 'question for 42?';");
- }
-
- @Test
+ public void testScriptReturnTypeCasting() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+
+ Object[][] variations = {
+ new Object[] { "true", "boolean", true },
+ new Object[] { "false", "boolean", false },
+ new Object[] { "100", "tinyint", (byte)100 },
+ new Object[] { "100.", "tinyint", (byte)100 },
+ new Object[] { "100", "smallint", (short)100 },
+ new Object[] { "100.", "smallint", (short)100 },
+ new Object[] { "100", "int", 100 },
+ new Object[] { "100.", "int", 100 },
+ new Object[] { "100", "double", 100d },
+ new Object[] { "100.", "double", 100d },
+ new Object[] { "100", "bigint", 100L },
+ new Object[] { "100.", "bigint", 100L },
+ new Object[] { "100", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "100.", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "parseInt(\"100\");", "decimal", BigDecimal.valueOf(100d) },
+ new Object[] { "100.", "decimal", BigDecimal.valueOf(100d) },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object functionBody = variation[0];
+ Object returnType = variation[1];
+ Object expectedResult = variation[2];
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " +returnType + ' ' +
+ "LANGUAGE javascript " +
+ "AS '" + functionBody + ";';");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1d, expectedResult));
+ }
+ }
+
+ @Test
+ public void testScriptParamReturnTypes() throws Throwable
+ {
+ UUID ruuid = UUID.randomUUID();
+ UUID tuuid = UUIDGen.getTimeUUID();
+
+ createTable("CREATE TABLE %s (key int primary key, " +
+ "tival tinyint, sival smallint, ival int, lval bigint, fval float, dval double, vval varint, ddval decimal, " +
+ "timval time, dtval date, tsval timestamp, uval uuid, tuval timeuuid)");
+ execute("INSERT INTO %s (key, tival, sival, ival, lval, fval, dval, vval, ddval, timval, dtval, tsval, uval, tuval) VALUES " +
+ "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 1,
+ (byte)1, (short)1, 1, 1L, 1f, 1d, BigInteger.valueOf(1L), BigDecimal.valueOf(1d), 1L, Integer.MAX_VALUE, new Date(1), ruuid, tuuid);
+
+ Object[][] variations = {
+ new Object[] { "tinyint", "tival", (byte)1, (byte)2 },
+ new Object[] { "smallint", "sival", (short)1, (short)2 },
+ new Object[] { "int", "ival", 1, 2 },
+ new Object[] { "bigint", "lval", 1L, 2L },
+ new Object[] { "float", "fval", 1f, 2f },
+ new Object[] { "double", "dval", 1d, 2d },
+ new Object[] { "varint", "vval", BigInteger.valueOf(1L), BigInteger.valueOf(2L) },
+ new Object[] { "decimal", "ddval", BigDecimal.valueOf(1d), BigDecimal.valueOf(2d) },
+ new Object[] { "time", "timval", 1L, 2L },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val+1;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+
+ variations = new Object[][] {
+ new Object[] { "timestamp","tsval", new Date(1), new Date(1) },
+ new Object[] { "uuid", "uval", ruuid, ruuid },
+ new Object[] { "timeuuid", "tuval", tuuid, tuuid },
+ new Object[] { "date", "dtval", Integer.MAX_VALUE, Integer.MAX_VALUE },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+ }
++
++ @Test
++ public void testJavascriptDisabled() throws Throwable
++ {
++ createTable("CREATE TABLE %s (key int primary key, val double)");
++
++ DatabaseDescriptor.enableScriptedUserDefinedFunctions(false);
++ try
++ {
++ assertInvalid("double",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".assertNotEnabled(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE javascript\n" +
++ "AS 'Math.sin(val);';");
++ }
++ finally
++ {
++ DatabaseDescriptor.enableScriptedUserDefinedFunctions(true);
++ }
++ }
++
++ @Test
++ public void testJavascriptCompileFailure() throws Throwable
++ {
++ assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE javascript\n" +
++ "AS 'foo bar';");
++ }
++
++ @Test
++ public void testScriptInvalidLanguage() throws Throwable
++ {
++ assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE artificial_intelligence\n" +
++ "AS 'question for 42?';");
++ }
+ }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/3aefe356/test/unit/org/apache/cassandra/cql3/validation/entities/UFSecurityTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFSecurityTest.java
index 0000000,0000000..5c7ca2b
new file mode 100644
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFSecurityTest.java
@@@ -1,0 -1,0 +1,258 @@@
++/*
++ * 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.security.AccessControlException;
++import java.util.List;
++
++import org.junit.Assert;
++import org.junit.Test;
++
++import org.apache.cassandra.config.Config;
++import org.apache.cassandra.config.DatabaseDescriptor;
++import org.apache.cassandra.cql3.CQLTester;
++import org.apache.cassandra.cql3.functions.UDHelper;
++import org.apache.cassandra.exceptions.FunctionExecutionException;
++import org.apache.cassandra.service.ClientWarn;
++
++public class UFSecurityTest extends CQLTester
++{
++ @Test
++ public void testSecurityPermissions() throws Throwable
++ {
++ createTable("CREATE TABLE %s (key int primary key, dval double)");
++ execute("INSERT INTO %s (key, dval) VALUES (?, ?)", 1, 1d);
++
++ // Java UDFs
++
++ try
++ {
++ 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 'System.getProperty(\"foo.bar.baz\"); return 0d;';");
++ execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
++ Assert.fail();
++ }
++ catch (FunctionExecutionException e)
++ {
++ assertAccessControlException("System.getProperty(\"foo.bar.baz\"); return 0d;", e);
++ }
++
++ String[][] typesAndSources =
++ {
++ {"", "try { Class.forName(\"" + UDHelper.class.getName() + "\"); } catch (Exception e) { throw new RuntimeException(e); } return 0d;"},
++ {"sun.misc.Unsafe", "sun.misc.Unsafe.getUnsafe(); return 0d;"},
++ {"", "try { Class.forName(\"sun.misc.Unsafe\"); } catch (Exception e) { throw new RuntimeException(e); } return 0d;"},
++ {"java.nio.file.FileSystems", "try {" +
++ " java.nio.file.FileSystems.getDefault(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.nio.channels.FileChannel", "try {" +
++ " java.nio.channels.FileChannel.open(java.nio.file.FileSystems.getDefault().getPath(\"/etc/passwd\")).close(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.nio.channels.SocketChannel", "try {" +
++ " java.nio.channels.SocketChannel.open().close(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.io.FileInputStream", "try {" +
++ " new java.io.FileInputStream(\"./foobar\").close(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.lang.Runtime", "try {" +
++ " java.lang.Runtime.getRuntime(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"org.apache.cassandra.service.StorageService",
++ "try {" +
++ " org.apache.cassandra.service.StorageService v = org.apache.cassandra.service.StorageService.instance; v.isShutdown(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.net.ServerSocket", "try {" +
++ " new java.net.ServerSocket().bind(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.io.FileOutputStream","try {" +
++ " new java.io.FileOutputStream(\".foo\"); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.lang.Runtime", "try {" +
++ " java.lang.Runtime.getRuntime().exec(\"/tmp/foo\"); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'}
++ };
++
++ for (String[] typeAndSource : typesAndSources)
++ {
++ assertInvalidMessage(typeAndSource[0] + " cannot be resolved",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".invalid_class_access(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE JAVA\n" +
++ "AS '" + typeAndSource[1] + "';");
++ }
++
++ // JavaScript UDFs
++
++ try
++ {
++ String fName = createFunction(KEYSPACE_PER_TEST, "double",
++ "CREATE OR REPLACE FUNCTION %s(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE javascript\n" +
++ "AS 'org.apache.cassandra.service.StorageService.instance.isShutdown(); 0;';");
++ execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
++ Assert.fail("Javascript security check failed");
++ }
++ catch (FunctionExecutionException e)
++ {
++ assertAccessControlException("", e);
++ }
++
++ String[] javascript =
++ {
++ "java.lang.management.ManagmentFactory.getThreadMXBean(); 0;",
++ "new java.io.FileInputStream(\"/tmp/foo\"); 0;",
++ "new java.io.FileOutputStream(\"/tmp/foo\"); 0;",
++ "java.nio.file.FileSystems.getDefault().createFileExclusively(\"./foo_bar_baz\"); 0;",
++ "java.nio.channels.FileChannel.open(java.nio.file.FileSystems.getDefault().getPath(\"/etc/passwd\")); 0;",
++ "java.nio.channels.SocketChannel.open(); 0;",
++ "new java.net.ServerSocket().bind(null); 0;",
++ "var thread = new java.lang.Thread(); thread.start(); 0;",
++ "java.lang.System.getProperty(\"foo.bar.baz\"); 0;",
++ "java.lang.Class.forName(\"java.lang.System\"); 0;",
++ "java.lang.Runtime.getRuntime().exec(\"/tmp/foo\"); 0;",
++ "java.lang.Runtime.getRuntime().loadLibrary(\"foobar\"); 0;",
++ "java.lang.Runtime.getRuntime().loadLibrary(\"foobar\"); 0;",
++ // TODO these (ugly) calls are still possible - these can consume CPU (as one could do with an evil loop, too)
++// "java.lang.Runtime.getRuntime().traceMethodCalls(true); 0;",
++// "java.lang.Runtime.getRuntime().gc(); 0;",
++// "java.lang.Runtime.getRuntime(); 0;",
++ };
++
++ for (String script : javascript)
++ {
++ try
++ {
++ String fName = createFunction(KEYSPACE_PER_TEST, "double",
++ "CREATE OR REPLACE FUNCTION %s(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE javascript\n" +
++ "AS '" + script + "';");
++ execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
++ Assert.fail("Javascript security check failed: " + script);
++ }
++ catch (FunctionExecutionException e)
++ {
++ assertAccessControlException(script, e);
++ }
++ }
++ }
++
++ private static void assertAccessControlException(String script, FunctionExecutionException e)
++ {
++ for (Throwable t = e; t != null && t != t.getCause(); t = t.getCause())
++ if (t instanceof AccessControlException)
++ return;
++ Assert.fail("no AccessControlException for " + script + " (got " + e + ')');
++ }
++
++ @Test
++ public void testAmokUDF() throws Throwable
++ {
++ createTable("CREATE TABLE %s (key int primary key, dval double)");
++ execute("INSERT INTO %s (key, dval) VALUES (?, ?)", 1, 1d);
++
++ long udfWarnTimeout = DatabaseDescriptor.getUserDefinedFunctionWarnTimeout();
++ long udfFailTimeout = DatabaseDescriptor.getUserDefinedFunctionFailTimeout();
++ int maxTries = 5;
++ for (int i = 1; i <= maxTries; i++)
++ {
++ try
++ {
++ // short timeout
++ DatabaseDescriptor.setUserDefinedFunctionWarnTimeout(10);
++ DatabaseDescriptor.setUserDefinedFunctionFailTimeout(250);
++ // don't kill the unit test... - default policy is "die"
++ DatabaseDescriptor.setUserFunctionTimeoutPolicy(Config.UserFunctionTimeoutPolicy.ignore);
++
++ ClientWarn.instance.captureWarnings();
++ 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 'long t=System.currentTimeMillis()+110; while (t>System.currentTimeMillis()) { }; return 0d;'");
++ execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
++ List<String> warnings = ClientWarn.instance.getWarnings();
++ Assert.assertNotNull(warnings);
++ Assert.assertFalse(warnings.isEmpty());
++ ClientWarn.instance.resetWarnings();
++
++ // Java UDF
++
++ fName = createFunction(KEYSPACE_PER_TEST, "double",
++ "CREATE OR REPLACE FUNCTION %s(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE JAVA\n" +
++ "AS 'long t=System.currentTimeMillis()+500; while (t>System.currentTimeMillis()) { }; return 0d;';");
++ assertInvalidMessage("ran longer than 250ms", "SELECT " + fName + "(dval) FROM %s WHERE key=1");
++
++ // Javascript UDF
++
++ fName = createFunction(KEYSPACE_PER_TEST, "double",
++ "CREATE OR REPLACE FUNCTION %s(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE JAVASCRIPT\n" +
++ "AS 'var t=java.lang.System.currentTimeMillis()+500; while (t>java.lang.System.currentTimeMillis()) { }; 0;';");
++ assertInvalidMessage("ran longer than 250ms", "SELECT " + fName + "(dval) FROM %s WHERE key=1");
++
++ return;
++ }
++ catch (Error | RuntimeException e)
++ {
++ if (i == maxTries)
++ throw e;
++ }
++ finally
++ {
++ // reset to defaults
++ DatabaseDescriptor.setUserDefinedFunctionWarnTimeout(udfWarnTimeout);
++ DatabaseDescriptor.setUserDefinedFunctionFailTimeout(udfFailTimeout);
++ }
++ }
++ }
++
++}
[12/25] 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/3aefe356
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/3aefe356
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/3aefe356
Branch: refs/heads/cassandra-3.X
Commit: 3aefe356545bcc2f5c4453e0d9d704bef339a008
Parents: 95d0b67 0b97c5d
Author: Robert Stupp <sn...@snazy.de>
Authored: Wed Dec 7 13:08:35 2016 +0100
Committer: Robert Stupp <sn...@snazy.de>
Committed: Wed Dec 7 13:08:35 2016 +0100
----------------------------------------------------------------------
.../cql3/validation/entities/UFJavaTest.java | 797 +++++++++
.../validation/entities/UFPureScriptTest.java | 406 -----
.../cql3/validation/entities/UFScriptTest.java | 428 +++++
.../validation/entities/UFSecurityTest.java | 258 +++
.../cql3/validation/entities/UFTest.java | 1519 +-----------------
.../cql3/validation/entities/UFTypesTest.java | 549 +++++++
6 files changed, 2033 insertions(+), 1924 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/3aefe356/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
index 0000000,caef808..15c8e18
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
@@@ -1,0 -1,1177 +1,797 @@@
+ /*
+ * 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.nio.ByteBuffer;
+ import java.util.Arrays;
+ import java.util.List;
+ import java.util.Map;
+ import java.util.Set;
+ import java.util.TreeMap;
+ import java.util.TreeSet;
+
+ 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 org.apache.cassandra.config.DatabaseDescriptor;
++import org.apache.cassandra.config.Schema;
+ import org.apache.cassandra.cql3.CQL3Type;
+ import org.apache.cassandra.cql3.CQLTester;
+ import org.apache.cassandra.cql3.UntypedResultSet;
+ import org.apache.cassandra.cql3.functions.FunctionName;
-import org.apache.cassandra.cql3.functions.Functions;
-import org.apache.cassandra.dht.ByteOrderedPartitioner;
+ import org.apache.cassandra.exceptions.FunctionExecutionException;
+ import org.apache.cassandra.exceptions.InvalidRequestException;
+ import org.apache.cassandra.transport.Server;
-import org.apache.cassandra.utils.ByteBufferUtil;
+
+ public class UFJavaTest extends CQLTester
+ {
- @BeforeClass
- public static void setUp()
- {
- DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance);
- }
-
-
+ @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=?",
++ 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=?",
++ 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 testJavaFunctionCounter() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val counter)");
+
+ String fName = createFunction(KEYSPACE, "counter",
+ "CREATE OR REPLACE FUNCTION %s(val counter) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS bigint " +
+ "LANGUAGE JAVA " +
+ "AS 'return val + 1;';");
+
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1L, 2L));
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ execute("UPDATE %s SET val = val + 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 4L, 5L));
+ execute("UPDATE %s SET val = val - 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ }
+
+ @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=?",
++ 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=?",
++ 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=?",
++ 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++)
++ for (int version : PROTOCOL_VERSIONS)
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fList + "(lst), " + fSet + "(st), " + fMap + "(mp) FROM %s WHERE key = 1"),
+ row(list, set, map));
+ }
+
+ @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()));
++ // same test - but via native protocol
++ // we use protocol V3 here to encode the expected version because the server
++ // always serializes Collections using V3 - see CollectionSerializer's
++ // serialize and deserialize methods.
++ TupleType tType = tupleTypeOf(Server.VERSION_3,
++ 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++)
++ for (int version : PROTOCOL_VERSIONS)
+ {
+ 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++)
++ for (int version : PROTOCOL_VERSIONS)
+ {
+ 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++)
++ for (int version : PROTOCOL_VERSIONS)
+ {
+ 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 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());
++ Assert.assertEquals(1, Schema.instance.getFunctions(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());
++ Assert.assertEquals(1, Schema.instance.getFunctions(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());
++ Assert.assertEquals(1, Schema.instance.getFunctions(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());
++ Assert.assertEquals(1, Schema.instance.getFunctions(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++)
++ for (int version : PROTOCOL_VERSIONS)
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fName1 + "(lst), " + fName2 + "(st), " + fName3 + "(mp) FROM %s WHERE key = 1"),
+ row("three", "one", "two"));
+ }
+
+ @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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<set<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS set<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<list<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS list<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<map<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS map<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<tuple<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, "(null, null)"),
- row(1, "(1, 2)"),
- row(2, "(4, 5)"),
- row(3, "(7, 8)"));
-
- functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS tuple<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
- }
-
- @Test
- public void testFunctionWithFrozenUDType() 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, 0);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<" + myType + "> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, "{f:0}"),
- row(1, "{f:1}"),
- row(2, "{f:4}"),
- row(3, "{f:7}"));
-
- functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS " + myType + " " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
- }
-
- @Test
- public void testEmptyString() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, sval text, aval ascii, bval blob, empty_int int)");
- execute("INSERT INTO %s (key, sval, aval, bval, empty_int) VALUES (?, ?, ?, ?, blobAsInt(0x))", 1, "", "", ByteBuffer.allocate(0));
-
- String fNameSRC = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameSCC = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return \"\";'");
-
- String fNameSRN = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameSCN = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return \"\";'");
-
- String fNameBRC = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "CALLED ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameBCC = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "CALLED ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return ByteBuffer.allocate(0);'");
-
- String fNameBRN = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameBCN = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return ByteBuffer.allocate(0);'");
-
- String fNameIRC = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameICC = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- String fNameIRN = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameICN = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- assertRows(execute("SELECT " + fNameSRC + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRN + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCC + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCN + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRC + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRN + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCC + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCN + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameBRC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBRN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBCC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBCN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameIRC + "(empty_int) FROM %s"), row(new Object[]{null}));
- assertRows(execute("SELECT " + fNameIRN + "(empty_int) FROM %s"), row(new Object[]{null}));
- assertRows(execute("SELECT " + fNameICC + "(empty_int) FROM %s"), row(0));
- assertRows(execute("SELECT " + fNameICN + "(empty_int) FROM %s"), row(new Object[]{null}));
- }
-
- @Test
+ public void testAllNativeTypes() throws Throwable
+ {
+ StringBuilder sig = new StringBuilder();
+ StringBuilder args = new StringBuilder();
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
++ if (type == CQL3Type.Native.EMPTY)
++ continue;
++
+ if (sig.length() > 0)
+ sig.append(',');
+ sig.append(type.toString());
+
+ if (args.length() > 0)
+ args.append(',');
+ args.append("arg").append(type.toString()).append(' ').append(type.toString());
+ }
+ createFunction(KEYSPACE, sig.toString(),
+ "CREATE OR REPLACE FUNCTION %s(" + args + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
++ if (type == CQL3Type.Native.EMPTY)
++ continue;
++
+ createFunction(KEYSPACE_PER_TEST, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type.toString() + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+ }
+ }
+ }
[13/25] 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/3aefe356/test/unit/org/apache/cassandra/cql3/validation/entities/UFTypesTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFTypesTest.java
index 0000000,0000000..de98748
new file mode 100644
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTypesTest.java
@@@ -1,0 -1,0 +1,549 @@@
++/*
++ * 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.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.Test;
++
++import com.datastax.driver.core.Row;
++import org.apache.cassandra.cql3.CQLTester;
++import org.apache.cassandra.cql3.UntypedResultSet;
++import org.apache.cassandra.utils.UUIDGen;
++
++public class UFTypesTest extends CQLTester
++{
++
++ @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 : PROTOCOL_VERSIONS)
++ {
++ 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"));
++ }
++ }
++
++ private static class TypesTestDef
++ {
++ final String udfType;
++ final String tableType;
++ final String columnName;
++ final Object referenceValue;
++
++ String fCheckArgAndReturn;
++
++ String fCalledOnNull;
++ String fReturnsNullOnNull;
++
++ TypesTestDef(String udfType, String tableType, String columnName, Object referenceValue)
++ {
++ this.udfType = udfType;
++ this.tableType = tableType;
++ this.columnName = columnName;
++ this.referenceValue = referenceValue;
++ }
++ }
++
++ @Test
++ public void testTypesWithAndWithoutNulls() throws Throwable
++ {
++ // test various combinations of types against UDFs with CALLED ON NULL or RETURNS NULL ON NULL
++
++ String type = createType("CREATE TYPE %s (txt text, i int)");
++
++ TypesTestDef[] typeDefs =
++ {
++ // udf type, table type, column, reference value
++ new TypesTestDef("timestamp", "timestamp", "ts", new Date()),
++ new TypesTestDef("date", "date", "dt", 12345),
++ new TypesTestDef("time", "time", "tim", 12345L),
++ new TypesTestDef("uuid", "uuid", "uu", UUID.randomUUID()),
++ new TypesTestDef("timeuuid", "timeuuid", "tu", UUIDGen.getTimeUUID()),
++ new TypesTestDef("tinyint", "tinyint", "ti", (byte) 42),
++ new TypesTestDef("smallint", "smallint", "si", (short) 43),
++ new TypesTestDef("int", "int", "i", 44),
++ new TypesTestDef("bigint", "bigint", "b", 45L),
++ new TypesTestDef("float", "float", "f", 46f),
++ new TypesTestDef("double", "double", "d", 47d),
++ new TypesTestDef("boolean", "boolean", "x", true),
++ new TypesTestDef("ascii", "ascii", "a", "tqbfjutld"),
++ new TypesTestDef("text", "text", "t", "k\u00f6lsche jung"),
++ //new TypesTestDef(type, "frozen<" + type + '>', "u", null),
++ new TypesTestDef("tuple<int, text>", "frozen<tuple<int, text>>", "tup", tuple(1, "foo"))
++ };
++
++ String createTableDDL = "CREATE TABLE %s (key int PRIMARY KEY";
++ String insertDML = "INSERT INTO %s (key";
++ List<Object> values = new ArrayList<>();
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ createTableDDL += ", " + typeDef.columnName + ' ' + typeDef.tableType;
++ insertDML += ", " + typeDef.columnName;
++ String typeName = typeDef.udfType;
++ typeDef.fCheckArgAndReturn = createFunction(KEYSPACE,
++ typeName,
++ "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS " + typeName + ' ' +
++ "LANGUAGE java\n" +
++ "AS 'return val;';");
++ typeDef.fCalledOnNull = createFunction(KEYSPACE,
++ typeName,
++ "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return \"called\";';");
++ typeDef.fReturnsNullOnNull = createFunction(KEYSPACE,
++ typeName,
++ "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return \"called\";';");
++ values.add(typeDef.referenceValue);
++ }
++
++ createTableDDL += ')';
++ createTable(createTableDDL);
++
++ insertDML += ") VALUES (1";
++ for (TypesTestDef ignored : typeDefs)
++ insertDML += ", ?";
++ insertDML += ')';
++
++ execute(insertDML, values.toArray());
++
++ // second row with null values
++ for (int i = 0; i < values.size(); i++)
++ values.set(i, null);
++ execute(insertDML.replace('1', '2'), values.toArray());
++
++ // check argument input + return
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ assertRows(execute("SELECT " + typeDef.fCheckArgAndReturn + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
++ row(new Object[]{ typeDef.referenceValue }));
++ }
++
++ // check for CALLED ON NULL INPUT with non-null arguments
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
++ row(new Object[]{ "called" }));
++ }
++
++ // check for CALLED ON NULL INPUT with null arguments
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
++ row(new Object[]{ "called" }));
++ }
++
++ // check for RETURNS NULL ON NULL INPUT with non-null arguments
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
++ row(new Object[]{ "called" }));
++ }
++
++ // check for RETURNS NULL ON NULL INPUT with null arguments
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
++ row(new Object[]{ null }));
++ }
++
++ }
++
++ @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));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
++
++ assertInvalidMessage("The function return type should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS frozen<set<int>> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ String functionName = createFunction(KEYSPACE,
++ "set<int>",
++ "CREATE FUNCTION %s (values set<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
++
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
++
++ functionName = createFunction(KEYSPACE,
++ "set<int>",
++ "CREATE FUNCTION %s (values set<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS set<int> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
++ row(1));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "DROP FUNCTION " + functionName + "(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));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
++
++ assertInvalidMessage("The function return type should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS frozen<list<int>> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ String functionName = createFunction(KEYSPACE,
++ "list<int>",
++ "CREATE FUNCTION %s (values list<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
++
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
++
++ functionName = createFunction(KEYSPACE,
++ "list<int>",
++ "CREATE FUNCTION %s (values list<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS list<int> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
++ row(1));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
++ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
++ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
++
++ assertInvalidMessage("The function return type should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS frozen<map<int, int>> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ String functionName = createFunction(KEYSPACE,
++ "map<int, int>",
++ "CREATE FUNCTION %s (values map<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
++
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
++
++ functionName = createFunction(KEYSPACE,
++ "map<int, int>",
++ "CREATE FUNCTION %s (values map<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS map<int, int> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
++ row(1));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "DROP FUNCTION " + functionName + "(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));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return values.toString();';");
++
++ assertInvalidMessage("The function return type should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS frozen<tuple<int, int>> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ String functionName = createFunction(KEYSPACE,
++ "tuple<int, int>",
++ "CREATE FUNCTION %s (values tuple<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return values.toString();';");
++
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, "(NULL,NULL)"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, "(1,2)"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, "(4,5)"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, "(7,8)"));
++
++ functionName = createFunction(KEYSPACE,
++ "tuple<int, int>",
++ "CREATE FUNCTION %s (values tuple<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS tuple<int, int> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
++ row(1));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
++ }
++
++ @Test
++ public void testFunctionWithFrozenUDType() 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, 0);
++ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
++ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
++ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return values.toString();';");
++
++ assertInvalidMessage("The function return type should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS frozen<" + myType + "> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ String functionName = createFunction(KEYSPACE,
++ myType,
++ "CREATE FUNCTION %s (values " + myType + ") " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return values.toString();';");
++
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, "{f:0}"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, "{f:1}"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, "{f:4}"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, "{f:7}"));
++
++ functionName = createFunction(KEYSPACE,
++ myType,
++ "CREATE FUNCTION %s (values " + myType + ") " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS " + myType + " " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
++ row(1));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
++ }
++}
[02/25] cassandra git commit: testall failure in
org.apache.cassandra.cql3.validation.entities.UFTest.testAllNativeTypes
Posted by sn...@apache.org.
testall failure in org.apache.cassandra.cql3.validation.entities.UFTest.testAllNativeTypes
patch by Robert Stupp; reviewed by Alex Petrov for CASSANDRA-12817
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/0b97c5d1
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/0b97c5d1
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/0b97c5d1
Branch: refs/heads/cassandra-2.2
Commit: 0b97c5d1f717be30a04c59c766465d9c62a4e9ee
Parents: 2e93398
Author: Robert Stupp <sn...@snazy.de>
Authored: Wed Dec 7 13:06:55 2016 +0100
Committer: Robert Stupp <sn...@snazy.de>
Committed: Wed Dec 7 13:06:55 2016 +0100
----------------------------------------------------------------------
.../cql3/validation/entities/UFJavaTest.java | 1177 +++++++++++++
.../cql3/validation/entities/UFScriptTest.java | 504 ++++++
.../cql3/validation/entities/UFTest.java | 1608 +-----------------
3 files changed, 1696 insertions(+), 1593 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0b97c5d1/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
new file mode 100644
index 0000000..caef808
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
@@ -0,0 +1,1177 @@
+/*
+ * 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.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+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 org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.cql3.CQL3Type;
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.cql3.UntypedResultSet;
+import org.apache.cassandra.cql3.functions.FunctionName;
+import org.apache.cassandra.cql3.functions.Functions;
+import org.apache.cassandra.dht.ByteOrderedPartitioner;
+import org.apache.cassandra.exceptions.FunctionExecutionException;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.transport.Server;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+public class UFJavaTest extends CQLTester
+{
+ @BeforeClass
+ public static void setUp()
+ {
+ DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance);
+ }
+
+
+ @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 testJavaFunctionCounter() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val counter)");
+
+ String fName = createFunction(KEYSPACE, "counter",
+ "CREATE OR REPLACE FUNCTION %s(val counter) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS bigint " +
+ "LANGUAGE JAVA " +
+ "AS 'return val + 1;';");
+
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1L, 2L));
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ execute("UPDATE %s SET val = val + 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 4L, 5L));
+ execute("UPDATE %s SET val = val - 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ }
+
+ @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 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 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 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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<set<int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "set<int>",
+ "CREATE FUNCTION %s (values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, 0),
+ row(1, 6),
+ row(2, 15),
+ row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "set<int>",
+ "CREATE FUNCTION %s (values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS set<int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<list<int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "list<int>",
+ "CREATE FUNCTION %s (values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, 0),
+ row(1, 6),
+ row(2, 15),
+ row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "list<int>",
+ "CREATE FUNCTION %s (values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS list<int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
+ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
+ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<map<int, int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "map<int, int>",
+ "CREATE FUNCTION %s (values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, 0),
+ row(1, 6),
+ row(2, 15),
+ row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "map<int, int>",
+ "CREATE FUNCTION %s (values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS map<int, int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<tuple<int, int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "tuple<int, int>",
+ "CREATE FUNCTION %s (values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, "(null, null)"),
+ row(1, "(1, 2)"),
+ row(2, "(4, 5)"),
+ row(3, "(7, 8)"));
+
+ functionName = createFunction(KEYSPACE,
+ "tuple<int, int>",
+ "CREATE FUNCTION %s (values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS tuple<int, int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
+ }
+
+ @Test
+ public void testFunctionWithFrozenUDType() 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, 0);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<" + myType + "> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ myType,
+ "CREATE FUNCTION %s (values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, "{f:0}"),
+ row(1, "{f:1}"),
+ row(2, "{f:4}"),
+ row(3, "{f:7}"));
+
+ functionName = createFunction(KEYSPACE,
+ myType,
+ "CREATE FUNCTION %s (values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS " + myType + " " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
+ }
+
+ @Test
+ public void testEmptyString() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, sval text, aval ascii, bval blob, empty_int int)");
+ execute("INSERT INTO %s (key, sval, aval, bval, empty_int) VALUES (?, ?, ?, ?, blobAsInt(0x))", 1, "", "", ByteBuffer.allocate(0));
+
+ String fNameSRC = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameSCC = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return \"\";'");
+
+ String fNameSRN = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameSCN = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return \"\";'");
+
+ String fNameBRC = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameBCC = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return ByteBuffer.allocate(0);'");
+
+ String fNameBRN = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameBCN = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return ByteBuffer.allocate(0);'");
+
+ String fNameIRC = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameICC = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ String fNameIRN = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameICN = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ assertRows(execute("SELECT " + fNameSRC + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRN + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCC + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCN + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRC + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRN + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCC + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCN + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameBRC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBRN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBCC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBCN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameIRC + "(empty_int) FROM %s"), row(new Object[]{null}));
+ assertRows(execute("SELECT " + fNameIRN + "(empty_int) FROM %s"), row(new Object[]{null}));
+ assertRows(execute("SELECT " + fNameICC + "(empty_int) FROM %s"), row(0));
+ assertRows(execute("SELECT " + fNameICN + "(empty_int) FROM %s"), row(new Object[]{null}));
+ }
+
+ @Test
+ public void testAllNativeTypes() throws Throwable
+ {
+ StringBuilder sig = new StringBuilder();
+ StringBuilder args = new StringBuilder();
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
+ if (sig.length() > 0)
+ sig.append(',');
+ sig.append(type.toString());
+
+ if (args.length() > 0)
+ args.append(',');
+ args.append("arg").append(type.toString()).append(' ').append(type.toString());
+ }
+ createFunction(KEYSPACE, sig.toString(),
+ "CREATE OR REPLACE FUNCTION %s(" + args + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
+ createFunction(KEYSPACE_PER_TEST, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type.toString() + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0b97c5d1/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
new file mode 100644
index 0000000..d3050a5
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
@@ -0,0 +1,504 @@
+/*
+ * 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.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.TupleType;
+import com.datastax.driver.core.TupleValue;
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.cql3.UntypedResultSet;
+import org.apache.cassandra.cql3.functions.FunctionName;
+import org.apache.cassandra.dht.ByteOrderedPartitioner;
+import org.apache.cassandra.exceptions.FunctionExecutionException;
+import org.apache.cassandra.transport.Server;
+import org.apache.cassandra.utils.UUIDGen;
+
+public class UFScriptTest extends CQLTester
+{
+ @BeforeClass
+ public static void setUp()
+ {
+ DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance);
+ }
+
+ @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"),
+ row(1d));
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fTup3 + "(tup) FROM %s WHERE key = 1"),
+ row(list));
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fTup4 + "(tup) FROM %s WHERE key = 1"),
+ row(set));
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fTup5 + "(tup) FROM %s WHERE key = 1"),
+ row(map));
+ }
+ }
+
+ @Test
+ public void testJavascriptUserType() throws Throwable
+ {
+ String type = createType("CREATE TYPE %s (txt text, i int)");
+
+ createTable("CREATE TABLE %s (key int primary key, udt frozen<" + type + ">)");
+
+ String fUdt1 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + " " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt;$$;");
+ String fUdt2 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getString(\"txt\");$$;");
+ String fUdt3 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getInt(\"i\");$$;");
+
+ execute("INSERT INTO %s (key, udt) VALUES (1, {txt: 'one', i:1})");
+
+ UntypedResultSet rows = execute("SELECT " + fUdt1 + "(udt) FROM %s WHERE key = 1");
+ Assert.assertEquals(1, rows.size());
+ assertRows(execute("SELECT " + fUdt2 + "(udt) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fUdt3 + "(udt) FROM %s WHERE key = 1"),
+ row(1));
+ }
+
+ @Test
+ public void testJavascriptUTCollections() throws Throwable
+ {
+ String type = 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 fName = createFunction(KEYSPACE, "list<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( lst list<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " lst.get(1).getString(\"txt\");$$;");
+ createFunctionOverload(fName, "set<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( st set<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " st.iterator().next().getString(\"txt\");$$;");
+ createFunctionOverload(fName, "map<int, frozen<" + type + ">>",
+ "CREATE FUNCTION %s( mp map<int, frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " mp.get(java.lang.Integer.valueOf(3)).getString(\"txt\");$$;");
+
+ execute("INSERT INTO %s (key, lst, st, mp) values (1, " +
+ // list<frozen<UDT>>
+ "[ {txt: 'one', i:1}, {txt: 'three', i:1}, {txt: 'one', i:1} ] , " +
+ // set<frozen<UDT>>
+ "{ {txt: 'one', i:1}, {txt: 'three', i:3}, {txt: 'two', i:2} }, " +
+ // map<int, frozen<UDT>>
+ "{ 1: {txt: 'one', i:1}, 2: {txt: 'one', i:3}, 3: {txt: 'two', i:2} })");
+
+ assertRows(execute("SELECT " + fName + "(lst) FROM %s WHERE key = 1"),
+ row("three"));
+ assertRows(execute("SELECT " + fName + "(st) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fName + "(mp) FROM %s WHERE key = 1"),
+ row("two"));
+
+ String cqlSelect = "SELECT " + fName + "(lst), " + fName + "(st), " + fName + "(mp) FROM %s WHERE key = 1";
+ assertRows(execute(cqlSelect),
+ row("three", "one", "two"));
+
+ // same test - but via native protocol
+ for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
+ assertRowsNet(version,
+ executeNet(version, cqlSelect),
+ row("three", "one", "two"));
+ }
+
+ @Test
+ public void testJavascriptFunction() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String functionBody = '\n' +
+ " Math.sin(val);\n";
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\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("javascript", 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 testJavascriptBadReturnType() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS '\"string\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ClassCastException
+ assertInvalidMessage("Invalid value for CQL type double", "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
+ public void testJavascriptThrow() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS 'throw \"fool\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ScriptException
+ assertInvalidThrowMessage("fool", FunctionExecutionException.class,
+ "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
+ public void testJavascriptCompileFailure() throws Throwable
+ {
+ assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS 'foo bar';");
+ }
+
+ @Test
+ public void testScriptInvalidLanguage() throws Throwable
+ {
+ assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE artificial_intelligence\n" +
+ "AS 'question for 42?';");
+ }
+
+ @Test
+ public void testScriptReturnTypeCasting() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+
+ Object[][] variations = {
+ new Object[] { "true", "boolean", true },
+ new Object[] { "false", "boolean", false },
+ new Object[] { "100", "tinyint", (byte)100 },
+ new Object[] { "100.", "tinyint", (byte)100 },
+ new Object[] { "100", "smallint", (short)100 },
+ new Object[] { "100.", "smallint", (short)100 },
+ new Object[] { "100", "int", 100 },
+ new Object[] { "100.", "int", 100 },
+ new Object[] { "100", "double", 100d },
+ new Object[] { "100.", "double", 100d },
+ new Object[] { "100", "bigint", 100L },
+ new Object[] { "100.", "bigint", 100L },
+ new Object[] { "100", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "100.", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "parseInt(\"100\");", "decimal", BigDecimal.valueOf(100d) },
+ new Object[] { "100.", "decimal", BigDecimal.valueOf(100d) },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object functionBody = variation[0];
+ Object returnType = variation[1];
+ Object expectedResult = variation[2];
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " +returnType + ' ' +
+ "LANGUAGE javascript " +
+ "AS '" + functionBody + ";';");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1d, expectedResult));
+ }
+ }
+
+ @Test
+ public void testScriptParamReturnTypes() throws Throwable
+ {
+ UUID ruuid = UUID.randomUUID();
+ UUID tuuid = UUIDGen.getTimeUUID();
+
+ createTable("CREATE TABLE %s (key int primary key, " +
+ "tival tinyint, sival smallint, ival int, lval bigint, fval float, dval double, vval varint, ddval decimal, " +
+ "timval time, dtval date, tsval timestamp, uval uuid, tuval timeuuid)");
+ execute("INSERT INTO %s (key, tival, sival, ival, lval, fval, dval, vval, ddval, timval, dtval, tsval, uval, tuval) VALUES " +
+ "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 1,
+ (byte)1, (short)1, 1, 1L, 1f, 1d, BigInteger.valueOf(1L), BigDecimal.valueOf(1d), 1L, Integer.MAX_VALUE, new Date(1), ruuid, tuuid);
+
+ Object[][] variations = {
+ new Object[] { "tinyint", "tival", (byte)1, (byte)2 },
+ new Object[] { "smallint", "sival", (short)1, (short)2 },
+ new Object[] { "int", "ival", 1, 2 },
+ new Object[] { "bigint", "lval", 1L, 2L },
+ new Object[] { "float", "fval", 1f, 2f },
+ new Object[] { "double", "dval", 1d, 2d },
+ new Object[] { "varint", "vval", BigInteger.valueOf(1L), BigInteger.valueOf(2L) },
+ new Object[] { "decimal", "ddval", BigDecimal.valueOf(1d), BigDecimal.valueOf(2d) },
+ new Object[] { "time", "timval", 1L, 2L },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val+1;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+
+ variations = new Object[][] {
+ new Object[] { "timestamp","tsval", new Date(1), new Date(1) },
+ new Object[] { "uuid", "uval", ruuid, ruuid },
+ new Object[] { "timeuuid", "tuval", tuuid, tuuid },
+ new Object[] { "date", "dtval", Integer.MAX_VALUE, Integer.MAX_VALUE },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+ }
+}
[10/25] 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/3aefe356/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
index c52e178,d4d2a10..8a743ea
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
@@@ -17,44 -17,37 +17,29 @@@
*/
package org.apache.cassandra.cql3.validation.entities;
+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 java.security.AccessControlException;
import org.junit.Assert;
-import org.junit.BeforeClass;
import org.junit.Test;
- import com.datastax.driver.core.*;
-import com.datastax.driver.core.Row;
import com.datastax.driver.core.exceptions.InvalidQueryException;
--import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.config.Schema;
- 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.config.Config;
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.cql3.functions.UDHelper;
import org.apache.cassandra.db.marshal.CollectionType;
- import org.apache.cassandra.exceptions.FunctionExecutionException;
-import org.apache.cassandra.dht.ByteOrderedPartitioner;
import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.schema.KeyspaceMetadata;
import org.apache.cassandra.service.ClientState;
- import org.apache.cassandra.service.ClientWarn;
import org.apache.cassandra.transport.Event;
import org.apache.cassandra.transport.Server;
import org.apache.cassandra.transport.messages.ResultMessage;
-import org.apache.cassandra.utils.UUIDGen;
+import org.apache.cassandra.utils.ByteBufferUtil;
- import org.apache.cassandra.utils.UUIDGen;
public class UFTest extends CQLTester
{
@@@ -1017,320 -724,115 +710,6 @@@
}
@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 : PROTOCOL_VERSIONS)
- 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));
-
- // same test - but via native protocol
- // we use protocol V3 here to encode the expected version because the server
- // always serializes Collections using V3 - see CollectionSerializer's
- // serialize and deserialize methods.
- TupleType tType = tupleTypeOf(Server.VERSION_3,
- 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 : PROTOCOL_VERSIONS)
- {
- 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 : PROTOCOL_VERSIONS)
- {
- 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 : PROTOCOL_VERSIONS)
- {
- 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)");
@@@ -1593,162 -880,140 +757,7 @@@
"AS '\"foo bar\";';");
}
- private static class TypesTestDef
- {
- final String udfType;
- final String tableType;
- final String columnName;
- final Object referenceValue;
-
- String fCheckArgAndReturn;
-
- String fCalledOnNull;
- String fReturnsNullOnNull;
-
- TypesTestDef(String udfType, String tableType, String columnName, Object referenceValue)
- {
- this.udfType = udfType;
- this.tableType = tableType;
- this.columnName = columnName;
- this.referenceValue = referenceValue;
- }
- }
-
- @Test
- public void testTypesWithAndWithoutNulls() throws Throwable
- {
- // test various combinations of types against UDFs with CALLED ON NULL or RETURNS NULL ON NULL
-
- String type = createType("CREATE TYPE %s (txt text, i int)");
-
- TypesTestDef[] typeDefs =
- {
- // udf type, table type, column, reference value
- new TypesTestDef("timestamp", "timestamp", "ts", new Date()),
- new TypesTestDef("date", "date", "dt", 12345),
- new TypesTestDef("time", "time", "tim", 12345L),
- new TypesTestDef("uuid", "uuid", "uu", UUID.randomUUID()),
- new TypesTestDef("timeuuid", "timeuuid", "tu", UUIDGen.getTimeUUID()),
- new TypesTestDef("tinyint", "tinyint", "ti", (byte) 42),
- new TypesTestDef("smallint", "smallint", "si", (short) 43),
- new TypesTestDef("int", "int", "i", 44),
- new TypesTestDef("bigint", "bigint", "b", 45L),
- new TypesTestDef("float", "float", "f", 46f),
- new TypesTestDef("double", "double", "d", 47d),
- new TypesTestDef("boolean", "boolean", "x", true),
- new TypesTestDef("ascii", "ascii", "a", "tqbfjutld"),
- new TypesTestDef("text", "text", "t", "k\u00f6lsche jung"),
- //new TypesTestDef(type, "frozen<" + type + '>', "u", null),
- new TypesTestDef("tuple<int, text>", "frozen<tuple<int, text>>", "tup", tuple(1, "foo"))
- };
-
- String createTableDDL = "CREATE TABLE %s (key int PRIMARY KEY";
- String insertDML = "INSERT INTO %s (key";
- List<Object> values = new ArrayList<>();
- for (TypesTestDef typeDef : typeDefs)
- {
- createTableDDL += ", " + typeDef.columnName + ' ' + typeDef.tableType;
- insertDML += ", " + typeDef.columnName;
- String typeName = typeDef.udfType;
- typeDef.fCheckArgAndReturn = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS " + typeName + ' ' +
- "LANGUAGE java\n" +
- "AS 'return val;';");
- typeDef.fCalledOnNull = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return \"called\";';");
- typeDef.fReturnsNullOnNull = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return \"called\";';");
- values.add(typeDef.referenceValue);
- }
-
- createTableDDL += ')';
- createTable(createTableDDL);
-
- insertDML += ") VALUES (1";
- for (TypesTestDef ignored : typeDefs)
- insertDML += ", ?";
- insertDML += ')';
-
- execute(insertDML, values.toArray());
-
- // second row with null values
- for (int i = 0; i < values.size(); i++)
- values.set(i, null);
- execute(insertDML.replace('1', '2'), values.toArray());
-
- // check argument input + return
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCheckArgAndReturn + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ typeDef.referenceValue }));
- }
-
- // check for CALLED ON NULL INPUT with non-null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ "called" }));
- }
-
- // check for CALLED ON NULL INPUT with null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
- row(new Object[]{ "called" }));
- }
-
- // check for RETURNS NULL ON NULL INPUT with non-null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ "called" }));
- }
-
- // check for RETURNS NULL ON NULL INPUT with null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
- row(new Object[]{ null }));
- }
-
- }
-
@Test
- public void testJavascriptCompileFailure() throws Throwable
- {
- assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS 'foo bar';");
- }
-
- @Test
- public void testScriptInvalidLanguage() throws Throwable
- {
- assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE artificial_intelligence\n" +
- "AS 'question for 42?';");
- }
-
- static class TypesTestDef
- {
- final String udfType;
- final String tableType;
- final String columnName;
- final Object referenceValue;
-
- String fCheckArgAndReturn;
-
- String fCalledOnNull;
- String fReturnsNullOnNull;
-
- TypesTestDef(String udfType, String tableType, String columnName, Object referenceValue)
- {
- this.udfType = udfType;
- this.tableType = tableType;
- this.columnName = columnName;
- this.referenceValue = referenceValue;
- }
- }
-
- @Test
- public void testTypesWithAndWithoutNulls() throws Throwable
- {
- // test various combinations of types against UDFs with CALLED ON NULL or RETURNS NULL ON NULL
-
- String type = createType("CREATE TYPE %s (txt text, i int)");
-
- TypesTestDef[] typeDefs =
- {
- // udf type, table type, column, reference value
- new TypesTestDef("timestamp", "timestamp", "ts", new Date()),
- new TypesTestDef("date", "date", "dt", 12345),
- new TypesTestDef("time", "time", "tim", 12345L),
- new TypesTestDef("uuid", "uuid", "uu", UUID.randomUUID()),
- new TypesTestDef("timeuuid", "timeuuid", "tu", UUIDGen.getTimeUUID()),
- new TypesTestDef("tinyint", "tinyint", "ti", (byte) 42),
- new TypesTestDef("smallint", "smallint", "si", (short) 43),
- new TypesTestDef("int", "int", "i", 44),
- new TypesTestDef("bigint", "bigint", "b", 45L),
- new TypesTestDef("float", "float", "f", 46f),
- new TypesTestDef("double", "double", "d", 47d),
- new TypesTestDef("boolean", "boolean", "x", true),
- new TypesTestDef("ascii", "ascii", "a", "tqbfjutld"),
- new TypesTestDef("text", "text", "t", "k\u00f6lsche jung"),
- //new TypesTestDef(type, "frozen<" + type + '>', "u", null),
- new TypesTestDef("tuple<int, text>", "frozen<tuple<int, text>>", "tup", tuple(1, "foo"))
- };
-
- String createTableDDL = "CREATE TABLE %s (key int PRIMARY KEY";
- String insertDML = "INSERT INTO %s (key";
- List<Object> values = new ArrayList<>();
- for (TypesTestDef typeDef : typeDefs)
- {
- createTableDDL += ", " + typeDef.columnName + ' ' + typeDef.tableType;
- insertDML += ", " + typeDef.columnName;
- String typeName = typeDef.udfType;
- typeDef.fCheckArgAndReturn = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS " + typeName + ' ' +
- "LANGUAGE java\n" +
- "AS 'return val;';");
- typeDef.fCalledOnNull = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return \"called\";';");
- typeDef.fReturnsNullOnNull = createFunction(KEYSPACE,
- typeName,
- "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return \"called\";';");
- values.add(typeDef.referenceValue);
- }
-
- createTableDDL += ')';
- createTable(createTableDDL);
-
- insertDML += ") VALUES (1";
- for (TypesTestDef ignored : typeDefs)
- insertDML += ", ?";
- insertDML += ')';
-
- execute(insertDML, values.toArray());
-
- // second row with null values
- for (int i = 0; i < values.size(); i++)
- values.set(i, null);
- execute(insertDML.replace('1', '2'), values.toArray());
-
- // check argument input + return
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCheckArgAndReturn + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ typeDef.referenceValue }));
- }
-
- // check for CALLED ON NULL INPUT with non-null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ "called" }));
- }
-
- // check for CALLED ON NULL INPUT with null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
- row(new Object[]{ "called" }));
- }
-
- // check for RETURNS NULL ON NULL INPUT with non-null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
- row(new Object[]{ "called" }));
- }
-
- // check for RETURNS NULL ON NULL INPUT with null arguments
- for (TypesTestDef typeDef : typeDefs)
- {
- assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
- row(new Object[]{ null }));
- }
-
- }
-
- @Test
public void testReplaceAllowNulls() throws Throwable
{
String fNulls = createFunction(KEYSPACE,
@@@ -1851,638 -1108,4 +860,112 @@@
}
}
}
- @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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<set<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS set<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<list<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS list<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<map<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS map<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<tuple<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, "(NULL,NULL)"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, "(1,2)"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, "(4,5)"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, "(7,8)"));
-
- functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS tuple<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
- }
-
- @Test
- public void testFunctionWithFrozenUDType() 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, 0);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<" + myType + "> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, "{f:0}"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, "{f:1}"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, "{f:4}"));
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, "{f:7}"));
-
- functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS " + myType + " " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
- }
+
+ @Test
+ public void testEmptyString() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, sval text, aval ascii, bval blob, empty_int int)");
+ execute("INSERT INTO %s (key, sval, aval, bval, empty_int) VALUES (?, ?, ?, ?, blobAsInt(0x))", 1, "", "", ByteBuffer.allocate(0));
+
+ String fNameSRC = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameSCC = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return \"\";'");
+
+ String fNameSRN = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameSCN = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return \"\";'");
+
+ String fNameBRC = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameBCC = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return ByteBuffer.allocate(0);'");
+
+ String fNameBRN = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameBCN = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return ByteBuffer.allocate(0);'");
+
+ String fNameIRC = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameICC = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ String fNameIRN = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameICN = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ assertRows(execute("SELECT " + fNameSRC + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRN + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCC + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCN + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRC + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRN + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCC + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCN + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameBRC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBRN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBCC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBCN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameIRC + "(empty_int) FROM %s"), row(new Object[]{ null }));
+ assertRows(execute("SELECT " + fNameIRN + "(empty_int) FROM %s"), row(new Object[]{ null }));
+ assertRows(execute("SELECT " + fNameICC + "(empty_int) FROM %s"), row(0));
+ assertRows(execute("SELECT " + fNameICN + "(empty_int) FROM %s"), row(new Object[]{ null }));
+ }
-
- @Test
- public void testAllNativeTypes() throws Throwable
- {
- StringBuilder sig = new StringBuilder();
- StringBuilder args = new StringBuilder();
- for (CQL3Type.Native type : CQL3Type.Native.values())
- {
- if (type == CQL3Type.Native.EMPTY)
- continue;
-
- if (sig.length() > 0)
- sig.append(',');
- sig.append(type.toString());
-
- if (args.length() > 0)
- args.append(',');
- args.append("arg").append(type.toString()).append(' ').append(type.toString());
- }
- createFunction(KEYSPACE, sig.toString(),
- "CREATE OR REPLACE FUNCTION %s(" + args + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- for (CQL3Type.Native type : CQL3Type.Native.values())
- {
- if (type == CQL3Type.Native.EMPTY)
- continue;
-
- createFunction(KEYSPACE_PER_TEST, type.toString(),
- "CREATE OR REPLACE FUNCTION %s(val " + type.toString() + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
- }
- }
-
- @Test
- public void testSecurityPermissions() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, dval double)");
- execute("INSERT INTO %s (key, dval) VALUES (?, ?)", 1, 1d);
-
- // Java UDFs
-
- try
- {
- 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 'System.getProperty(\"foo.bar.baz\"); return 0d;';");
- execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
- Assert.fail();
- }
- catch (FunctionExecutionException e)
- {
- assertAccessControlException("System.getProperty(\"foo.bar.baz\"); return 0d;", e);
- }
-
- String[][] typesAndSources =
- {
- {"", "try { Class.forName(\"" + UDHelper.class.getName() + "\"); } catch (Exception e) { throw new RuntimeException(e); } return 0d;"},
- {"sun.misc.Unsafe", "sun.misc.Unsafe.getUnsafe(); return 0d;"},
- {"", "try { Class.forName(\"sun.misc.Unsafe\"); } catch (Exception e) { throw new RuntimeException(e); } return 0d;"},
- {"java.nio.file.FileSystems", "try {" +
- " java.nio.file.FileSystems.getDefault(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.nio.channels.FileChannel", "try {" +
- " java.nio.channels.FileChannel.open(java.nio.file.FileSystems.getDefault().getPath(\"/etc/passwd\")).close(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.nio.channels.SocketChannel", "try {" +
- " java.nio.channels.SocketChannel.open().close(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.io.FileInputStream", "try {" +
- " new java.io.FileInputStream(\"./foobar\").close(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.lang.Runtime", "try {" +
- " java.lang.Runtime.getRuntime(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"org.apache.cassandra.service.StorageService",
- "try {" +
- " org.apache.cassandra.service.StorageService v = org.apache.cassandra.service.StorageService.instance; v.isShutdown(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.net.ServerSocket", "try {" +
- " new java.net.ServerSocket().bind(); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.io.FileOutputStream","try {" +
- " new java.io.FileOutputStream(\".foo\"); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'},
- {"java.lang.Runtime", "try {" +
- " java.lang.Runtime.getRuntime().exec(\"/tmp/foo\"); return 0d;" +
- "} catch (Exception t) {" +
- " throw new RuntimeException(t);" +
- '}'}
- };
-
- for (String[] typeAndSource : typesAndSources)
- {
- assertInvalidMessage(typeAndSource[0] + " cannot be resolved",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".invalid_class_access(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE JAVA\n" +
- "AS '" + typeAndSource[1] + "';");
- }
-
- // JavaScript UDFs
-
- try
- {
- String fName = createFunction(KEYSPACE_PER_TEST, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS 'org.apache.cassandra.service.StorageService.instance.isShutdown(); 0;';");
- execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
- Assert.fail("Javascript security check failed");
- }
- catch (FunctionExecutionException e)
- {
- assertAccessControlException("", e);
- }
-
- String[] javascript =
- {
- "java.lang.management.ManagmentFactory.getThreadMXBean(); 0;",
- "new java.io.FileInputStream(\"/tmp/foo\"); 0;",
- "new java.io.FileOutputStream(\"/tmp/foo\"); 0;",
- "java.nio.file.FileSystems.getDefault().createFileExclusively(\"./foo_bar_baz\"); 0;",
- "java.nio.channels.FileChannel.open(java.nio.file.FileSystems.getDefault().getPath(\"/etc/passwd\")); 0;",
- "java.nio.channels.SocketChannel.open(); 0;",
- "new java.net.ServerSocket().bind(null); 0;",
- "var thread = new java.lang.Thread(); thread.start(); 0;",
- "java.lang.System.getProperty(\"foo.bar.baz\"); 0;",
- "java.lang.Class.forName(\"java.lang.System\"); 0;",
- "java.lang.Runtime.getRuntime().exec(\"/tmp/foo\"); 0;",
- "java.lang.Runtime.getRuntime().loadLibrary(\"foobar\"); 0;",
- "java.lang.Runtime.getRuntime().loadLibrary(\"foobar\"); 0;",
- // TODO these (ugly) calls are still possible - these can consume CPU (as one could do with an evil loop, too)
- // "java.lang.Runtime.getRuntime().traceMethodCalls(true); 0;",
- // "java.lang.Runtime.getRuntime().gc(); 0;",
- // "java.lang.Runtime.getRuntime(); 0;",
- };
-
- for (String script : javascript)
- {
- try
- {
- String fName = createFunction(KEYSPACE_PER_TEST, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS '" + script + "';");
- execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
- Assert.fail("Javascript security check failed: " + script);
- }
- catch (FunctionExecutionException e)
- {
- assertAccessControlException(script, e);
- }
- }
- }
-
- private static void assertAccessControlException(String script, FunctionExecutionException e)
- {
- for (Throwable t = e; t != null && t != t.getCause(); t = t.getCause())
- if (t instanceof AccessControlException)
- return;
- Assert.fail("no AccessControlException for " + script + " (got " + e + ')');
- }
-
- @Test
- public void testAmokUDF() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, dval double)");
- execute("INSERT INTO %s (key, dval) VALUES (?, ?)", 1, 1d);
-
- long udfWarnTimeout = DatabaseDescriptor.getUserDefinedFunctionWarnTimeout();
- long udfFailTimeout = DatabaseDescriptor.getUserDefinedFunctionFailTimeout();
- int maxTries = 5;
- for (int i = 1; i <= maxTries; i++)
- {
- try
- {
- // short timeout
- DatabaseDescriptor.setUserDefinedFunctionWarnTimeout(10);
- DatabaseDescriptor.setUserDefinedFunctionFailTimeout(250);
- // don't kill the unit test... - default policy is "die"
- DatabaseDescriptor.setUserFunctionTimeoutPolicy(Config.UserFunctionTimeoutPolicy.ignore);
-
- ClientWarn.instance.captureWarnings();
- 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 'long t=System.currentTimeMillis()+110; while (t>System.currentTimeMillis()) { }; return 0d;'");
- execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
- List<String> warnings = ClientWarn.instance.getWarnings();
- Assert.assertNotNull(warnings);
- Assert.assertFalse(warnings.isEmpty());
- ClientWarn.instance.resetWarnings();
-
- // Java UDF
-
- fName = createFunction(KEYSPACE_PER_TEST, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE JAVA\n" +
- "AS 'long t=System.currentTimeMillis()+500; while (t>System.currentTimeMillis()) { }; return 0d;';");
- assertInvalidMessage("ran longer than 250ms", "SELECT " + fName + "(dval) FROM %s WHERE key=1");
-
- // Javascript UDF
-
- fName = createFunction(KEYSPACE_PER_TEST, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE JAVASCRIPT\n" +
- "AS 'var t=java.lang.System.currentTimeMillis()+500; while (t>java.lang.System.currentTimeMillis()) { }; 0;';");
- assertInvalidMessage("ran longer than 250ms", "SELECT " + fName + "(dval) FROM %s WHERE key=1");
-
- return;
- }
- catch (Error | RuntimeException e)
- {
- if (i == maxTries)
- throw e;
- }
- finally
- {
- // reset to defaults
- DatabaseDescriptor.setUserDefinedFunctionWarnTimeout(udfWarnTimeout);
- DatabaseDescriptor.setUserDefinedFunctionFailTimeout(udfFailTimeout);
- }
- }
- }
}
[11/25] 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/3aefe356/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
index 0000000,d3050a5..af3c894
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
@@@ -1,0 -1,504 +1,428 @@@
+ /*
+ * 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.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.TupleType;
-import com.datastax.driver.core.TupleValue;
+ import org.apache.cassandra.config.DatabaseDescriptor;
+ import org.apache.cassandra.cql3.CQLTester;
+ import org.apache.cassandra.cql3.UntypedResultSet;
+ import org.apache.cassandra.cql3.functions.FunctionName;
-import org.apache.cassandra.dht.ByteOrderedPartitioner;
+ import org.apache.cassandra.exceptions.FunctionExecutionException;
-import org.apache.cassandra.transport.Server;
+ import org.apache.cassandra.utils.UUIDGen;
+
+ public class UFScriptTest extends CQLTester
+ {
- @BeforeClass
- public static void setUp()
- {
- DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance);
- }
++ // Just JavaScript UDFs to check how UDF - especially security/class-loading/sandboxing stuff -
++ // behaves, if no Java UDF has been executed before.
++
++ // Do not add any other test here - especially none using Java UDFs
+
+ @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++)
++ for (int version : PROTOCOL_VERSIONS)
+ 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"),
- row(1d));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup3 + "(tup) FROM %s WHERE key = 1"),
- row(list));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup4 + "(tup) FROM %s WHERE key = 1"),
- row(set));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup5 + "(tup) FROM %s WHERE key = 1"),
- row(map));
- }
- }
-
- @Test
+ public void testJavascriptUserType() throws Throwable
+ {
+ String type = createType("CREATE TYPE %s (txt text, i int)");
+
+ createTable("CREATE TABLE %s (key int primary key, udt frozen<" + type + ">)");
+
+ String fUdt1 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
- "RETURNS " + type + " " +
++ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt;$$;");
+ String fUdt2 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getString(\"txt\");$$;");
+ String fUdt3 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getInt(\"i\");$$;");
+
+ execute("INSERT INTO %s (key, udt) VALUES (1, {txt: 'one', i:1})");
+
+ UntypedResultSet rows = execute("SELECT " + fUdt1 + "(udt) FROM %s WHERE key = 1");
+ Assert.assertEquals(1, rows.size());
+ assertRows(execute("SELECT " + fUdt2 + "(udt) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fUdt3 + "(udt) FROM %s WHERE key = 1"),
+ row(1));
+ }
+
+ @Test
+ public void testJavascriptUTCollections() throws Throwable
+ {
+ String type = 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 fName = createFunction(KEYSPACE, "list<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( lst list<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " lst.get(1).getString(\"txt\");$$;");
+ createFunctionOverload(fName, "set<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( st set<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " st.iterator().next().getString(\"txt\");$$;");
+ createFunctionOverload(fName, "map<int, frozen<" + type + ">>",
+ "CREATE FUNCTION %s( mp map<int, frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " mp.get(java.lang.Integer.valueOf(3)).getString(\"txt\");$$;");
+
+ execute("INSERT INTO %s (key, lst, st, mp) values (1, " +
+ // list<frozen<UDT>>
+ "[ {txt: 'one', i:1}, {txt: 'three', i:1}, {txt: 'one', i:1} ] , " +
+ // set<frozen<UDT>>
+ "{ {txt: 'one', i:1}, {txt: 'three', i:3}, {txt: 'two', i:2} }, " +
+ // map<int, frozen<UDT>>
+ "{ 1: {txt: 'one', i:1}, 2: {txt: 'one', i:3}, 3: {txt: 'two', i:2} })");
+
+ assertRows(execute("SELECT " + fName + "(lst) FROM %s WHERE key = 1"),
+ row("three"));
+ assertRows(execute("SELECT " + fName + "(st) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fName + "(mp) FROM %s WHERE key = 1"),
+ row("two"));
+
+ String cqlSelect = "SELECT " + fName + "(lst), " + fName + "(st), " + fName + "(mp) FROM %s WHERE key = 1";
+ assertRows(execute(cqlSelect),
+ row("three", "one", "two"));
+
+ // same test - but via native protocol
- for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
++ for (int version : PROTOCOL_VERSIONS)
+ assertRowsNet(version,
+ executeNet(version, cqlSelect),
+ row("three", "one", "two"));
+ }
+
+ @Test
+ public void testJavascriptFunction() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String functionBody = '\n' +
+ " Math.sin(val);\n";
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS '" + functionBody + "';");
+
+ FunctionName fNameName = parseFunctionName(fName);
+
- assertRows(execute("SELECT language, body FROM system.schema_functions WHERE keyspace_name=? AND function_name=?",
++ assertRows(execute("SELECT language, body FROM system_schema.functions WHERE keyspace_name=? AND function_name=?",
+ fNameName.keyspace, fNameName.name),
+ row("javascript", 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 testJavascriptBadReturnType() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS '\"string\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ClassCastException
+ assertInvalidMessage("Invalid value for CQL type double", "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
+ public void testJavascriptThrow() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS 'throw \"fool\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ScriptException
+ assertInvalidThrowMessage("fool", FunctionExecutionException.class,
+ "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
- public void testJavascriptCompileFailure() throws Throwable
- {
- assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS 'foo bar';");
- }
-
- @Test
- public void testScriptInvalidLanguage() throws Throwable
- {
- assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE artificial_intelligence\n" +
- "AS 'question for 42?';");
- }
-
- @Test
+ public void testScriptReturnTypeCasting() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+
+ Object[][] variations = {
+ new Object[] { "true", "boolean", true },
+ new Object[] { "false", "boolean", false },
+ new Object[] { "100", "tinyint", (byte)100 },
+ new Object[] { "100.", "tinyint", (byte)100 },
+ new Object[] { "100", "smallint", (short)100 },
+ new Object[] { "100.", "smallint", (short)100 },
+ new Object[] { "100", "int", 100 },
+ new Object[] { "100.", "int", 100 },
+ new Object[] { "100", "double", 100d },
+ new Object[] { "100.", "double", 100d },
+ new Object[] { "100", "bigint", 100L },
+ new Object[] { "100.", "bigint", 100L },
+ new Object[] { "100", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "100.", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "parseInt(\"100\");", "decimal", BigDecimal.valueOf(100d) },
+ new Object[] { "100.", "decimal", BigDecimal.valueOf(100d) },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object functionBody = variation[0];
+ Object returnType = variation[1];
+ Object expectedResult = variation[2];
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " +returnType + ' ' +
+ "LANGUAGE javascript " +
+ "AS '" + functionBody + ";';");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1d, expectedResult));
+ }
+ }
+
+ @Test
+ public void testScriptParamReturnTypes() throws Throwable
+ {
+ UUID ruuid = UUID.randomUUID();
+ UUID tuuid = UUIDGen.getTimeUUID();
+
+ createTable("CREATE TABLE %s (key int primary key, " +
+ "tival tinyint, sival smallint, ival int, lval bigint, fval float, dval double, vval varint, ddval decimal, " +
+ "timval time, dtval date, tsval timestamp, uval uuid, tuval timeuuid)");
+ execute("INSERT INTO %s (key, tival, sival, ival, lval, fval, dval, vval, ddval, timval, dtval, tsval, uval, tuval) VALUES " +
+ "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 1,
+ (byte)1, (short)1, 1, 1L, 1f, 1d, BigInteger.valueOf(1L), BigDecimal.valueOf(1d), 1L, Integer.MAX_VALUE, new Date(1), ruuid, tuuid);
+
+ Object[][] variations = {
+ new Object[] { "tinyint", "tival", (byte)1, (byte)2 },
+ new Object[] { "smallint", "sival", (short)1, (short)2 },
+ new Object[] { "int", "ival", 1, 2 },
+ new Object[] { "bigint", "lval", 1L, 2L },
+ new Object[] { "float", "fval", 1f, 2f },
+ new Object[] { "double", "dval", 1d, 2d },
+ new Object[] { "varint", "vval", BigInteger.valueOf(1L), BigInteger.valueOf(2L) },
+ new Object[] { "decimal", "ddval", BigDecimal.valueOf(1d), BigDecimal.valueOf(2d) },
+ new Object[] { "time", "timval", 1L, 2L },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val+1;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+
+ variations = new Object[][] {
+ new Object[] { "timestamp","tsval", new Date(1), new Date(1) },
+ new Object[] { "uuid", "uval", ruuid, ruuid },
+ new Object[] { "timeuuid", "tuval", tuuid, tuuid },
+ new Object[] { "date", "dtval", Integer.MAX_VALUE, Integer.MAX_VALUE },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+ }
++
++ @Test
++ public void testJavascriptDisabled() throws Throwable
++ {
++ createTable("CREATE TABLE %s (key int primary key, val double)");
++
++ DatabaseDescriptor.enableScriptedUserDefinedFunctions(false);
++ try
++ {
++ assertInvalid("double",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".assertNotEnabled(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE javascript\n" +
++ "AS 'Math.sin(val);';");
++ }
++ finally
++ {
++ DatabaseDescriptor.enableScriptedUserDefinedFunctions(true);
++ }
++ }
++
++ @Test
++ public void testJavascriptCompileFailure() throws Throwable
++ {
++ assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE javascript\n" +
++ "AS 'foo bar';");
++ }
++
++ @Test
++ public void testScriptInvalidLanguage() throws Throwable
++ {
++ assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE artificial_intelligence\n" +
++ "AS 'question for 42?';");
++ }
+ }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/3aefe356/test/unit/org/apache/cassandra/cql3/validation/entities/UFSecurityTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFSecurityTest.java
index 0000000,0000000..5c7ca2b
new file mode 100644
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFSecurityTest.java
@@@ -1,0 -1,0 +1,258 @@@
++/*
++ * 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.security.AccessControlException;
++import java.util.List;
++
++import org.junit.Assert;
++import org.junit.Test;
++
++import org.apache.cassandra.config.Config;
++import org.apache.cassandra.config.DatabaseDescriptor;
++import org.apache.cassandra.cql3.CQLTester;
++import org.apache.cassandra.cql3.functions.UDHelper;
++import org.apache.cassandra.exceptions.FunctionExecutionException;
++import org.apache.cassandra.service.ClientWarn;
++
++public class UFSecurityTest extends CQLTester
++{
++ @Test
++ public void testSecurityPermissions() throws Throwable
++ {
++ createTable("CREATE TABLE %s (key int primary key, dval double)");
++ execute("INSERT INTO %s (key, dval) VALUES (?, ?)", 1, 1d);
++
++ // Java UDFs
++
++ try
++ {
++ 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 'System.getProperty(\"foo.bar.baz\"); return 0d;';");
++ execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
++ Assert.fail();
++ }
++ catch (FunctionExecutionException e)
++ {
++ assertAccessControlException("System.getProperty(\"foo.bar.baz\"); return 0d;", e);
++ }
++
++ String[][] typesAndSources =
++ {
++ {"", "try { Class.forName(\"" + UDHelper.class.getName() + "\"); } catch (Exception e) { throw new RuntimeException(e); } return 0d;"},
++ {"sun.misc.Unsafe", "sun.misc.Unsafe.getUnsafe(); return 0d;"},
++ {"", "try { Class.forName(\"sun.misc.Unsafe\"); } catch (Exception e) { throw new RuntimeException(e); } return 0d;"},
++ {"java.nio.file.FileSystems", "try {" +
++ " java.nio.file.FileSystems.getDefault(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.nio.channels.FileChannel", "try {" +
++ " java.nio.channels.FileChannel.open(java.nio.file.FileSystems.getDefault().getPath(\"/etc/passwd\")).close(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.nio.channels.SocketChannel", "try {" +
++ " java.nio.channels.SocketChannel.open().close(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.io.FileInputStream", "try {" +
++ " new java.io.FileInputStream(\"./foobar\").close(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.lang.Runtime", "try {" +
++ " java.lang.Runtime.getRuntime(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"org.apache.cassandra.service.StorageService",
++ "try {" +
++ " org.apache.cassandra.service.StorageService v = org.apache.cassandra.service.StorageService.instance; v.isShutdown(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.net.ServerSocket", "try {" +
++ " new java.net.ServerSocket().bind(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.io.FileOutputStream","try {" +
++ " new java.io.FileOutputStream(\".foo\"); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.lang.Runtime", "try {" +
++ " java.lang.Runtime.getRuntime().exec(\"/tmp/foo\"); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'}
++ };
++
++ for (String[] typeAndSource : typesAndSources)
++ {
++ assertInvalidMessage(typeAndSource[0] + " cannot be resolved",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".invalid_class_access(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE JAVA\n" +
++ "AS '" + typeAndSource[1] + "';");
++ }
++
++ // JavaScript UDFs
++
++ try
++ {
++ String fName = createFunction(KEYSPACE_PER_TEST, "double",
++ "CREATE OR REPLACE FUNCTION %s(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE javascript\n" +
++ "AS 'org.apache.cassandra.service.StorageService.instance.isShutdown(); 0;';");
++ execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
++ Assert.fail("Javascript security check failed");
++ }
++ catch (FunctionExecutionException e)
++ {
++ assertAccessControlException("", e);
++ }
++
++ String[] javascript =
++ {
++ "java.lang.management.ManagmentFactory.getThreadMXBean(); 0;",
++ "new java.io.FileInputStream(\"/tmp/foo\"); 0;",
++ "new java.io.FileOutputStream(\"/tmp/foo\"); 0;",
++ "java.nio.file.FileSystems.getDefault().createFileExclusively(\"./foo_bar_baz\"); 0;",
++ "java.nio.channels.FileChannel.open(java.nio.file.FileSystems.getDefault().getPath(\"/etc/passwd\")); 0;",
++ "java.nio.channels.SocketChannel.open(); 0;",
++ "new java.net.ServerSocket().bind(null); 0;",
++ "var thread = new java.lang.Thread(); thread.start(); 0;",
++ "java.lang.System.getProperty(\"foo.bar.baz\"); 0;",
++ "java.lang.Class.forName(\"java.lang.System\"); 0;",
++ "java.lang.Runtime.getRuntime().exec(\"/tmp/foo\"); 0;",
++ "java.lang.Runtime.getRuntime().loadLibrary(\"foobar\"); 0;",
++ "java.lang.Runtime.getRuntime().loadLibrary(\"foobar\"); 0;",
++ // TODO these (ugly) calls are still possible - these can consume CPU (as one could do with an evil loop, too)
++// "java.lang.Runtime.getRuntime().traceMethodCalls(true); 0;",
++// "java.lang.Runtime.getRuntime().gc(); 0;",
++// "java.lang.Runtime.getRuntime(); 0;",
++ };
++
++ for (String script : javascript)
++ {
++ try
++ {
++ String fName = createFunction(KEYSPACE_PER_TEST, "double",
++ "CREATE OR REPLACE FUNCTION %s(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE javascript\n" +
++ "AS '" + script + "';");
++ execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
++ Assert.fail("Javascript security check failed: " + script);
++ }
++ catch (FunctionExecutionException e)
++ {
++ assertAccessControlException(script, e);
++ }
++ }
++ }
++
++ private static void assertAccessControlException(String script, FunctionExecutionException e)
++ {
++ for (Throwable t = e; t != null && t != t.getCause(); t = t.getCause())
++ if (t instanceof AccessControlException)
++ return;
++ Assert.fail("no AccessControlException for " + script + " (got " + e + ')');
++ }
++
++ @Test
++ public void testAmokUDF() throws Throwable
++ {
++ createTable("CREATE TABLE %s (key int primary key, dval double)");
++ execute("INSERT INTO %s (key, dval) VALUES (?, ?)", 1, 1d);
++
++ long udfWarnTimeout = DatabaseDescriptor.getUserDefinedFunctionWarnTimeout();
++ long udfFailTimeout = DatabaseDescriptor.getUserDefinedFunctionFailTimeout();
++ int maxTries = 5;
++ for (int i = 1; i <= maxTries; i++)
++ {
++ try
++ {
++ // short timeout
++ DatabaseDescriptor.setUserDefinedFunctionWarnTimeout(10);
++ DatabaseDescriptor.setUserDefinedFunctionFailTimeout(250);
++ // don't kill the unit test... - default policy is "die"
++ DatabaseDescriptor.setUserFunctionTimeoutPolicy(Config.UserFunctionTimeoutPolicy.ignore);
++
++ ClientWarn.instance.captureWarnings();
++ 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 'long t=System.currentTimeMillis()+110; while (t>System.currentTimeMillis()) { }; return 0d;'");
++ execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
++ List<String> warnings = ClientWarn.instance.getWarnings();
++ Assert.assertNotNull(warnings);
++ Assert.assertFalse(warnings.isEmpty());
++ ClientWarn.instance.resetWarnings();
++
++ // Java UDF
++
++ fName = createFunction(KEYSPACE_PER_TEST, "double",
++ "CREATE OR REPLACE FUNCTION %s(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE JAVA\n" +
++ "AS 'long t=System.currentTimeMillis()+500; while (t>System.currentTimeMillis()) { }; return 0d;';");
++ assertInvalidMessage("ran longer than 250ms", "SELECT " + fName + "(dval) FROM %s WHERE key=1");
++
++ // Javascript UDF
++
++ fName = createFunction(KEYSPACE_PER_TEST, "double",
++ "CREATE OR REPLACE FUNCTION %s(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE JAVASCRIPT\n" +
++ "AS 'var t=java.lang.System.currentTimeMillis()+500; while (t>java.lang.System.currentTimeMillis()) { }; 0;';");
++ assertInvalidMessage("ran longer than 250ms", "SELECT " + fName + "(dval) FROM %s WHERE key=1");
++
++ return;
++ }
++ catch (Error | RuntimeException e)
++ {
++ if (i == maxTries)
++ throw e;
++ }
++ finally
++ {
++ // reset to defaults
++ DatabaseDescriptor.setUserDefinedFunctionWarnTimeout(udfWarnTimeout);
++ DatabaseDescriptor.setUserDefinedFunctionFailTimeout(udfFailTimeout);
++ }
++ }
++ }
++
++}
[06/25] cassandra git commit: testall failure in
org.apache.cassandra.cql3.validation.entities.UFTest.testAllNativeTypes
Posted by sn...@apache.org.
testall failure in org.apache.cassandra.cql3.validation.entities.UFTest.testAllNativeTypes
patch by Robert Stupp; reviewed by Alex Petrov for CASSANDRA-12817
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/0b97c5d1
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/0b97c5d1
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/0b97c5d1
Branch: refs/heads/cassandra-3.X
Commit: 0b97c5d1f717be30a04c59c766465d9c62a4e9ee
Parents: 2e93398
Author: Robert Stupp <sn...@snazy.de>
Authored: Wed Dec 7 13:06:55 2016 +0100
Committer: Robert Stupp <sn...@snazy.de>
Committed: Wed Dec 7 13:06:55 2016 +0100
----------------------------------------------------------------------
.../cql3/validation/entities/UFJavaTest.java | 1177 +++++++++++++
.../cql3/validation/entities/UFScriptTest.java | 504 ++++++
.../cql3/validation/entities/UFTest.java | 1608 +-----------------
3 files changed, 1696 insertions(+), 1593 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0b97c5d1/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
new file mode 100644
index 0000000..caef808
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
@@ -0,0 +1,1177 @@
+/*
+ * 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.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+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 org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.cql3.CQL3Type;
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.cql3.UntypedResultSet;
+import org.apache.cassandra.cql3.functions.FunctionName;
+import org.apache.cassandra.cql3.functions.Functions;
+import org.apache.cassandra.dht.ByteOrderedPartitioner;
+import org.apache.cassandra.exceptions.FunctionExecutionException;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.transport.Server;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+public class UFJavaTest extends CQLTester
+{
+ @BeforeClass
+ public static void setUp()
+ {
+ DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance);
+ }
+
+
+ @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 testJavaFunctionCounter() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val counter)");
+
+ String fName = createFunction(KEYSPACE, "counter",
+ "CREATE OR REPLACE FUNCTION %s(val counter) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS bigint " +
+ "LANGUAGE JAVA " +
+ "AS 'return val + 1;';");
+
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1L, 2L));
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ execute("UPDATE %s SET val = val + 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 4L, 5L));
+ execute("UPDATE %s SET val = val - 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ }
+
+ @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 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 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 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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<set<int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "set<int>",
+ "CREATE FUNCTION %s (values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, 0),
+ row(1, 6),
+ row(2, 15),
+ row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "set<int>",
+ "CREATE FUNCTION %s (values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS set<int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<list<int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "list<int>",
+ "CREATE FUNCTION %s (values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, 0),
+ row(1, 6),
+ row(2, 15),
+ row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "list<int>",
+ "CREATE FUNCTION %s (values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS list<int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
+ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
+ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<map<int, int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "map<int, int>",
+ "CREATE FUNCTION %s (values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, 0),
+ row(1, 6),
+ row(2, 15),
+ row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "map<int, int>",
+ "CREATE FUNCTION %s (values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS map<int, int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<tuple<int, int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "tuple<int, int>",
+ "CREATE FUNCTION %s (values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, "(null, null)"),
+ row(1, "(1, 2)"),
+ row(2, "(4, 5)"),
+ row(3, "(7, 8)"));
+
+ functionName = createFunction(KEYSPACE,
+ "tuple<int, int>",
+ "CREATE FUNCTION %s (values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS tuple<int, int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
+ }
+
+ @Test
+ public void testFunctionWithFrozenUDType() 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, 0);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<" + myType + "> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ myType,
+ "CREATE FUNCTION %s (values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, "{f:0}"),
+ row(1, "{f:1}"),
+ row(2, "{f:4}"),
+ row(3, "{f:7}"));
+
+ functionName = createFunction(KEYSPACE,
+ myType,
+ "CREATE FUNCTION %s (values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS " + myType + " " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
+ }
+
+ @Test
+ public void testEmptyString() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, sval text, aval ascii, bval blob, empty_int int)");
+ execute("INSERT INTO %s (key, sval, aval, bval, empty_int) VALUES (?, ?, ?, ?, blobAsInt(0x))", 1, "", "", ByteBuffer.allocate(0));
+
+ String fNameSRC = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameSCC = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return \"\";'");
+
+ String fNameSRN = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameSCN = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return \"\";'");
+
+ String fNameBRC = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameBCC = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return ByteBuffer.allocate(0);'");
+
+ String fNameBRN = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameBCN = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return ByteBuffer.allocate(0);'");
+
+ String fNameIRC = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameICC = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ String fNameIRN = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameICN = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ assertRows(execute("SELECT " + fNameSRC + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRN + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCC + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCN + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRC + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRN + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCC + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCN + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameBRC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBRN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBCC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBCN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameIRC + "(empty_int) FROM %s"), row(new Object[]{null}));
+ assertRows(execute("SELECT " + fNameIRN + "(empty_int) FROM %s"), row(new Object[]{null}));
+ assertRows(execute("SELECT " + fNameICC + "(empty_int) FROM %s"), row(0));
+ assertRows(execute("SELECT " + fNameICN + "(empty_int) FROM %s"), row(new Object[]{null}));
+ }
+
+ @Test
+ public void testAllNativeTypes() throws Throwable
+ {
+ StringBuilder sig = new StringBuilder();
+ StringBuilder args = new StringBuilder();
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
+ if (sig.length() > 0)
+ sig.append(',');
+ sig.append(type.toString());
+
+ if (args.length() > 0)
+ args.append(',');
+ args.append("arg").append(type.toString()).append(' ').append(type.toString());
+ }
+ createFunction(KEYSPACE, sig.toString(),
+ "CREATE OR REPLACE FUNCTION %s(" + args + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
+ createFunction(KEYSPACE_PER_TEST, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type.toString() + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0b97c5d1/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
new file mode 100644
index 0000000..d3050a5
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
@@ -0,0 +1,504 @@
+/*
+ * 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.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.TupleType;
+import com.datastax.driver.core.TupleValue;
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.cql3.UntypedResultSet;
+import org.apache.cassandra.cql3.functions.FunctionName;
+import org.apache.cassandra.dht.ByteOrderedPartitioner;
+import org.apache.cassandra.exceptions.FunctionExecutionException;
+import org.apache.cassandra.transport.Server;
+import org.apache.cassandra.utils.UUIDGen;
+
+public class UFScriptTest extends CQLTester
+{
+ @BeforeClass
+ public static void setUp()
+ {
+ DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance);
+ }
+
+ @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"),
+ row(1d));
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fTup3 + "(tup) FROM %s WHERE key = 1"),
+ row(list));
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fTup4 + "(tup) FROM %s WHERE key = 1"),
+ row(set));
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fTup5 + "(tup) FROM %s WHERE key = 1"),
+ row(map));
+ }
+ }
+
+ @Test
+ public void testJavascriptUserType() throws Throwable
+ {
+ String type = createType("CREATE TYPE %s (txt text, i int)");
+
+ createTable("CREATE TABLE %s (key int primary key, udt frozen<" + type + ">)");
+
+ String fUdt1 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + " " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt;$$;");
+ String fUdt2 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getString(\"txt\");$$;");
+ String fUdt3 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getInt(\"i\");$$;");
+
+ execute("INSERT INTO %s (key, udt) VALUES (1, {txt: 'one', i:1})");
+
+ UntypedResultSet rows = execute("SELECT " + fUdt1 + "(udt) FROM %s WHERE key = 1");
+ Assert.assertEquals(1, rows.size());
+ assertRows(execute("SELECT " + fUdt2 + "(udt) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fUdt3 + "(udt) FROM %s WHERE key = 1"),
+ row(1));
+ }
+
+ @Test
+ public void testJavascriptUTCollections() throws Throwable
+ {
+ String type = 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 fName = createFunction(KEYSPACE, "list<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( lst list<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " lst.get(1).getString(\"txt\");$$;");
+ createFunctionOverload(fName, "set<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( st set<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " st.iterator().next().getString(\"txt\");$$;");
+ createFunctionOverload(fName, "map<int, frozen<" + type + ">>",
+ "CREATE FUNCTION %s( mp map<int, frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " mp.get(java.lang.Integer.valueOf(3)).getString(\"txt\");$$;");
+
+ execute("INSERT INTO %s (key, lst, st, mp) values (1, " +
+ // list<frozen<UDT>>
+ "[ {txt: 'one', i:1}, {txt: 'three', i:1}, {txt: 'one', i:1} ] , " +
+ // set<frozen<UDT>>
+ "{ {txt: 'one', i:1}, {txt: 'three', i:3}, {txt: 'two', i:2} }, " +
+ // map<int, frozen<UDT>>
+ "{ 1: {txt: 'one', i:1}, 2: {txt: 'one', i:3}, 3: {txt: 'two', i:2} })");
+
+ assertRows(execute("SELECT " + fName + "(lst) FROM %s WHERE key = 1"),
+ row("three"));
+ assertRows(execute("SELECT " + fName + "(st) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fName + "(mp) FROM %s WHERE key = 1"),
+ row("two"));
+
+ String cqlSelect = "SELECT " + fName + "(lst), " + fName + "(st), " + fName + "(mp) FROM %s WHERE key = 1";
+ assertRows(execute(cqlSelect),
+ row("three", "one", "two"));
+
+ // same test - but via native protocol
+ for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
+ assertRowsNet(version,
+ executeNet(version, cqlSelect),
+ row("three", "one", "two"));
+ }
+
+ @Test
+ public void testJavascriptFunction() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String functionBody = '\n' +
+ " Math.sin(val);\n";
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\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("javascript", 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 testJavascriptBadReturnType() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS '\"string\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ClassCastException
+ assertInvalidMessage("Invalid value for CQL type double", "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
+ public void testJavascriptThrow() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS 'throw \"fool\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ScriptException
+ assertInvalidThrowMessage("fool", FunctionExecutionException.class,
+ "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
+ public void testJavascriptCompileFailure() throws Throwable
+ {
+ assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS 'foo bar';");
+ }
+
+ @Test
+ public void testScriptInvalidLanguage() throws Throwable
+ {
+ assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE artificial_intelligence\n" +
+ "AS 'question for 42?';");
+ }
+
+ @Test
+ public void testScriptReturnTypeCasting() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+
+ Object[][] variations = {
+ new Object[] { "true", "boolean", true },
+ new Object[] { "false", "boolean", false },
+ new Object[] { "100", "tinyint", (byte)100 },
+ new Object[] { "100.", "tinyint", (byte)100 },
+ new Object[] { "100", "smallint", (short)100 },
+ new Object[] { "100.", "smallint", (short)100 },
+ new Object[] { "100", "int", 100 },
+ new Object[] { "100.", "int", 100 },
+ new Object[] { "100", "double", 100d },
+ new Object[] { "100.", "double", 100d },
+ new Object[] { "100", "bigint", 100L },
+ new Object[] { "100.", "bigint", 100L },
+ new Object[] { "100", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "100.", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "parseInt(\"100\");", "decimal", BigDecimal.valueOf(100d) },
+ new Object[] { "100.", "decimal", BigDecimal.valueOf(100d) },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object functionBody = variation[0];
+ Object returnType = variation[1];
+ Object expectedResult = variation[2];
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " +returnType + ' ' +
+ "LANGUAGE javascript " +
+ "AS '" + functionBody + ";';");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1d, expectedResult));
+ }
+ }
+
+ @Test
+ public void testScriptParamReturnTypes() throws Throwable
+ {
+ UUID ruuid = UUID.randomUUID();
+ UUID tuuid = UUIDGen.getTimeUUID();
+
+ createTable("CREATE TABLE %s (key int primary key, " +
+ "tival tinyint, sival smallint, ival int, lval bigint, fval float, dval double, vval varint, ddval decimal, " +
+ "timval time, dtval date, tsval timestamp, uval uuid, tuval timeuuid)");
+ execute("INSERT INTO %s (key, tival, sival, ival, lval, fval, dval, vval, ddval, timval, dtval, tsval, uval, tuval) VALUES " +
+ "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 1,
+ (byte)1, (short)1, 1, 1L, 1f, 1d, BigInteger.valueOf(1L), BigDecimal.valueOf(1d), 1L, Integer.MAX_VALUE, new Date(1), ruuid, tuuid);
+
+ Object[][] variations = {
+ new Object[] { "tinyint", "tival", (byte)1, (byte)2 },
+ new Object[] { "smallint", "sival", (short)1, (short)2 },
+ new Object[] { "int", "ival", 1, 2 },
+ new Object[] { "bigint", "lval", 1L, 2L },
+ new Object[] { "float", "fval", 1f, 2f },
+ new Object[] { "double", "dval", 1d, 2d },
+ new Object[] { "varint", "vval", BigInteger.valueOf(1L), BigInteger.valueOf(2L) },
+ new Object[] { "decimal", "ddval", BigDecimal.valueOf(1d), BigDecimal.valueOf(2d) },
+ new Object[] { "time", "timval", 1L, 2L },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val+1;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+
+ variations = new Object[][] {
+ new Object[] { "timestamp","tsval", new Date(1), new Date(1) },
+ new Object[] { "uuid", "uval", ruuid, ruuid },
+ new Object[] { "timeuuid", "tuval", tuuid, tuuid },
+ new Object[] { "date", "dtval", Integer.MAX_VALUE, Integer.MAX_VALUE },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+ }
+}
[24/25] cassandra git commit: Merge branch 'cassandra-3.0' into
cassandra-3.X
Posted by sn...@apache.org.
Merge branch 'cassandra-3.0' into cassandra-3.X
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/d7b6b7a3
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/d7b6b7a3
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/d7b6b7a3
Branch: refs/heads/trunk
Commit: d7b6b7a34d8a9401b8f615c91230a1fc882e32e1
Parents: 57c2003 3aefe35
Author: Robert Stupp <sn...@snazy.de>
Authored: Wed Dec 7 13:23:32 2016 +0100
Committer: Robert Stupp <sn...@snazy.de>
Committed: Wed Dec 7 13:23:32 2016 +0100
----------------------------------------------------------------------
.../cql3/validation/entities/UFJavaTest.java | 797 ++++++++
.../validation/entities/UFPureScriptTest.java | 407 ----
.../cql3/validation/entities/UFScriptTest.java | 429 +++++
.../validation/entities/UFSecurityTest.java | 258 +++
.../cql3/validation/entities/UFTest.java | 1739 +-----------------
.../cql3/validation/entities/UFTypesTest.java | 550 ++++++
6 files changed, 2035 insertions(+), 2145 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/d7b6b7a3/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
index 0000000,15c8e18..4d46b8b
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
@@@ -1,0 -1,797 +1,797 @@@
+ /*
+ * 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.util.Arrays;
+ import java.util.List;
+ import java.util.Map;
+ import java.util.Set;
+ import java.util.TreeMap;
+ import java.util.TreeSet;
+
+ import org.junit.Assert;
+ 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 org.apache.cassandra.config.Schema;
+ import org.apache.cassandra.cql3.CQL3Type;
+ import org.apache.cassandra.cql3.CQLTester;
+ import org.apache.cassandra.cql3.UntypedResultSet;
+ import org.apache.cassandra.cql3.functions.FunctionName;
+ import org.apache.cassandra.exceptions.FunctionExecutionException;
+ import org.apache.cassandra.exceptions.InvalidRequestException;
-import org.apache.cassandra.transport.Server;
++import org.apache.cassandra.transport.ProtocolVersion;
+
+ public class UFJavaTest extends CQLTester
+ {
+ @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 testJavaFunctionCounter() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val counter)");
+
+ String fName = createFunction(KEYSPACE, "counter",
+ "CREATE OR REPLACE FUNCTION %s(val counter) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS bigint " +
+ "LANGUAGE JAVA " +
+ "AS 'return val + 1;';");
+
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1L, 2L));
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ execute("UPDATE %s SET val = val + 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 4L, 5L));
+ execute("UPDATE %s SET val = val - 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ }
+
+ @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 : PROTOCOL_VERSIONS)
++ for (ProtocolVersion version : PROTOCOL_VERSIONS)
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fList + "(lst), " + fSet + "(st), " + fMap + "(mp) FROM %s WHERE key = 1"),
+ row(list, set, map));
+ }
+
+ @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));
+
+ // same test - but via native protocol
+ // we use protocol V3 here to encode the expected version because the server
+ // always serializes Collections using V3 - see CollectionSerializer's
+ // serialize and deserialize methods.
- TupleType tType = tupleTypeOf(Server.VERSION_3,
++ TupleType tType = tupleTypeOf(ProtocolVersion.V3,
+ 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 : PROTOCOL_VERSIONS)
++ for (ProtocolVersion version : PROTOCOL_VERSIONS)
+ {
+ 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 : PROTOCOL_VERSIONS)
++ for (ProtocolVersion version : PROTOCOL_VERSIONS)
+ {
+ 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 : PROTOCOL_VERSIONS)
++ for (ProtocolVersion version : PROTOCOL_VERSIONS)
+ {
+ 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 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, Schema.instance.getFunctions(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, Schema.instance.getFunctions(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, Schema.instance.getFunctions(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, Schema.instance.getFunctions(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 : PROTOCOL_VERSIONS)
++ for (ProtocolVersion version : PROTOCOL_VERSIONS)
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fName1 + "(lst), " + fName2 + "(st), " + fName3 + "(mp) FROM %s WHERE key = 1"),
+ row("three", "one", "two"));
+ }
+
+ @Test
+ public void testAllNativeTypes() throws Throwable
+ {
+ StringBuilder sig = new StringBuilder();
+ StringBuilder args = new StringBuilder();
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
+ if (type == CQL3Type.Native.EMPTY)
+ continue;
+
+ if (sig.length() > 0)
+ sig.append(',');
+ sig.append(type.toString());
+
+ if (args.length() > 0)
+ args.append(',');
+ args.append("arg").append(type.toString()).append(' ').append(type.toString());
+ }
+ createFunction(KEYSPACE, sig.toString(),
+ "CREATE OR REPLACE FUNCTION %s(" + args + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
+ if (type == CQL3Type.Native.EMPTY)
+ continue;
+
+ createFunction(KEYSPACE_PER_TEST, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type.toString() + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+ }
+ }
+ }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/d7b6b7a3/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
index 0000000,af3c894..02a13e7
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
@@@ -1,0 -1,428 +1,429 @@@
+ /*
+ * 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.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.Test;
+
+ import org.apache.cassandra.config.DatabaseDescriptor;
+ import org.apache.cassandra.cql3.CQLTester;
+ import org.apache.cassandra.cql3.UntypedResultSet;
+ import org.apache.cassandra.cql3.functions.FunctionName;
+ import org.apache.cassandra.exceptions.FunctionExecutionException;
++import org.apache.cassandra.transport.ProtocolVersion;
+ import org.apache.cassandra.utils.UUIDGen;
+
+ public class UFScriptTest extends CQLTester
+ {
+ // Just JavaScript UDFs to check how UDF - especially security/class-loading/sandboxing stuff -
+ // behaves, if no Java UDF has been executed before.
+
+ // Do not add any other test here - especially none using Java UDFs
+
+ @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 : PROTOCOL_VERSIONS)
++ for (ProtocolVersion version : PROTOCOL_VERSIONS)
+ 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 testJavascriptUserType() throws Throwable
+ {
+ String type = createType("CREATE TYPE %s (txt text, i int)");
+
+ createTable("CREATE TABLE %s (key int primary key, udt frozen<" + type + ">)");
+
+ String fUdt1 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt;$$;");
+ String fUdt2 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getString(\"txt\");$$;");
+ String fUdt3 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getInt(\"i\");$$;");
+
+ execute("INSERT INTO %s (key, udt) VALUES (1, {txt: 'one', i:1})");
+
+ UntypedResultSet rows = execute("SELECT " + fUdt1 + "(udt) FROM %s WHERE key = 1");
+ Assert.assertEquals(1, rows.size());
+ assertRows(execute("SELECT " + fUdt2 + "(udt) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fUdt3 + "(udt) FROM %s WHERE key = 1"),
+ row(1));
+ }
+
+ @Test
+ public void testJavascriptUTCollections() throws Throwable
+ {
+ String type = 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 fName = createFunction(KEYSPACE, "list<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( lst list<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " lst.get(1).getString(\"txt\");$$;");
+ createFunctionOverload(fName, "set<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( st set<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " st.iterator().next().getString(\"txt\");$$;");
+ createFunctionOverload(fName, "map<int, frozen<" + type + ">>",
+ "CREATE FUNCTION %s( mp map<int, frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " mp.get(java.lang.Integer.valueOf(3)).getString(\"txt\");$$;");
+
+ execute("INSERT INTO %s (key, lst, st, mp) values (1, " +
+ // list<frozen<UDT>>
+ "[ {txt: 'one', i:1}, {txt: 'three', i:1}, {txt: 'one', i:1} ] , " +
+ // set<frozen<UDT>>
+ "{ {txt: 'one', i:1}, {txt: 'three', i:3}, {txt: 'two', i:2} }, " +
+ // map<int, frozen<UDT>>
+ "{ 1: {txt: 'one', i:1}, 2: {txt: 'one', i:3}, 3: {txt: 'two', i:2} })");
+
+ assertRows(execute("SELECT " + fName + "(lst) FROM %s WHERE key = 1"),
+ row("three"));
+ assertRows(execute("SELECT " + fName + "(st) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fName + "(mp) FROM %s WHERE key = 1"),
+ row("two"));
+
+ String cqlSelect = "SELECT " + fName + "(lst), " + fName + "(st), " + fName + "(mp) FROM %s WHERE key = 1";
+ assertRows(execute(cqlSelect),
+ row("three", "one", "two"));
+
+ // same test - but via native protocol
- for (int version : PROTOCOL_VERSIONS)
++ for (ProtocolVersion version : PROTOCOL_VERSIONS)
+ assertRowsNet(version,
+ executeNet(version, cqlSelect),
+ row("three", "one", "two"));
+ }
+
+ @Test
+ public void testJavascriptFunction() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String functionBody = '\n' +
+ " Math.sin(val);\n";
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\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("javascript", 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 testJavascriptBadReturnType() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS '\"string\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ClassCastException
+ assertInvalidMessage("Invalid value for CQL type double", "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
+ public void testJavascriptThrow() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS 'throw \"fool\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ScriptException
+ assertInvalidThrowMessage("fool", FunctionExecutionException.class,
+ "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
+ public void testScriptReturnTypeCasting() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+
+ Object[][] variations = {
+ new Object[] { "true", "boolean", true },
+ new Object[] { "false", "boolean", false },
+ new Object[] { "100", "tinyint", (byte)100 },
+ new Object[] { "100.", "tinyint", (byte)100 },
+ new Object[] { "100", "smallint", (short)100 },
+ new Object[] { "100.", "smallint", (short)100 },
+ new Object[] { "100", "int", 100 },
+ new Object[] { "100.", "int", 100 },
+ new Object[] { "100", "double", 100d },
+ new Object[] { "100.", "double", 100d },
+ new Object[] { "100", "bigint", 100L },
+ new Object[] { "100.", "bigint", 100L },
+ new Object[] { "100", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "100.", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "parseInt(\"100\");", "decimal", BigDecimal.valueOf(100d) },
+ new Object[] { "100.", "decimal", BigDecimal.valueOf(100d) },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object functionBody = variation[0];
+ Object returnType = variation[1];
+ Object expectedResult = variation[2];
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " +returnType + ' ' +
+ "LANGUAGE javascript " +
+ "AS '" + functionBody + ";';");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1d, expectedResult));
+ }
+ }
+
+ @Test
+ public void testScriptParamReturnTypes() throws Throwable
+ {
+ UUID ruuid = UUID.randomUUID();
+ UUID tuuid = UUIDGen.getTimeUUID();
+
+ createTable("CREATE TABLE %s (key int primary key, " +
+ "tival tinyint, sival smallint, ival int, lval bigint, fval float, dval double, vval varint, ddval decimal, " +
+ "timval time, dtval date, tsval timestamp, uval uuid, tuval timeuuid)");
+ execute("INSERT INTO %s (key, tival, sival, ival, lval, fval, dval, vval, ddval, timval, dtval, tsval, uval, tuval) VALUES " +
+ "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 1,
+ (byte)1, (short)1, 1, 1L, 1f, 1d, BigInteger.valueOf(1L), BigDecimal.valueOf(1d), 1L, Integer.MAX_VALUE, new Date(1), ruuid, tuuid);
+
+ Object[][] variations = {
+ new Object[] { "tinyint", "tival", (byte)1, (byte)2 },
+ new Object[] { "smallint", "sival", (short)1, (short)2 },
+ new Object[] { "int", "ival", 1, 2 },
+ new Object[] { "bigint", "lval", 1L, 2L },
+ new Object[] { "float", "fval", 1f, 2f },
+ new Object[] { "double", "dval", 1d, 2d },
+ new Object[] { "varint", "vval", BigInteger.valueOf(1L), BigInteger.valueOf(2L) },
+ new Object[] { "decimal", "ddval", BigDecimal.valueOf(1d), BigDecimal.valueOf(2d) },
+ new Object[] { "time", "timval", 1L, 2L },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val+1;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+
+ variations = new Object[][] {
+ new Object[] { "timestamp","tsval", new Date(1), new Date(1) },
+ new Object[] { "uuid", "uval", ruuid, ruuid },
+ new Object[] { "timeuuid", "tuval", tuuid, tuuid },
+ new Object[] { "date", "dtval", Integer.MAX_VALUE, Integer.MAX_VALUE },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+ }
+
+ @Test
+ public void testJavascriptDisabled() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ DatabaseDescriptor.enableScriptedUserDefinedFunctions(false);
+ try
+ {
+ assertInvalid("double",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".assertNotEnabled(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS 'Math.sin(val);';");
+ }
+ finally
+ {
+ DatabaseDescriptor.enableScriptedUserDefinedFunctions(true);
+ }
+ }
+
+ @Test
+ public void testJavascriptCompileFailure() throws Throwable
+ {
+ assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS 'foo bar';");
+ }
+
+ @Test
+ public void testScriptInvalidLanguage() throws Throwable
+ {
+ assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE artificial_intelligence\n" +
+ "AS 'question for 42?';");
+ }
+ }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/d7b6b7a3/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
index 1eccc3f,8a743ea..c54982e
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
@@@ -18,46 -18,28 +18,31 @@@
package org.apache.cassandra.cql3.validation.entities;
import java.nio.ByteBuffer;
- import java.security.AccessControlException;
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 com.google.common.reflect.TypeToken;
import org.junit.Assert;
import org.junit.Test;
+import com.datastax.driver.core.*;
- import com.datastax.driver.core.DataType;
import com.datastax.driver.core.exceptions.InvalidQueryException;
- import org.apache.cassandra.config.Config;
- import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.config.Schema;
- 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.JavaBasedUDFunction;
import org.apache.cassandra.cql3.functions.UDFunction;
- import org.apache.cassandra.cql3.functions.UDHelper;
import org.apache.cassandra.db.marshal.CollectionType;
- import org.apache.cassandra.exceptions.FunctionExecutionException;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.schema.KeyspaceMetadata;
import org.apache.cassandra.service.ClientState;
- import org.apache.cassandra.service.ClientWarn;
-import org.apache.cassandra.transport.Event;
-import org.apache.cassandra.transport.Server;
+import org.apache.cassandra.transport.*;
+import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.transport.messages.ResultMessage;
import org.apache.cassandra.utils.ByteBufferUtil;
- import org.apache.cassandra.utils.UUIDGen;
public class UFTest extends CQLTester
{
[21/25] cassandra git commit: Merge branch 'cassandra-3.0' into
cassandra-3.X
Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/d7b6b7a3/test/unit/org/apache/cassandra/cql3/validation/entities/UFTypesTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFTypesTest.java
index 0000000,de98748..3f1bcb1
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTypesTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTypesTest.java
@@@ -1,0 -1,549 +1,550 @@@
+ /*
+ * 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.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.Test;
+
+ import com.datastax.driver.core.Row;
+ import org.apache.cassandra.cql3.CQLTester;
+ import org.apache.cassandra.cql3.UntypedResultSet;
++import org.apache.cassandra.transport.ProtocolVersion;
+ import org.apache.cassandra.utils.UUIDGen;
+
+ public class UFTypesTest extends CQLTester
+ {
+
+ @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 : PROTOCOL_VERSIONS)
++ for (ProtocolVersion version : PROTOCOL_VERSIONS)
+ {
+ 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"));
+ }
+ }
+
+ private static class TypesTestDef
+ {
+ final String udfType;
+ final String tableType;
+ final String columnName;
+ final Object referenceValue;
+
+ String fCheckArgAndReturn;
+
+ String fCalledOnNull;
+ String fReturnsNullOnNull;
+
+ TypesTestDef(String udfType, String tableType, String columnName, Object referenceValue)
+ {
+ this.udfType = udfType;
+ this.tableType = tableType;
+ this.columnName = columnName;
+ this.referenceValue = referenceValue;
+ }
+ }
+
+ @Test
+ public void testTypesWithAndWithoutNulls() throws Throwable
+ {
+ // test various combinations of types against UDFs with CALLED ON NULL or RETURNS NULL ON NULL
+
+ String type = createType("CREATE TYPE %s (txt text, i int)");
+
+ TypesTestDef[] typeDefs =
+ {
+ // udf type, table type, column, reference value
+ new TypesTestDef("timestamp", "timestamp", "ts", new Date()),
+ new TypesTestDef("date", "date", "dt", 12345),
+ new TypesTestDef("time", "time", "tim", 12345L),
+ new TypesTestDef("uuid", "uuid", "uu", UUID.randomUUID()),
+ new TypesTestDef("timeuuid", "timeuuid", "tu", UUIDGen.getTimeUUID()),
+ new TypesTestDef("tinyint", "tinyint", "ti", (byte) 42),
+ new TypesTestDef("smallint", "smallint", "si", (short) 43),
+ new TypesTestDef("int", "int", "i", 44),
+ new TypesTestDef("bigint", "bigint", "b", 45L),
+ new TypesTestDef("float", "float", "f", 46f),
+ new TypesTestDef("double", "double", "d", 47d),
+ new TypesTestDef("boolean", "boolean", "x", true),
+ new TypesTestDef("ascii", "ascii", "a", "tqbfjutld"),
+ new TypesTestDef("text", "text", "t", "k\u00f6lsche jung"),
+ //new TypesTestDef(type, "frozen<" + type + '>', "u", null),
+ new TypesTestDef("tuple<int, text>", "frozen<tuple<int, text>>", "tup", tuple(1, "foo"))
+ };
+
+ String createTableDDL = "CREATE TABLE %s (key int PRIMARY KEY";
+ String insertDML = "INSERT INTO %s (key";
+ List<Object> values = new ArrayList<>();
+ for (TypesTestDef typeDef : typeDefs)
+ {
+ createTableDDL += ", " + typeDef.columnName + ' ' + typeDef.tableType;
+ insertDML += ", " + typeDef.columnName;
+ String typeName = typeDef.udfType;
+ typeDef.fCheckArgAndReturn = createFunction(KEYSPACE,
+ typeName,
+ "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS " + typeName + ' ' +
+ "LANGUAGE java\n" +
+ "AS 'return val;';");
+ typeDef.fCalledOnNull = createFunction(KEYSPACE,
+ typeName,
+ "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return \"called\";';");
+ typeDef.fReturnsNullOnNull = createFunction(KEYSPACE,
+ typeName,
+ "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return \"called\";';");
+ values.add(typeDef.referenceValue);
+ }
+
+ createTableDDL += ')';
+ createTable(createTableDDL);
+
+ insertDML += ") VALUES (1";
+ for (TypesTestDef ignored : typeDefs)
+ insertDML += ", ?";
+ insertDML += ')';
+
+ execute(insertDML, values.toArray());
+
+ // second row with null values
+ for (int i = 0; i < values.size(); i++)
+ values.set(i, null);
+ execute(insertDML.replace('1', '2'), values.toArray());
+
+ // check argument input + return
+ for (TypesTestDef typeDef : typeDefs)
+ {
+ assertRows(execute("SELECT " + typeDef.fCheckArgAndReturn + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
+ row(new Object[]{ typeDef.referenceValue }));
+ }
+
+ // check for CALLED ON NULL INPUT with non-null arguments
+ for (TypesTestDef typeDef : typeDefs)
+ {
+ assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
+ row(new Object[]{ "called" }));
+ }
+
+ // check for CALLED ON NULL INPUT with null arguments
+ for (TypesTestDef typeDef : typeDefs)
+ {
+ assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
+ row(new Object[]{ "called" }));
+ }
+
+ // check for RETURNS NULL ON NULL INPUT with non-null arguments
+ for (TypesTestDef typeDef : typeDefs)
+ {
+ assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
+ row(new Object[]{ "called" }));
+ }
+
+ // check for RETURNS NULL ON NULL INPUT with null arguments
+ for (TypesTestDef typeDef : typeDefs)
+ {
+ assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
+ row(new Object[]{ null }));
+ }
+
+ }
+
+ @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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<set<int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "set<int>",
+ "CREATE FUNCTION %s (values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "set<int>",
+ "CREATE FUNCTION %s (values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS set<int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<list<int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "list<int>",
+ "CREATE FUNCTION %s (values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "list<int>",
+ "CREATE FUNCTION %s (values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS list<int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
+ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
+ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<map<int, int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "map<int, int>",
+ "CREATE FUNCTION %s (values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "map<int, int>",
+ "CREATE FUNCTION %s (values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS map<int, int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<tuple<int, int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "tuple<int, int>",
+ "CREATE FUNCTION %s (values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, "(NULL,NULL)"));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, "(1,2)"));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, "(4,5)"));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, "(7,8)"));
+
+ functionName = createFunction(KEYSPACE,
+ "tuple<int, int>",
+ "CREATE FUNCTION %s (values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS tuple<int, int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
+ }
+
+ @Test
+ public void testFunctionWithFrozenUDType() 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, 0);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<" + myType + "> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ myType,
+ "CREATE FUNCTION %s (values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, "{f:0}"));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, "{f:1}"));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, "{f:4}"));
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, "{f:7}"));
+
+ functionName = createFunction(KEYSPACE,
+ myType,
+ "CREATE FUNCTION %s (values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS " + myType + " " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
+ }
+ }
[22/25] cassandra git commit: Merge branch 'cassandra-3.0' into
cassandra-3.X
Posted by sn...@apache.org.
Merge branch 'cassandra-3.0' into cassandra-3.X
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/d7b6b7a3
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/d7b6b7a3
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/d7b6b7a3
Branch: refs/heads/cassandra-3.X
Commit: d7b6b7a34d8a9401b8f615c91230a1fc882e32e1
Parents: 57c2003 3aefe35
Author: Robert Stupp <sn...@snazy.de>
Authored: Wed Dec 7 13:23:32 2016 +0100
Committer: Robert Stupp <sn...@snazy.de>
Committed: Wed Dec 7 13:23:32 2016 +0100
----------------------------------------------------------------------
.../cql3/validation/entities/UFJavaTest.java | 797 ++++++++
.../validation/entities/UFPureScriptTest.java | 407 ----
.../cql3/validation/entities/UFScriptTest.java | 429 +++++
.../validation/entities/UFSecurityTest.java | 258 +++
.../cql3/validation/entities/UFTest.java | 1739 +-----------------
.../cql3/validation/entities/UFTypesTest.java | 550 ++++++
6 files changed, 2035 insertions(+), 2145 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/d7b6b7a3/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
index 0000000,15c8e18..4d46b8b
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
@@@ -1,0 -1,797 +1,797 @@@
+ /*
+ * 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.util.Arrays;
+ import java.util.List;
+ import java.util.Map;
+ import java.util.Set;
+ import java.util.TreeMap;
+ import java.util.TreeSet;
+
+ import org.junit.Assert;
+ 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 org.apache.cassandra.config.Schema;
+ import org.apache.cassandra.cql3.CQL3Type;
+ import org.apache.cassandra.cql3.CQLTester;
+ import org.apache.cassandra.cql3.UntypedResultSet;
+ import org.apache.cassandra.cql3.functions.FunctionName;
+ import org.apache.cassandra.exceptions.FunctionExecutionException;
+ import org.apache.cassandra.exceptions.InvalidRequestException;
-import org.apache.cassandra.transport.Server;
++import org.apache.cassandra.transport.ProtocolVersion;
+
+ public class UFJavaTest extends CQLTester
+ {
+ @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 testJavaFunctionCounter() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val counter)");
+
+ String fName = createFunction(KEYSPACE, "counter",
+ "CREATE OR REPLACE FUNCTION %s(val counter) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS bigint " +
+ "LANGUAGE JAVA " +
+ "AS 'return val + 1;';");
+
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1L, 2L));
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ execute("UPDATE %s SET val = val + 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 4L, 5L));
+ execute("UPDATE %s SET val = val - 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ }
+
+ @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 : PROTOCOL_VERSIONS)
++ for (ProtocolVersion version : PROTOCOL_VERSIONS)
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fList + "(lst), " + fSet + "(st), " + fMap + "(mp) FROM %s WHERE key = 1"),
+ row(list, set, map));
+ }
+
+ @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));
+
+ // same test - but via native protocol
+ // we use protocol V3 here to encode the expected version because the server
+ // always serializes Collections using V3 - see CollectionSerializer's
+ // serialize and deserialize methods.
- TupleType tType = tupleTypeOf(Server.VERSION_3,
++ TupleType tType = tupleTypeOf(ProtocolVersion.V3,
+ 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 : PROTOCOL_VERSIONS)
++ for (ProtocolVersion version : PROTOCOL_VERSIONS)
+ {
+ 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 : PROTOCOL_VERSIONS)
++ for (ProtocolVersion version : PROTOCOL_VERSIONS)
+ {
+ 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 : PROTOCOL_VERSIONS)
++ for (ProtocolVersion version : PROTOCOL_VERSIONS)
+ {
+ 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 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, Schema.instance.getFunctions(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, Schema.instance.getFunctions(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, Schema.instance.getFunctions(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, Schema.instance.getFunctions(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 : PROTOCOL_VERSIONS)
++ for (ProtocolVersion version : PROTOCOL_VERSIONS)
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fName1 + "(lst), " + fName2 + "(st), " + fName3 + "(mp) FROM %s WHERE key = 1"),
+ row("three", "one", "two"));
+ }
+
+ @Test
+ public void testAllNativeTypes() throws Throwable
+ {
+ StringBuilder sig = new StringBuilder();
+ StringBuilder args = new StringBuilder();
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
+ if (type == CQL3Type.Native.EMPTY)
+ continue;
+
+ if (sig.length() > 0)
+ sig.append(',');
+ sig.append(type.toString());
+
+ if (args.length() > 0)
+ args.append(',');
+ args.append("arg").append(type.toString()).append(' ').append(type.toString());
+ }
+ createFunction(KEYSPACE, sig.toString(),
+ "CREATE OR REPLACE FUNCTION %s(" + args + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
+ if (type == CQL3Type.Native.EMPTY)
+ continue;
+
+ createFunction(KEYSPACE_PER_TEST, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type.toString() + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+ }
+ }
+ }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/d7b6b7a3/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
index 0000000,af3c894..02a13e7
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
@@@ -1,0 -1,428 +1,429 @@@
+ /*
+ * 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.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.Test;
+
+ import org.apache.cassandra.config.DatabaseDescriptor;
+ import org.apache.cassandra.cql3.CQLTester;
+ import org.apache.cassandra.cql3.UntypedResultSet;
+ import org.apache.cassandra.cql3.functions.FunctionName;
+ import org.apache.cassandra.exceptions.FunctionExecutionException;
++import org.apache.cassandra.transport.ProtocolVersion;
+ import org.apache.cassandra.utils.UUIDGen;
+
+ public class UFScriptTest extends CQLTester
+ {
+ // Just JavaScript UDFs to check how UDF - especially security/class-loading/sandboxing stuff -
+ // behaves, if no Java UDF has been executed before.
+
+ // Do not add any other test here - especially none using Java UDFs
+
+ @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 : PROTOCOL_VERSIONS)
++ for (ProtocolVersion version : PROTOCOL_VERSIONS)
+ 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 testJavascriptUserType() throws Throwable
+ {
+ String type = createType("CREATE TYPE %s (txt text, i int)");
+
+ createTable("CREATE TABLE %s (key int primary key, udt frozen<" + type + ">)");
+
+ String fUdt1 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt;$$;");
+ String fUdt2 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getString(\"txt\");$$;");
+ String fUdt3 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getInt(\"i\");$$;");
+
+ execute("INSERT INTO %s (key, udt) VALUES (1, {txt: 'one', i:1})");
+
+ UntypedResultSet rows = execute("SELECT " + fUdt1 + "(udt) FROM %s WHERE key = 1");
+ Assert.assertEquals(1, rows.size());
+ assertRows(execute("SELECT " + fUdt2 + "(udt) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fUdt3 + "(udt) FROM %s WHERE key = 1"),
+ row(1));
+ }
+
+ @Test
+ public void testJavascriptUTCollections() throws Throwable
+ {
+ String type = 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 fName = createFunction(KEYSPACE, "list<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( lst list<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " lst.get(1).getString(\"txt\");$$;");
+ createFunctionOverload(fName, "set<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( st set<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " st.iterator().next().getString(\"txt\");$$;");
+ createFunctionOverload(fName, "map<int, frozen<" + type + ">>",
+ "CREATE FUNCTION %s( mp map<int, frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " mp.get(java.lang.Integer.valueOf(3)).getString(\"txt\");$$;");
+
+ execute("INSERT INTO %s (key, lst, st, mp) values (1, " +
+ // list<frozen<UDT>>
+ "[ {txt: 'one', i:1}, {txt: 'three', i:1}, {txt: 'one', i:1} ] , " +
+ // set<frozen<UDT>>
+ "{ {txt: 'one', i:1}, {txt: 'three', i:3}, {txt: 'two', i:2} }, " +
+ // map<int, frozen<UDT>>
+ "{ 1: {txt: 'one', i:1}, 2: {txt: 'one', i:3}, 3: {txt: 'two', i:2} })");
+
+ assertRows(execute("SELECT " + fName + "(lst) FROM %s WHERE key = 1"),
+ row("three"));
+ assertRows(execute("SELECT " + fName + "(st) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fName + "(mp) FROM %s WHERE key = 1"),
+ row("two"));
+
+ String cqlSelect = "SELECT " + fName + "(lst), " + fName + "(st), " + fName + "(mp) FROM %s WHERE key = 1";
+ assertRows(execute(cqlSelect),
+ row("three", "one", "two"));
+
+ // same test - but via native protocol
- for (int version : PROTOCOL_VERSIONS)
++ for (ProtocolVersion version : PROTOCOL_VERSIONS)
+ assertRowsNet(version,
+ executeNet(version, cqlSelect),
+ row("three", "one", "two"));
+ }
+
+ @Test
+ public void testJavascriptFunction() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String functionBody = '\n' +
+ " Math.sin(val);\n";
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\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("javascript", 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 testJavascriptBadReturnType() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS '\"string\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ClassCastException
+ assertInvalidMessage("Invalid value for CQL type double", "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
+ public void testJavascriptThrow() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS 'throw \"fool\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ScriptException
+ assertInvalidThrowMessage("fool", FunctionExecutionException.class,
+ "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
+ public void testScriptReturnTypeCasting() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+
+ Object[][] variations = {
+ new Object[] { "true", "boolean", true },
+ new Object[] { "false", "boolean", false },
+ new Object[] { "100", "tinyint", (byte)100 },
+ new Object[] { "100.", "tinyint", (byte)100 },
+ new Object[] { "100", "smallint", (short)100 },
+ new Object[] { "100.", "smallint", (short)100 },
+ new Object[] { "100", "int", 100 },
+ new Object[] { "100.", "int", 100 },
+ new Object[] { "100", "double", 100d },
+ new Object[] { "100.", "double", 100d },
+ new Object[] { "100", "bigint", 100L },
+ new Object[] { "100.", "bigint", 100L },
+ new Object[] { "100", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "100.", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "parseInt(\"100\");", "decimal", BigDecimal.valueOf(100d) },
+ new Object[] { "100.", "decimal", BigDecimal.valueOf(100d) },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object functionBody = variation[0];
+ Object returnType = variation[1];
+ Object expectedResult = variation[2];
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " +returnType + ' ' +
+ "LANGUAGE javascript " +
+ "AS '" + functionBody + ";';");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1d, expectedResult));
+ }
+ }
+
+ @Test
+ public void testScriptParamReturnTypes() throws Throwable
+ {
+ UUID ruuid = UUID.randomUUID();
+ UUID tuuid = UUIDGen.getTimeUUID();
+
+ createTable("CREATE TABLE %s (key int primary key, " +
+ "tival tinyint, sival smallint, ival int, lval bigint, fval float, dval double, vval varint, ddval decimal, " +
+ "timval time, dtval date, tsval timestamp, uval uuid, tuval timeuuid)");
+ execute("INSERT INTO %s (key, tival, sival, ival, lval, fval, dval, vval, ddval, timval, dtval, tsval, uval, tuval) VALUES " +
+ "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 1,
+ (byte)1, (short)1, 1, 1L, 1f, 1d, BigInteger.valueOf(1L), BigDecimal.valueOf(1d), 1L, Integer.MAX_VALUE, new Date(1), ruuid, tuuid);
+
+ Object[][] variations = {
+ new Object[] { "tinyint", "tival", (byte)1, (byte)2 },
+ new Object[] { "smallint", "sival", (short)1, (short)2 },
+ new Object[] { "int", "ival", 1, 2 },
+ new Object[] { "bigint", "lval", 1L, 2L },
+ new Object[] { "float", "fval", 1f, 2f },
+ new Object[] { "double", "dval", 1d, 2d },
+ new Object[] { "varint", "vval", BigInteger.valueOf(1L), BigInteger.valueOf(2L) },
+ new Object[] { "decimal", "ddval", BigDecimal.valueOf(1d), BigDecimal.valueOf(2d) },
+ new Object[] { "time", "timval", 1L, 2L },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val+1;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+
+ variations = new Object[][] {
+ new Object[] { "timestamp","tsval", new Date(1), new Date(1) },
+ new Object[] { "uuid", "uval", ruuid, ruuid },
+ new Object[] { "timeuuid", "tuval", tuuid, tuuid },
+ new Object[] { "date", "dtval", Integer.MAX_VALUE, Integer.MAX_VALUE },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+ }
+
+ @Test
+ public void testJavascriptDisabled() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ DatabaseDescriptor.enableScriptedUserDefinedFunctions(false);
+ try
+ {
+ assertInvalid("double",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".assertNotEnabled(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS 'Math.sin(val);';");
+ }
+ finally
+ {
+ DatabaseDescriptor.enableScriptedUserDefinedFunctions(true);
+ }
+ }
+
+ @Test
+ public void testJavascriptCompileFailure() throws Throwable
+ {
+ assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS 'foo bar';");
+ }
+
+ @Test
+ public void testScriptInvalidLanguage() throws Throwable
+ {
+ assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE artificial_intelligence\n" +
+ "AS 'question for 42?';");
+ }
+ }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/d7b6b7a3/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
index 1eccc3f,8a743ea..c54982e
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
@@@ -18,46 -18,28 +18,31 @@@
package org.apache.cassandra.cql3.validation.entities;
import java.nio.ByteBuffer;
- import java.security.AccessControlException;
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 com.google.common.reflect.TypeToken;
import org.junit.Assert;
import org.junit.Test;
+import com.datastax.driver.core.*;
- import com.datastax.driver.core.DataType;
import com.datastax.driver.core.exceptions.InvalidQueryException;
- import org.apache.cassandra.config.Config;
- import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.config.Schema;
- 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.JavaBasedUDFunction;
import org.apache.cassandra.cql3.functions.UDFunction;
- import org.apache.cassandra.cql3.functions.UDHelper;
import org.apache.cassandra.db.marshal.CollectionType;
- import org.apache.cassandra.exceptions.FunctionExecutionException;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.schema.KeyspaceMetadata;
import org.apache.cassandra.service.ClientState;
- import org.apache.cassandra.service.ClientWarn;
-import org.apache.cassandra.transport.Event;
-import org.apache.cassandra.transport.Server;
+import org.apache.cassandra.transport.*;
+import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.transport.messages.ResultMessage;
import org.apache.cassandra.utils.ByteBufferUtil;
- import org.apache.cassandra.utils.UUIDGen;
public class UFTest extends CQLTester
{
[19/25] 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/3aefe356/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
index 0000000,d3050a5..af3c894
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
@@@ -1,0 -1,504 +1,428 @@@
+ /*
+ * 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.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.TupleType;
-import com.datastax.driver.core.TupleValue;
+ import org.apache.cassandra.config.DatabaseDescriptor;
+ import org.apache.cassandra.cql3.CQLTester;
+ import org.apache.cassandra.cql3.UntypedResultSet;
+ import org.apache.cassandra.cql3.functions.FunctionName;
-import org.apache.cassandra.dht.ByteOrderedPartitioner;
+ import org.apache.cassandra.exceptions.FunctionExecutionException;
-import org.apache.cassandra.transport.Server;
+ import org.apache.cassandra.utils.UUIDGen;
+
+ public class UFScriptTest extends CQLTester
+ {
- @BeforeClass
- public static void setUp()
- {
- DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance);
- }
++ // Just JavaScript UDFs to check how UDF - especially security/class-loading/sandboxing stuff -
++ // behaves, if no Java UDF has been executed before.
++
++ // Do not add any other test here - especially none using Java UDFs
+
+ @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++)
++ for (int version : PROTOCOL_VERSIONS)
+ 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"),
- row(1d));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup3 + "(tup) FROM %s WHERE key = 1"),
- row(list));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup4 + "(tup) FROM %s WHERE key = 1"),
- row(set));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup5 + "(tup) FROM %s WHERE key = 1"),
- row(map));
- }
- }
-
- @Test
+ public void testJavascriptUserType() throws Throwable
+ {
+ String type = createType("CREATE TYPE %s (txt text, i int)");
+
+ createTable("CREATE TABLE %s (key int primary key, udt frozen<" + type + ">)");
+
+ String fUdt1 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
- "RETURNS " + type + " " +
++ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt;$$;");
+ String fUdt2 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getString(\"txt\");$$;");
+ String fUdt3 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getInt(\"i\");$$;");
+
+ execute("INSERT INTO %s (key, udt) VALUES (1, {txt: 'one', i:1})");
+
+ UntypedResultSet rows = execute("SELECT " + fUdt1 + "(udt) FROM %s WHERE key = 1");
+ Assert.assertEquals(1, rows.size());
+ assertRows(execute("SELECT " + fUdt2 + "(udt) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fUdt3 + "(udt) FROM %s WHERE key = 1"),
+ row(1));
+ }
+
+ @Test
+ public void testJavascriptUTCollections() throws Throwable
+ {
+ String type = 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 fName = createFunction(KEYSPACE, "list<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( lst list<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " lst.get(1).getString(\"txt\");$$;");
+ createFunctionOverload(fName, "set<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( st set<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " st.iterator().next().getString(\"txt\");$$;");
+ createFunctionOverload(fName, "map<int, frozen<" + type + ">>",
+ "CREATE FUNCTION %s( mp map<int, frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " mp.get(java.lang.Integer.valueOf(3)).getString(\"txt\");$$;");
+
+ execute("INSERT INTO %s (key, lst, st, mp) values (1, " +
+ // list<frozen<UDT>>
+ "[ {txt: 'one', i:1}, {txt: 'three', i:1}, {txt: 'one', i:1} ] , " +
+ // set<frozen<UDT>>
+ "{ {txt: 'one', i:1}, {txt: 'three', i:3}, {txt: 'two', i:2} }, " +
+ // map<int, frozen<UDT>>
+ "{ 1: {txt: 'one', i:1}, 2: {txt: 'one', i:3}, 3: {txt: 'two', i:2} })");
+
+ assertRows(execute("SELECT " + fName + "(lst) FROM %s WHERE key = 1"),
+ row("three"));
+ assertRows(execute("SELECT " + fName + "(st) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fName + "(mp) FROM %s WHERE key = 1"),
+ row("two"));
+
+ String cqlSelect = "SELECT " + fName + "(lst), " + fName + "(st), " + fName + "(mp) FROM %s WHERE key = 1";
+ assertRows(execute(cqlSelect),
+ row("three", "one", "two"));
+
+ // same test - but via native protocol
- for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
++ for (int version : PROTOCOL_VERSIONS)
+ assertRowsNet(version,
+ executeNet(version, cqlSelect),
+ row("three", "one", "two"));
+ }
+
+ @Test
+ public void testJavascriptFunction() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String functionBody = '\n' +
+ " Math.sin(val);\n";
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS '" + functionBody + "';");
+
+ FunctionName fNameName = parseFunctionName(fName);
+
- assertRows(execute("SELECT language, body FROM system.schema_functions WHERE keyspace_name=? AND function_name=?",
++ assertRows(execute("SELECT language, body FROM system_schema.functions WHERE keyspace_name=? AND function_name=?",
+ fNameName.keyspace, fNameName.name),
+ row("javascript", 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 testJavascriptBadReturnType() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS '\"string\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ClassCastException
+ assertInvalidMessage("Invalid value for CQL type double", "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
+ public void testJavascriptThrow() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS 'throw \"fool\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ScriptException
+ assertInvalidThrowMessage("fool", FunctionExecutionException.class,
+ "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
- public void testJavascriptCompileFailure() throws Throwable
- {
- assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS 'foo bar';");
- }
-
- @Test
- public void testScriptInvalidLanguage() throws Throwable
- {
- assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE artificial_intelligence\n" +
- "AS 'question for 42?';");
- }
-
- @Test
+ public void testScriptReturnTypeCasting() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+
+ Object[][] variations = {
+ new Object[] { "true", "boolean", true },
+ new Object[] { "false", "boolean", false },
+ new Object[] { "100", "tinyint", (byte)100 },
+ new Object[] { "100.", "tinyint", (byte)100 },
+ new Object[] { "100", "smallint", (short)100 },
+ new Object[] { "100.", "smallint", (short)100 },
+ new Object[] { "100", "int", 100 },
+ new Object[] { "100.", "int", 100 },
+ new Object[] { "100", "double", 100d },
+ new Object[] { "100.", "double", 100d },
+ new Object[] { "100", "bigint", 100L },
+ new Object[] { "100.", "bigint", 100L },
+ new Object[] { "100", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "100.", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "parseInt(\"100\");", "decimal", BigDecimal.valueOf(100d) },
+ new Object[] { "100.", "decimal", BigDecimal.valueOf(100d) },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object functionBody = variation[0];
+ Object returnType = variation[1];
+ Object expectedResult = variation[2];
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " +returnType + ' ' +
+ "LANGUAGE javascript " +
+ "AS '" + functionBody + ";';");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1d, expectedResult));
+ }
+ }
+
+ @Test
+ public void testScriptParamReturnTypes() throws Throwable
+ {
+ UUID ruuid = UUID.randomUUID();
+ UUID tuuid = UUIDGen.getTimeUUID();
+
+ createTable("CREATE TABLE %s (key int primary key, " +
+ "tival tinyint, sival smallint, ival int, lval bigint, fval float, dval double, vval varint, ddval decimal, " +
+ "timval time, dtval date, tsval timestamp, uval uuid, tuval timeuuid)");
+ execute("INSERT INTO %s (key, tival, sival, ival, lval, fval, dval, vval, ddval, timval, dtval, tsval, uval, tuval) VALUES " +
+ "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 1,
+ (byte)1, (short)1, 1, 1L, 1f, 1d, BigInteger.valueOf(1L), BigDecimal.valueOf(1d), 1L, Integer.MAX_VALUE, new Date(1), ruuid, tuuid);
+
+ Object[][] variations = {
+ new Object[] { "tinyint", "tival", (byte)1, (byte)2 },
+ new Object[] { "smallint", "sival", (short)1, (short)2 },
+ new Object[] { "int", "ival", 1, 2 },
+ new Object[] { "bigint", "lval", 1L, 2L },
+ new Object[] { "float", "fval", 1f, 2f },
+ new Object[] { "double", "dval", 1d, 2d },
+ new Object[] { "varint", "vval", BigInteger.valueOf(1L), BigInteger.valueOf(2L) },
+ new Object[] { "decimal", "ddval", BigDecimal.valueOf(1d), BigDecimal.valueOf(2d) },
+ new Object[] { "time", "timval", 1L, 2L },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val+1;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+
+ variations = new Object[][] {
+ new Object[] { "timestamp","tsval", new Date(1), new Date(1) },
+ new Object[] { "uuid", "uval", ruuid, ruuid },
+ new Object[] { "timeuuid", "tuval", tuuid, tuuid },
+ new Object[] { "date", "dtval", Integer.MAX_VALUE, Integer.MAX_VALUE },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+ }
++
++ @Test
++ public void testJavascriptDisabled() throws Throwable
++ {
++ createTable("CREATE TABLE %s (key int primary key, val double)");
++
++ DatabaseDescriptor.enableScriptedUserDefinedFunctions(false);
++ try
++ {
++ assertInvalid("double",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".assertNotEnabled(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE javascript\n" +
++ "AS 'Math.sin(val);';");
++ }
++ finally
++ {
++ DatabaseDescriptor.enableScriptedUserDefinedFunctions(true);
++ }
++ }
++
++ @Test
++ public void testJavascriptCompileFailure() throws Throwable
++ {
++ assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE javascript\n" +
++ "AS 'foo bar';");
++ }
++
++ @Test
++ public void testScriptInvalidLanguage() throws Throwable
++ {
++ assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE artificial_intelligence\n" +
++ "AS 'question for 42?';");
++ }
+ }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/3aefe356/test/unit/org/apache/cassandra/cql3/validation/entities/UFSecurityTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFSecurityTest.java
index 0000000,0000000..5c7ca2b
new file mode 100644
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFSecurityTest.java
@@@ -1,0 -1,0 +1,258 @@@
++/*
++ * 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.security.AccessControlException;
++import java.util.List;
++
++import org.junit.Assert;
++import org.junit.Test;
++
++import org.apache.cassandra.config.Config;
++import org.apache.cassandra.config.DatabaseDescriptor;
++import org.apache.cassandra.cql3.CQLTester;
++import org.apache.cassandra.cql3.functions.UDHelper;
++import org.apache.cassandra.exceptions.FunctionExecutionException;
++import org.apache.cassandra.service.ClientWarn;
++
++public class UFSecurityTest extends CQLTester
++{
++ @Test
++ public void testSecurityPermissions() throws Throwable
++ {
++ createTable("CREATE TABLE %s (key int primary key, dval double)");
++ execute("INSERT INTO %s (key, dval) VALUES (?, ?)", 1, 1d);
++
++ // Java UDFs
++
++ try
++ {
++ 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 'System.getProperty(\"foo.bar.baz\"); return 0d;';");
++ execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
++ Assert.fail();
++ }
++ catch (FunctionExecutionException e)
++ {
++ assertAccessControlException("System.getProperty(\"foo.bar.baz\"); return 0d;", e);
++ }
++
++ String[][] typesAndSources =
++ {
++ {"", "try { Class.forName(\"" + UDHelper.class.getName() + "\"); } catch (Exception e) { throw new RuntimeException(e); } return 0d;"},
++ {"sun.misc.Unsafe", "sun.misc.Unsafe.getUnsafe(); return 0d;"},
++ {"", "try { Class.forName(\"sun.misc.Unsafe\"); } catch (Exception e) { throw new RuntimeException(e); } return 0d;"},
++ {"java.nio.file.FileSystems", "try {" +
++ " java.nio.file.FileSystems.getDefault(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.nio.channels.FileChannel", "try {" +
++ " java.nio.channels.FileChannel.open(java.nio.file.FileSystems.getDefault().getPath(\"/etc/passwd\")).close(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.nio.channels.SocketChannel", "try {" +
++ " java.nio.channels.SocketChannel.open().close(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.io.FileInputStream", "try {" +
++ " new java.io.FileInputStream(\"./foobar\").close(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.lang.Runtime", "try {" +
++ " java.lang.Runtime.getRuntime(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"org.apache.cassandra.service.StorageService",
++ "try {" +
++ " org.apache.cassandra.service.StorageService v = org.apache.cassandra.service.StorageService.instance; v.isShutdown(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.net.ServerSocket", "try {" +
++ " new java.net.ServerSocket().bind(); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.io.FileOutputStream","try {" +
++ " new java.io.FileOutputStream(\".foo\"); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'},
++ {"java.lang.Runtime", "try {" +
++ " java.lang.Runtime.getRuntime().exec(\"/tmp/foo\"); return 0d;" +
++ "} catch (Exception t) {" +
++ " throw new RuntimeException(t);" +
++ '}'}
++ };
++
++ for (String[] typeAndSource : typesAndSources)
++ {
++ assertInvalidMessage(typeAndSource[0] + " cannot be resolved",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".invalid_class_access(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE JAVA\n" +
++ "AS '" + typeAndSource[1] + "';");
++ }
++
++ // JavaScript UDFs
++
++ try
++ {
++ String fName = createFunction(KEYSPACE_PER_TEST, "double",
++ "CREATE OR REPLACE FUNCTION %s(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE javascript\n" +
++ "AS 'org.apache.cassandra.service.StorageService.instance.isShutdown(); 0;';");
++ execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
++ Assert.fail("Javascript security check failed");
++ }
++ catch (FunctionExecutionException e)
++ {
++ assertAccessControlException("", e);
++ }
++
++ String[] javascript =
++ {
++ "java.lang.management.ManagmentFactory.getThreadMXBean(); 0;",
++ "new java.io.FileInputStream(\"/tmp/foo\"); 0;",
++ "new java.io.FileOutputStream(\"/tmp/foo\"); 0;",
++ "java.nio.file.FileSystems.getDefault().createFileExclusively(\"./foo_bar_baz\"); 0;",
++ "java.nio.channels.FileChannel.open(java.nio.file.FileSystems.getDefault().getPath(\"/etc/passwd\")); 0;",
++ "java.nio.channels.SocketChannel.open(); 0;",
++ "new java.net.ServerSocket().bind(null); 0;",
++ "var thread = new java.lang.Thread(); thread.start(); 0;",
++ "java.lang.System.getProperty(\"foo.bar.baz\"); 0;",
++ "java.lang.Class.forName(\"java.lang.System\"); 0;",
++ "java.lang.Runtime.getRuntime().exec(\"/tmp/foo\"); 0;",
++ "java.lang.Runtime.getRuntime().loadLibrary(\"foobar\"); 0;",
++ "java.lang.Runtime.getRuntime().loadLibrary(\"foobar\"); 0;",
++ // TODO these (ugly) calls are still possible - these can consume CPU (as one could do with an evil loop, too)
++// "java.lang.Runtime.getRuntime().traceMethodCalls(true); 0;",
++// "java.lang.Runtime.getRuntime().gc(); 0;",
++// "java.lang.Runtime.getRuntime(); 0;",
++ };
++
++ for (String script : javascript)
++ {
++ try
++ {
++ String fName = createFunction(KEYSPACE_PER_TEST, "double",
++ "CREATE OR REPLACE FUNCTION %s(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE javascript\n" +
++ "AS '" + script + "';");
++ execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
++ Assert.fail("Javascript security check failed: " + script);
++ }
++ catch (FunctionExecutionException e)
++ {
++ assertAccessControlException(script, e);
++ }
++ }
++ }
++
++ private static void assertAccessControlException(String script, FunctionExecutionException e)
++ {
++ for (Throwable t = e; t != null && t != t.getCause(); t = t.getCause())
++ if (t instanceof AccessControlException)
++ return;
++ Assert.fail("no AccessControlException for " + script + " (got " + e + ')');
++ }
++
++ @Test
++ public void testAmokUDF() throws Throwable
++ {
++ createTable("CREATE TABLE %s (key int primary key, dval double)");
++ execute("INSERT INTO %s (key, dval) VALUES (?, ?)", 1, 1d);
++
++ long udfWarnTimeout = DatabaseDescriptor.getUserDefinedFunctionWarnTimeout();
++ long udfFailTimeout = DatabaseDescriptor.getUserDefinedFunctionFailTimeout();
++ int maxTries = 5;
++ for (int i = 1; i <= maxTries; i++)
++ {
++ try
++ {
++ // short timeout
++ DatabaseDescriptor.setUserDefinedFunctionWarnTimeout(10);
++ DatabaseDescriptor.setUserDefinedFunctionFailTimeout(250);
++ // don't kill the unit test... - default policy is "die"
++ DatabaseDescriptor.setUserFunctionTimeoutPolicy(Config.UserFunctionTimeoutPolicy.ignore);
++
++ ClientWarn.instance.captureWarnings();
++ 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 'long t=System.currentTimeMillis()+110; while (t>System.currentTimeMillis()) { }; return 0d;'");
++ execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
++ List<String> warnings = ClientWarn.instance.getWarnings();
++ Assert.assertNotNull(warnings);
++ Assert.assertFalse(warnings.isEmpty());
++ ClientWarn.instance.resetWarnings();
++
++ // Java UDF
++
++ fName = createFunction(KEYSPACE_PER_TEST, "double",
++ "CREATE OR REPLACE FUNCTION %s(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE JAVA\n" +
++ "AS 'long t=System.currentTimeMillis()+500; while (t>System.currentTimeMillis()) { }; return 0d;';");
++ assertInvalidMessage("ran longer than 250ms", "SELECT " + fName + "(dval) FROM %s WHERE key=1");
++
++ // Javascript UDF
++
++ fName = createFunction(KEYSPACE_PER_TEST, "double",
++ "CREATE OR REPLACE FUNCTION %s(val double) " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS double " +
++ "LANGUAGE JAVASCRIPT\n" +
++ "AS 'var t=java.lang.System.currentTimeMillis()+500; while (t>java.lang.System.currentTimeMillis()) { }; 0;';");
++ assertInvalidMessage("ran longer than 250ms", "SELECT " + fName + "(dval) FROM %s WHERE key=1");
++
++ return;
++ }
++ catch (Error | RuntimeException e)
++ {
++ if (i == maxTries)
++ throw e;
++ }
++ finally
++ {
++ // reset to defaults
++ DatabaseDescriptor.setUserDefinedFunctionWarnTimeout(udfWarnTimeout);
++ DatabaseDescriptor.setUserDefinedFunctionFailTimeout(udfFailTimeout);
++ }
++ }
++ }
++
++}
[09/25] 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/3aefe356/test/unit/org/apache/cassandra/cql3/validation/entities/UFTypesTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFTypesTest.java
index 0000000,0000000..de98748
new file mode 100644
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTypesTest.java
@@@ -1,0 -1,0 +1,549 @@@
++/*
++ * 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.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.Test;
++
++import com.datastax.driver.core.Row;
++import org.apache.cassandra.cql3.CQLTester;
++import org.apache.cassandra.cql3.UntypedResultSet;
++import org.apache.cassandra.utils.UUIDGen;
++
++public class UFTypesTest extends CQLTester
++{
++
++ @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 : PROTOCOL_VERSIONS)
++ {
++ 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"));
++ }
++ }
++
++ private static class TypesTestDef
++ {
++ final String udfType;
++ final String tableType;
++ final String columnName;
++ final Object referenceValue;
++
++ String fCheckArgAndReturn;
++
++ String fCalledOnNull;
++ String fReturnsNullOnNull;
++
++ TypesTestDef(String udfType, String tableType, String columnName, Object referenceValue)
++ {
++ this.udfType = udfType;
++ this.tableType = tableType;
++ this.columnName = columnName;
++ this.referenceValue = referenceValue;
++ }
++ }
++
++ @Test
++ public void testTypesWithAndWithoutNulls() throws Throwable
++ {
++ // test various combinations of types against UDFs with CALLED ON NULL or RETURNS NULL ON NULL
++
++ String type = createType("CREATE TYPE %s (txt text, i int)");
++
++ TypesTestDef[] typeDefs =
++ {
++ // udf type, table type, column, reference value
++ new TypesTestDef("timestamp", "timestamp", "ts", new Date()),
++ new TypesTestDef("date", "date", "dt", 12345),
++ new TypesTestDef("time", "time", "tim", 12345L),
++ new TypesTestDef("uuid", "uuid", "uu", UUID.randomUUID()),
++ new TypesTestDef("timeuuid", "timeuuid", "tu", UUIDGen.getTimeUUID()),
++ new TypesTestDef("tinyint", "tinyint", "ti", (byte) 42),
++ new TypesTestDef("smallint", "smallint", "si", (short) 43),
++ new TypesTestDef("int", "int", "i", 44),
++ new TypesTestDef("bigint", "bigint", "b", 45L),
++ new TypesTestDef("float", "float", "f", 46f),
++ new TypesTestDef("double", "double", "d", 47d),
++ new TypesTestDef("boolean", "boolean", "x", true),
++ new TypesTestDef("ascii", "ascii", "a", "tqbfjutld"),
++ new TypesTestDef("text", "text", "t", "k\u00f6lsche jung"),
++ //new TypesTestDef(type, "frozen<" + type + '>', "u", null),
++ new TypesTestDef("tuple<int, text>", "frozen<tuple<int, text>>", "tup", tuple(1, "foo"))
++ };
++
++ String createTableDDL = "CREATE TABLE %s (key int PRIMARY KEY";
++ String insertDML = "INSERT INTO %s (key";
++ List<Object> values = new ArrayList<>();
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ createTableDDL += ", " + typeDef.columnName + ' ' + typeDef.tableType;
++ insertDML += ", " + typeDef.columnName;
++ String typeName = typeDef.udfType;
++ typeDef.fCheckArgAndReturn = createFunction(KEYSPACE,
++ typeName,
++ "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS " + typeName + ' ' +
++ "LANGUAGE java\n" +
++ "AS 'return val;';");
++ typeDef.fCalledOnNull = createFunction(KEYSPACE,
++ typeName,
++ "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return \"called\";';");
++ typeDef.fReturnsNullOnNull = createFunction(KEYSPACE,
++ typeName,
++ "CREATE OR REPLACE FUNCTION %s(val " + typeName + ") " +
++ "RETURNS NULL ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return \"called\";';");
++ values.add(typeDef.referenceValue);
++ }
++
++ createTableDDL += ')';
++ createTable(createTableDDL);
++
++ insertDML += ") VALUES (1";
++ for (TypesTestDef ignored : typeDefs)
++ insertDML += ", ?";
++ insertDML += ')';
++
++ execute(insertDML, values.toArray());
++
++ // second row with null values
++ for (int i = 0; i < values.size(); i++)
++ values.set(i, null);
++ execute(insertDML.replace('1', '2'), values.toArray());
++
++ // check argument input + return
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ assertRows(execute("SELECT " + typeDef.fCheckArgAndReturn + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
++ row(new Object[]{ typeDef.referenceValue }));
++ }
++
++ // check for CALLED ON NULL INPUT with non-null arguments
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
++ row(new Object[]{ "called" }));
++ }
++
++ // check for CALLED ON NULL INPUT with null arguments
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ assertRows(execute("SELECT " + typeDef.fCalledOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
++ row(new Object[]{ "called" }));
++ }
++
++ // check for RETURNS NULL ON NULL INPUT with non-null arguments
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 1"),
++ row(new Object[]{ "called" }));
++ }
++
++ // check for RETURNS NULL ON NULL INPUT with null arguments
++ for (TypesTestDef typeDef : typeDefs)
++ {
++ assertRows(execute("SELECT " + typeDef.fReturnsNullOnNull + '(' + typeDef.columnName + ") FROM %s WHERE key = 2"),
++ row(new Object[]{ null }));
++ }
++
++ }
++
++ @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));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
++
++ assertInvalidMessage("The function return type should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS frozen<set<int>> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ String functionName = createFunction(KEYSPACE,
++ "set<int>",
++ "CREATE FUNCTION %s (values set<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
++
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
++
++ functionName = createFunction(KEYSPACE,
++ "set<int>",
++ "CREATE FUNCTION %s (values set<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS set<int> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
++ row(1));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "DROP FUNCTION " + functionName + "(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));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
++
++ assertInvalidMessage("The function return type should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS frozen<list<int>> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ String functionName = createFunction(KEYSPACE,
++ "list<int>",
++ "CREATE FUNCTION %s (values list<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
++
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
++
++ functionName = createFunction(KEYSPACE,
++ "list<int>",
++ "CREATE FUNCTION %s (values list<int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS list<int> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
++ row(1));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
++ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
++ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
++
++ assertInvalidMessage("The function return type should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS frozen<map<int, int>> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ String functionName = createFunction(KEYSPACE,
++ "map<int, int>",
++ "CREATE FUNCTION %s (values map<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS int " +
++ "LANGUAGE java\n" +
++ "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
++
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, 0));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, 6));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, 15));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, 24));
++
++ functionName = createFunction(KEYSPACE,
++ "map<int, int>",
++ "CREATE FUNCTION %s (values map<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS map<int, int> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
++ row(1));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "DROP FUNCTION " + functionName + "(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));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return values.toString();';");
++
++ assertInvalidMessage("The function return type should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS frozen<tuple<int, int>> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ String functionName = createFunction(KEYSPACE,
++ "tuple<int, int>",
++ "CREATE FUNCTION %s (values tuple<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return values.toString();';");
++
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, "(NULL,NULL)"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, "(1,2)"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, "(4,5)"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, "(7,8)"));
++
++ functionName = createFunction(KEYSPACE,
++ "tuple<int, int>",
++ "CREATE FUNCTION %s (values tuple<int, int>) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS tuple<int, int> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
++ row(1));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
++ }
++
++ @Test
++ public void testFunctionWithFrozenUDType() 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, 0);
++ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
++ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
++ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return values.toString();';");
++
++ assertInvalidMessage("The function return type should not be frozen",
++ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS frozen<" + myType + "> " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ String functionName = createFunction(KEYSPACE,
++ myType,
++ "CREATE FUNCTION %s (values " + myType + ") " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS text " +
++ "LANGUAGE java\n" +
++ "AS 'return values.toString();';");
++
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 0"), row(0, "{f:0}"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 1"), row(1, "{f:1}"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 2"), row(2, "{f:4}"));
++ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s WHERE a = 3"), row(3, "{f:7}"));
++
++ functionName = createFunction(KEYSPACE,
++ myType,
++ "CREATE FUNCTION %s (values " + myType + ") " +
++ "CALLED ON NULL INPUT " +
++ "RETURNS " + myType + " " +
++ "LANGUAGE java\n" +
++ "AS 'return values;';");
++
++ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
++ row(1));
++
++ assertInvalidMessage("The function arguments should not be frozen",
++ "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
++ }
++}
[04/25] cassandra git commit: testall failure in
org.apache.cassandra.cql3.validation.entities.UFTest.testAllNativeTypes
Posted by sn...@apache.org.
testall failure in org.apache.cassandra.cql3.validation.entities.UFTest.testAllNativeTypes
patch by Robert Stupp; reviewed by Alex Petrov for CASSANDRA-12817
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/0b97c5d1
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/0b97c5d1
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/0b97c5d1
Branch: refs/heads/cassandra-3.0
Commit: 0b97c5d1f717be30a04c59c766465d9c62a4e9ee
Parents: 2e93398
Author: Robert Stupp <sn...@snazy.de>
Authored: Wed Dec 7 13:06:55 2016 +0100
Committer: Robert Stupp <sn...@snazy.de>
Committed: Wed Dec 7 13:06:55 2016 +0100
----------------------------------------------------------------------
.../cql3/validation/entities/UFJavaTest.java | 1177 +++++++++++++
.../cql3/validation/entities/UFScriptTest.java | 504 ++++++
.../cql3/validation/entities/UFTest.java | 1608 +-----------------
3 files changed, 1696 insertions(+), 1593 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0b97c5d1/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
new file mode 100644
index 0000000..caef808
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
@@ -0,0 +1,1177 @@
+/*
+ * 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.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+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 org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.cql3.CQL3Type;
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.cql3.UntypedResultSet;
+import org.apache.cassandra.cql3.functions.FunctionName;
+import org.apache.cassandra.cql3.functions.Functions;
+import org.apache.cassandra.dht.ByteOrderedPartitioner;
+import org.apache.cassandra.exceptions.FunctionExecutionException;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.transport.Server;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+public class UFJavaTest extends CQLTester
+{
+ @BeforeClass
+ public static void setUp()
+ {
+ DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance);
+ }
+
+
+ @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 testJavaFunctionCounter() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val counter)");
+
+ String fName = createFunction(KEYSPACE, "counter",
+ "CREATE OR REPLACE FUNCTION %s(val counter) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS bigint " +
+ "LANGUAGE JAVA " +
+ "AS 'return val + 1;';");
+
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1L, 2L));
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ execute("UPDATE %s SET val = val + 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 4L, 5L));
+ execute("UPDATE %s SET val = val - 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ }
+
+ @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 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 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 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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<set<int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "set<int>",
+ "CREATE FUNCTION %s (values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, 0),
+ row(1, 6),
+ row(2, 15),
+ row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "set<int>",
+ "CREATE FUNCTION %s (values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS set<int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<list<int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "list<int>",
+ "CREATE FUNCTION %s (values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, 0),
+ row(1, 6),
+ row(2, 15),
+ row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "list<int>",
+ "CREATE FUNCTION %s (values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS list<int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
+ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
+ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<map<int, int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "map<int, int>",
+ "CREATE FUNCTION %s (values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, 0),
+ row(1, 6),
+ row(2, 15),
+ row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "map<int, int>",
+ "CREATE FUNCTION %s (values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS map<int, int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<tuple<int, int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "tuple<int, int>",
+ "CREATE FUNCTION %s (values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, "(null, null)"),
+ row(1, "(1, 2)"),
+ row(2, "(4, 5)"),
+ row(3, "(7, 8)"));
+
+ functionName = createFunction(KEYSPACE,
+ "tuple<int, int>",
+ "CREATE FUNCTION %s (values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS tuple<int, int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
+ }
+
+ @Test
+ public void testFunctionWithFrozenUDType() 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, 0);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<" + myType + "> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ myType,
+ "CREATE FUNCTION %s (values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, "{f:0}"),
+ row(1, "{f:1}"),
+ row(2, "{f:4}"),
+ row(3, "{f:7}"));
+
+ functionName = createFunction(KEYSPACE,
+ myType,
+ "CREATE FUNCTION %s (values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS " + myType + " " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
+ }
+
+ @Test
+ public void testEmptyString() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, sval text, aval ascii, bval blob, empty_int int)");
+ execute("INSERT INTO %s (key, sval, aval, bval, empty_int) VALUES (?, ?, ?, ?, blobAsInt(0x))", 1, "", "", ByteBuffer.allocate(0));
+
+ String fNameSRC = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameSCC = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return \"\";'");
+
+ String fNameSRN = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameSCN = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return \"\";'");
+
+ String fNameBRC = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameBCC = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return ByteBuffer.allocate(0);'");
+
+ String fNameBRN = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameBCN = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return ByteBuffer.allocate(0);'");
+
+ String fNameIRC = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameICC = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ String fNameIRN = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameICN = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ assertRows(execute("SELECT " + fNameSRC + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRN + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCC + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCN + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRC + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRN + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCC + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCN + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameBRC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBRN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBCC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBCN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameIRC + "(empty_int) FROM %s"), row(new Object[]{null}));
+ assertRows(execute("SELECT " + fNameIRN + "(empty_int) FROM %s"), row(new Object[]{null}));
+ assertRows(execute("SELECT " + fNameICC + "(empty_int) FROM %s"), row(0));
+ assertRows(execute("SELECT " + fNameICN + "(empty_int) FROM %s"), row(new Object[]{null}));
+ }
+
+ @Test
+ public void testAllNativeTypes() throws Throwable
+ {
+ StringBuilder sig = new StringBuilder();
+ StringBuilder args = new StringBuilder();
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
+ if (sig.length() > 0)
+ sig.append(',');
+ sig.append(type.toString());
+
+ if (args.length() > 0)
+ args.append(',');
+ args.append("arg").append(type.toString()).append(' ').append(type.toString());
+ }
+ createFunction(KEYSPACE, sig.toString(),
+ "CREATE OR REPLACE FUNCTION %s(" + args + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
+ createFunction(KEYSPACE_PER_TEST, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type.toString() + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0b97c5d1/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
new file mode 100644
index 0000000..d3050a5
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
@@ -0,0 +1,504 @@
+/*
+ * 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.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.TupleType;
+import com.datastax.driver.core.TupleValue;
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.cql3.UntypedResultSet;
+import org.apache.cassandra.cql3.functions.FunctionName;
+import org.apache.cassandra.dht.ByteOrderedPartitioner;
+import org.apache.cassandra.exceptions.FunctionExecutionException;
+import org.apache.cassandra.transport.Server;
+import org.apache.cassandra.utils.UUIDGen;
+
+public class UFScriptTest extends CQLTester
+{
+ @BeforeClass
+ public static void setUp()
+ {
+ DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance);
+ }
+
+ @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"),
+ row(1d));
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fTup3 + "(tup) FROM %s WHERE key = 1"),
+ row(list));
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fTup4 + "(tup) FROM %s WHERE key = 1"),
+ row(set));
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fTup5 + "(tup) FROM %s WHERE key = 1"),
+ row(map));
+ }
+ }
+
+ @Test
+ public void testJavascriptUserType() throws Throwable
+ {
+ String type = createType("CREATE TYPE %s (txt text, i int)");
+
+ createTable("CREATE TABLE %s (key int primary key, udt frozen<" + type + ">)");
+
+ String fUdt1 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + " " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt;$$;");
+ String fUdt2 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getString(\"txt\");$$;");
+ String fUdt3 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getInt(\"i\");$$;");
+
+ execute("INSERT INTO %s (key, udt) VALUES (1, {txt: 'one', i:1})");
+
+ UntypedResultSet rows = execute("SELECT " + fUdt1 + "(udt) FROM %s WHERE key = 1");
+ Assert.assertEquals(1, rows.size());
+ assertRows(execute("SELECT " + fUdt2 + "(udt) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fUdt3 + "(udt) FROM %s WHERE key = 1"),
+ row(1));
+ }
+
+ @Test
+ public void testJavascriptUTCollections() throws Throwable
+ {
+ String type = 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 fName = createFunction(KEYSPACE, "list<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( lst list<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " lst.get(1).getString(\"txt\");$$;");
+ createFunctionOverload(fName, "set<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( st set<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " st.iterator().next().getString(\"txt\");$$;");
+ createFunctionOverload(fName, "map<int, frozen<" + type + ">>",
+ "CREATE FUNCTION %s( mp map<int, frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " mp.get(java.lang.Integer.valueOf(3)).getString(\"txt\");$$;");
+
+ execute("INSERT INTO %s (key, lst, st, mp) values (1, " +
+ // list<frozen<UDT>>
+ "[ {txt: 'one', i:1}, {txt: 'three', i:1}, {txt: 'one', i:1} ] , " +
+ // set<frozen<UDT>>
+ "{ {txt: 'one', i:1}, {txt: 'three', i:3}, {txt: 'two', i:2} }, " +
+ // map<int, frozen<UDT>>
+ "{ 1: {txt: 'one', i:1}, 2: {txt: 'one', i:3}, 3: {txt: 'two', i:2} })");
+
+ assertRows(execute("SELECT " + fName + "(lst) FROM %s WHERE key = 1"),
+ row("three"));
+ assertRows(execute("SELECT " + fName + "(st) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fName + "(mp) FROM %s WHERE key = 1"),
+ row("two"));
+
+ String cqlSelect = "SELECT " + fName + "(lst), " + fName + "(st), " + fName + "(mp) FROM %s WHERE key = 1";
+ assertRows(execute(cqlSelect),
+ row("three", "one", "two"));
+
+ // same test - but via native protocol
+ for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
+ assertRowsNet(version,
+ executeNet(version, cqlSelect),
+ row("three", "one", "two"));
+ }
+
+ @Test
+ public void testJavascriptFunction() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String functionBody = '\n' +
+ " Math.sin(val);\n";
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\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("javascript", 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 testJavascriptBadReturnType() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS '\"string\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ClassCastException
+ assertInvalidMessage("Invalid value for CQL type double", "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
+ public void testJavascriptThrow() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS 'throw \"fool\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ScriptException
+ assertInvalidThrowMessage("fool", FunctionExecutionException.class,
+ "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
+ public void testJavascriptCompileFailure() throws Throwable
+ {
+ assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS 'foo bar';");
+ }
+
+ @Test
+ public void testScriptInvalidLanguage() throws Throwable
+ {
+ assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE artificial_intelligence\n" +
+ "AS 'question for 42?';");
+ }
+
+ @Test
+ public void testScriptReturnTypeCasting() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+
+ Object[][] variations = {
+ new Object[] { "true", "boolean", true },
+ new Object[] { "false", "boolean", false },
+ new Object[] { "100", "tinyint", (byte)100 },
+ new Object[] { "100.", "tinyint", (byte)100 },
+ new Object[] { "100", "smallint", (short)100 },
+ new Object[] { "100.", "smallint", (short)100 },
+ new Object[] { "100", "int", 100 },
+ new Object[] { "100.", "int", 100 },
+ new Object[] { "100", "double", 100d },
+ new Object[] { "100.", "double", 100d },
+ new Object[] { "100", "bigint", 100L },
+ new Object[] { "100.", "bigint", 100L },
+ new Object[] { "100", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "100.", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "parseInt(\"100\");", "decimal", BigDecimal.valueOf(100d) },
+ new Object[] { "100.", "decimal", BigDecimal.valueOf(100d) },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object functionBody = variation[0];
+ Object returnType = variation[1];
+ Object expectedResult = variation[2];
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " +returnType + ' ' +
+ "LANGUAGE javascript " +
+ "AS '" + functionBody + ";';");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1d, expectedResult));
+ }
+ }
+
+ @Test
+ public void testScriptParamReturnTypes() throws Throwable
+ {
+ UUID ruuid = UUID.randomUUID();
+ UUID tuuid = UUIDGen.getTimeUUID();
+
+ createTable("CREATE TABLE %s (key int primary key, " +
+ "tival tinyint, sival smallint, ival int, lval bigint, fval float, dval double, vval varint, ddval decimal, " +
+ "timval time, dtval date, tsval timestamp, uval uuid, tuval timeuuid)");
+ execute("INSERT INTO %s (key, tival, sival, ival, lval, fval, dval, vval, ddval, timval, dtval, tsval, uval, tuval) VALUES " +
+ "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 1,
+ (byte)1, (short)1, 1, 1L, 1f, 1d, BigInteger.valueOf(1L), BigDecimal.valueOf(1d), 1L, Integer.MAX_VALUE, new Date(1), ruuid, tuuid);
+
+ Object[][] variations = {
+ new Object[] { "tinyint", "tival", (byte)1, (byte)2 },
+ new Object[] { "smallint", "sival", (short)1, (short)2 },
+ new Object[] { "int", "ival", 1, 2 },
+ new Object[] { "bigint", "lval", 1L, 2L },
+ new Object[] { "float", "fval", 1f, 2f },
+ new Object[] { "double", "dval", 1d, 2d },
+ new Object[] { "varint", "vval", BigInteger.valueOf(1L), BigInteger.valueOf(2L) },
+ new Object[] { "decimal", "ddval", BigDecimal.valueOf(1d), BigDecimal.valueOf(2d) },
+ new Object[] { "time", "timval", 1L, 2L },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val+1;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+
+ variations = new Object[][] {
+ new Object[] { "timestamp","tsval", new Date(1), new Date(1) },
+ new Object[] { "uuid", "uval", ruuid, ruuid },
+ new Object[] { "timeuuid", "tuval", tuuid, tuuid },
+ new Object[] { "date", "dtval", Integer.MAX_VALUE, Integer.MAX_VALUE },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+ }
+}
[16/25] 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/3aefe356
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/3aefe356
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/3aefe356
Branch: refs/heads/cassandra-3.0
Commit: 3aefe356545bcc2f5c4453e0d9d704bef339a008
Parents: 95d0b67 0b97c5d
Author: Robert Stupp <sn...@snazy.de>
Authored: Wed Dec 7 13:08:35 2016 +0100
Committer: Robert Stupp <sn...@snazy.de>
Committed: Wed Dec 7 13:08:35 2016 +0100
----------------------------------------------------------------------
.../cql3/validation/entities/UFJavaTest.java | 797 +++++++++
.../validation/entities/UFPureScriptTest.java | 406 -----
.../cql3/validation/entities/UFScriptTest.java | 428 +++++
.../validation/entities/UFSecurityTest.java | 258 +++
.../cql3/validation/entities/UFTest.java | 1519 +-----------------
.../cql3/validation/entities/UFTypesTest.java | 549 +++++++
6 files changed, 2033 insertions(+), 1924 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/3aefe356/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
index 0000000,caef808..15c8e18
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
@@@ -1,0 -1,1177 +1,797 @@@
+ /*
+ * 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.nio.ByteBuffer;
+ import java.util.Arrays;
+ import java.util.List;
+ import java.util.Map;
+ import java.util.Set;
+ import java.util.TreeMap;
+ import java.util.TreeSet;
+
+ 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 org.apache.cassandra.config.DatabaseDescriptor;
++import org.apache.cassandra.config.Schema;
+ import org.apache.cassandra.cql3.CQL3Type;
+ import org.apache.cassandra.cql3.CQLTester;
+ import org.apache.cassandra.cql3.UntypedResultSet;
+ import org.apache.cassandra.cql3.functions.FunctionName;
-import org.apache.cassandra.cql3.functions.Functions;
-import org.apache.cassandra.dht.ByteOrderedPartitioner;
+ import org.apache.cassandra.exceptions.FunctionExecutionException;
+ import org.apache.cassandra.exceptions.InvalidRequestException;
+ import org.apache.cassandra.transport.Server;
-import org.apache.cassandra.utils.ByteBufferUtil;
+
+ public class UFJavaTest extends CQLTester
+ {
- @BeforeClass
- public static void setUp()
- {
- DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance);
- }
-
-
+ @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=?",
++ 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=?",
++ 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 testJavaFunctionCounter() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val counter)");
+
+ String fName = createFunction(KEYSPACE, "counter",
+ "CREATE OR REPLACE FUNCTION %s(val counter) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS bigint " +
+ "LANGUAGE JAVA " +
+ "AS 'return val + 1;';");
+
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1L, 2L));
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ execute("UPDATE %s SET val = val + 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 4L, 5L));
+ execute("UPDATE %s SET val = val - 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ }
+
+ @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=?",
++ 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=?",
++ 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=?",
++ 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++)
++ for (int version : PROTOCOL_VERSIONS)
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fList + "(lst), " + fSet + "(st), " + fMap + "(mp) FROM %s WHERE key = 1"),
+ row(list, set, map));
+ }
+
+ @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()));
++ // same test - but via native protocol
++ // we use protocol V3 here to encode the expected version because the server
++ // always serializes Collections using V3 - see CollectionSerializer's
++ // serialize and deserialize methods.
++ TupleType tType = tupleTypeOf(Server.VERSION_3,
++ 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++)
++ for (int version : PROTOCOL_VERSIONS)
+ {
+ 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++)
++ for (int version : PROTOCOL_VERSIONS)
+ {
+ 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++)
++ for (int version : PROTOCOL_VERSIONS)
+ {
+ 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 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());
++ Assert.assertEquals(1, Schema.instance.getFunctions(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());
++ Assert.assertEquals(1, Schema.instance.getFunctions(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());
++ Assert.assertEquals(1, Schema.instance.getFunctions(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());
++ Assert.assertEquals(1, Schema.instance.getFunctions(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++)
++ for (int version : PROTOCOL_VERSIONS)
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fName1 + "(lst), " + fName2 + "(st), " + fName3 + "(mp) FROM %s WHERE key = 1"),
+ row("three", "one", "two"));
+ }
+
+ @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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<set<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS set<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<list<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS list<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<map<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS map<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<tuple<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, "(null, null)"),
- row(1, "(1, 2)"),
- row(2, "(4, 5)"),
- row(3, "(7, 8)"));
-
- functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS tuple<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
- }
-
- @Test
- public void testFunctionWithFrozenUDType() 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, 0);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<" + myType + "> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, "{f:0}"),
- row(1, "{f:1}"),
- row(2, "{f:4}"),
- row(3, "{f:7}"));
-
- functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS " + myType + " " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
- }
-
- @Test
- public void testEmptyString() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, sval text, aval ascii, bval blob, empty_int int)");
- execute("INSERT INTO %s (key, sval, aval, bval, empty_int) VALUES (?, ?, ?, ?, blobAsInt(0x))", 1, "", "", ByteBuffer.allocate(0));
-
- String fNameSRC = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameSCC = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return \"\";'");
-
- String fNameSRN = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameSCN = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return \"\";'");
-
- String fNameBRC = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "CALLED ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameBCC = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "CALLED ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return ByteBuffer.allocate(0);'");
-
- String fNameBRN = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameBCN = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return ByteBuffer.allocate(0);'");
-
- String fNameIRC = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameICC = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- String fNameIRN = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameICN = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- assertRows(execute("SELECT " + fNameSRC + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRN + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCC + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCN + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRC + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRN + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCC + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCN + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameBRC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBRN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBCC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBCN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameIRC + "(empty_int) FROM %s"), row(new Object[]{null}));
- assertRows(execute("SELECT " + fNameIRN + "(empty_int) FROM %s"), row(new Object[]{null}));
- assertRows(execute("SELECT " + fNameICC + "(empty_int) FROM %s"), row(0));
- assertRows(execute("SELECT " + fNameICN + "(empty_int) FROM %s"), row(new Object[]{null}));
- }
-
- @Test
+ public void testAllNativeTypes() throws Throwable
+ {
+ StringBuilder sig = new StringBuilder();
+ StringBuilder args = new StringBuilder();
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
++ if (type == CQL3Type.Native.EMPTY)
++ continue;
++
+ if (sig.length() > 0)
+ sig.append(',');
+ sig.append(type.toString());
+
+ if (args.length() > 0)
+ args.append(',');
+ args.append("arg").append(type.toString()).append(' ').append(type.toString());
+ }
+ createFunction(KEYSPACE, sig.toString(),
+ "CREATE OR REPLACE FUNCTION %s(" + args + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
++ if (type == CQL3Type.Native.EMPTY)
++ continue;
++
+ createFunction(KEYSPACE_PER_TEST, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type.toString() + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+ }
+ }
+ }
[08/25] cassandra git commit: testall failure in
org.apache.cassandra.cql3.validation.entities.UFTest.testAllNativeTypes
Posted by sn...@apache.org.
testall failure in org.apache.cassandra.cql3.validation.entities.UFTest.testAllNativeTypes
patch by Robert Stupp; reviewed by Alex Petrov for CASSANDRA-12817
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/0b97c5d1
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/0b97c5d1
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/0b97c5d1
Branch: refs/heads/trunk
Commit: 0b97c5d1f717be30a04c59c766465d9c62a4e9ee
Parents: 2e93398
Author: Robert Stupp <sn...@snazy.de>
Authored: Wed Dec 7 13:06:55 2016 +0100
Committer: Robert Stupp <sn...@snazy.de>
Committed: Wed Dec 7 13:06:55 2016 +0100
----------------------------------------------------------------------
.../cql3/validation/entities/UFJavaTest.java | 1177 +++++++++++++
.../cql3/validation/entities/UFScriptTest.java | 504 ++++++
.../cql3/validation/entities/UFTest.java | 1608 +-----------------
3 files changed, 1696 insertions(+), 1593 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0b97c5d1/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
new file mode 100644
index 0000000..caef808
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFJavaTest.java
@@ -0,0 +1,1177 @@
+/*
+ * 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.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+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 org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.cql3.CQL3Type;
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.cql3.UntypedResultSet;
+import org.apache.cassandra.cql3.functions.FunctionName;
+import org.apache.cassandra.cql3.functions.Functions;
+import org.apache.cassandra.dht.ByteOrderedPartitioner;
+import org.apache.cassandra.exceptions.FunctionExecutionException;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.transport.Server;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+public class UFJavaTest extends CQLTester
+{
+ @BeforeClass
+ public static void setUp()
+ {
+ DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance);
+ }
+
+
+ @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 testJavaFunctionCounter() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val counter)");
+
+ String fName = createFunction(KEYSPACE, "counter",
+ "CREATE OR REPLACE FUNCTION %s(val counter) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS bigint " +
+ "LANGUAGE JAVA " +
+ "AS 'return val + 1;';");
+
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1L, 2L));
+ execute("UPDATE %s SET val = val + 1 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ execute("UPDATE %s SET val = val + 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 4L, 5L));
+ execute("UPDATE %s SET val = val - 2 WHERE key = 1");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 2L, 3L));
+ }
+
+ @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 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 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 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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<set<int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "set<int>",
+ "CREATE FUNCTION %s (values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, 0),
+ row(1, 6),
+ row(2, 15),
+ row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "set<int>",
+ "CREATE FUNCTION %s (values set<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS set<int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<list<int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "list<int>",
+ "CREATE FUNCTION %s (values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, 0),
+ row(1, 6),
+ row(2, 15),
+ row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "list<int>",
+ "CREATE FUNCTION %s (values list<int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS list<int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
+ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
+ execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<map<int, int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "map<int, int>",
+ "CREATE FUNCTION %s (values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE java\n" +
+ "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, 0),
+ row(1, 6),
+ row(2, 15),
+ row(3, 24));
+
+ functionName = createFunction(KEYSPACE,
+ "map<int, int>",
+ "CREATE FUNCTION %s (values map<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS map<int, int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(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));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<tuple<int, int>> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ "tuple<int, int>",
+ "CREATE FUNCTION %s (values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, "(null, null)"),
+ row(1, "(1, 2)"),
+ row(2, "(4, 5)"),
+ row(3, "(7, 8)"));
+
+ functionName = createFunction(KEYSPACE,
+ "tuple<int, int>",
+ "CREATE FUNCTION %s (values tuple<int, int>) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS tuple<int, int> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
+ }
+
+ @Test
+ public void testFunctionWithFrozenUDType() 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, 0);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
+ execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertInvalidMessage("The function return type should not be frozen",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS frozen<" + myType + "> " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ String functionName = createFunction(KEYSPACE,
+ myType,
+ "CREATE FUNCTION %s (values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE java\n" +
+ "AS 'return values.toString();';");
+
+ assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
+ row(0, "{f:0}"),
+ row(1, "{f:1}"),
+ row(2, "{f:4}"),
+ row(3, "{f:7}"));
+
+ functionName = createFunction(KEYSPACE,
+ myType,
+ "CREATE FUNCTION %s (values " + myType + ") " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS " + myType + " " +
+ "LANGUAGE java\n" +
+ "AS 'return values;';");
+
+ assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
+ row(1));
+
+ assertInvalidMessage("The function arguments should not be frozen",
+ "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
+ }
+
+ @Test
+ public void testEmptyString() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, sval text, aval ascii, bval blob, empty_int int)");
+ execute("INSERT INTO %s (key, sval, aval, bval, empty_int) VALUES (?, ?, ?, ?, blobAsInt(0x))", 1, "", "", ByteBuffer.allocate(0));
+
+ String fNameSRC = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameSCC = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return \"\";'");
+
+ String fNameSRN = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameSCN = createFunction(KEYSPACE_PER_TEST, "text",
+ "CREATE OR REPLACE FUNCTION %s(val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return \"\";'");
+
+ String fNameBRC = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameBCC = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return ByteBuffer.allocate(0);'");
+
+ String fNameBRN = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameBCN = createFunction(KEYSPACE_PER_TEST, "blob",
+ "CREATE OR REPLACE FUNCTION %s(val blob) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS blob " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return ByteBuffer.allocate(0);'");
+
+ String fNameIRC = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameICC = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "CALLED ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ String fNameIRN = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return val;'");
+
+ String fNameICN = createFunction(KEYSPACE_PER_TEST, "int",
+ "CREATE OR REPLACE FUNCTION %s(val int) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ assertRows(execute("SELECT " + fNameSRC + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRN + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCC + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCN + "(sval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRC + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSRN + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCC + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameSCN + "(aval) FROM %s"), row(""));
+ assertRows(execute("SELECT " + fNameBRC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBRN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBCC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameBCN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ assertRows(execute("SELECT " + fNameIRC + "(empty_int) FROM %s"), row(new Object[]{null}));
+ assertRows(execute("SELECT " + fNameIRN + "(empty_int) FROM %s"), row(new Object[]{null}));
+ assertRows(execute("SELECT " + fNameICC + "(empty_int) FROM %s"), row(0));
+ assertRows(execute("SELECT " + fNameICN + "(empty_int) FROM %s"), row(new Object[]{null}));
+ }
+
+ @Test
+ public void testAllNativeTypes() throws Throwable
+ {
+ StringBuilder sig = new StringBuilder();
+ StringBuilder args = new StringBuilder();
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
+ if (sig.length() > 0)
+ sig.append(',');
+ sig.append(type.toString());
+
+ if (args.length() > 0)
+ args.append(',');
+ args.append("arg").append(type.toString()).append(' ').append(type.toString());
+ }
+ createFunction(KEYSPACE, sig.toString(),
+ "CREATE OR REPLACE FUNCTION %s(" + args + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+
+ for (CQL3Type.Native type : CQL3Type.Native.values())
+ {
+ createFunction(KEYSPACE_PER_TEST, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type.toString() + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE JAVA\n" +
+ "AS 'return 0;'");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0b97c5d1/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
new file mode 100644
index 0000000..d3050a5
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFScriptTest.java
@@ -0,0 +1,504 @@
+/*
+ * 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.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.TupleType;
+import com.datastax.driver.core.TupleValue;
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.cql3.UntypedResultSet;
+import org.apache.cassandra.cql3.functions.FunctionName;
+import org.apache.cassandra.dht.ByteOrderedPartitioner;
+import org.apache.cassandra.exceptions.FunctionExecutionException;
+import org.apache.cassandra.transport.Server;
+import org.apache.cassandra.utils.UUIDGen;
+
+public class UFScriptTest extends CQLTester
+{
+ @BeforeClass
+ public static void setUp()
+ {
+ DatabaseDescriptor.setPartitioner(ByteOrderedPartitioner.instance);
+ }
+
+ @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"),
+ row(1d));
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fTup3 + "(tup) FROM %s WHERE key = 1"),
+ row(list));
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fTup4 + "(tup) FROM %s WHERE key = 1"),
+ row(set));
+ assertRowsNet(version,
+ executeNet(version, "SELECT " + fTup5 + "(tup) FROM %s WHERE key = 1"),
+ row(map));
+ }
+ }
+
+ @Test
+ public void testJavascriptUserType() throws Throwable
+ {
+ String type = createType("CREATE TYPE %s (txt text, i int)");
+
+ createTable("CREATE TABLE %s (key int primary key, udt frozen<" + type + ">)");
+
+ String fUdt1 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + " " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt;$$;");
+ String fUdt2 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getString(\"txt\");$$;");
+ String fUdt3 = createFunction(KEYSPACE, type,
+ "CREATE FUNCTION %s( udt " + type + " ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS int " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " udt.getInt(\"i\");$$;");
+
+ execute("INSERT INTO %s (key, udt) VALUES (1, {txt: 'one', i:1})");
+
+ UntypedResultSet rows = execute("SELECT " + fUdt1 + "(udt) FROM %s WHERE key = 1");
+ Assert.assertEquals(1, rows.size());
+ assertRows(execute("SELECT " + fUdt2 + "(udt) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fUdt3 + "(udt) FROM %s WHERE key = 1"),
+ row(1));
+ }
+
+ @Test
+ public void testJavascriptUTCollections() throws Throwable
+ {
+ String type = 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 fName = createFunction(KEYSPACE, "list<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( lst list<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " lst.get(1).getString(\"txt\");$$;");
+ createFunctionOverload(fName, "set<frozen<" + type + ">>",
+ "CREATE FUNCTION %s( st set<frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " st.iterator().next().getString(\"txt\");$$;");
+ createFunctionOverload(fName, "map<int, frozen<" + type + ">>",
+ "CREATE FUNCTION %s( mp map<int, frozen<" + type + ">> ) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS $$" +
+ " mp.get(java.lang.Integer.valueOf(3)).getString(\"txt\");$$;");
+
+ execute("INSERT INTO %s (key, lst, st, mp) values (1, " +
+ // list<frozen<UDT>>
+ "[ {txt: 'one', i:1}, {txt: 'three', i:1}, {txt: 'one', i:1} ] , " +
+ // set<frozen<UDT>>
+ "{ {txt: 'one', i:1}, {txt: 'three', i:3}, {txt: 'two', i:2} }, " +
+ // map<int, frozen<UDT>>
+ "{ 1: {txt: 'one', i:1}, 2: {txt: 'one', i:3}, 3: {txt: 'two', i:2} })");
+
+ assertRows(execute("SELECT " + fName + "(lst) FROM %s WHERE key = 1"),
+ row("three"));
+ assertRows(execute("SELECT " + fName + "(st) FROM %s WHERE key = 1"),
+ row("one"));
+ assertRows(execute("SELECT " + fName + "(mp) FROM %s WHERE key = 1"),
+ row("two"));
+
+ String cqlSelect = "SELECT " + fName + "(lst), " + fName + "(st), " + fName + "(mp) FROM %s WHERE key = 1";
+ assertRows(execute(cqlSelect),
+ row("three", "one", "two"));
+
+ // same test - but via native protocol
+ for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
+ assertRowsNet(version,
+ executeNet(version, cqlSelect),
+ row("three", "one", "two"));
+ }
+
+ @Test
+ public void testJavascriptFunction() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String functionBody = '\n' +
+ " Math.sin(val);\n";
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\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("javascript", 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 testJavascriptBadReturnType() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS '\"string\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ClassCastException
+ assertInvalidMessage("Invalid value for CQL type double", "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
+ public void testJavascriptThrow() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS 'throw \"fool\";';");
+
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+ // throws IRE with ScriptException
+ assertInvalidThrowMessage("fool", FunctionExecutionException.class,
+ "SELECT key, val, " + fName + "(val) FROM %s");
+ }
+
+ @Test
+ public void testJavascriptCompileFailure() throws Throwable
+ {
+ assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE javascript\n" +
+ "AS 'foo bar';");
+ }
+
+ @Test
+ public void testScriptInvalidLanguage() throws Throwable
+ {
+ assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS double " +
+ "LANGUAGE artificial_intelligence\n" +
+ "AS 'question for 42?';");
+ }
+
+ @Test
+ public void testScriptReturnTypeCasting() throws Throwable
+ {
+ createTable("CREATE TABLE %s (key int primary key, val double)");
+ execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
+
+ Object[][] variations = {
+ new Object[] { "true", "boolean", true },
+ new Object[] { "false", "boolean", false },
+ new Object[] { "100", "tinyint", (byte)100 },
+ new Object[] { "100.", "tinyint", (byte)100 },
+ new Object[] { "100", "smallint", (short)100 },
+ new Object[] { "100.", "smallint", (short)100 },
+ new Object[] { "100", "int", 100 },
+ new Object[] { "100.", "int", 100 },
+ new Object[] { "100", "double", 100d },
+ new Object[] { "100.", "double", 100d },
+ new Object[] { "100", "bigint", 100L },
+ new Object[] { "100.", "bigint", 100L },
+ new Object[] { "100", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "100.", "varint", BigInteger.valueOf(100L) },
+ new Object[] { "parseInt(\"100\");", "decimal", BigDecimal.valueOf(100d) },
+ new Object[] { "100.", "decimal", BigDecimal.valueOf(100d) },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object functionBody = variation[0];
+ Object returnType = variation[1];
+ Object expectedResult = variation[2];
+
+ String fName = createFunction(KEYSPACE, "double",
+ "CREATE OR REPLACE FUNCTION %s(val double) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " +returnType + ' ' +
+ "LANGUAGE javascript " +
+ "AS '" + functionBody + ";';");
+ assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
+ row(1, 1d, expectedResult));
+ }
+ }
+
+ @Test
+ public void testScriptParamReturnTypes() throws Throwable
+ {
+ UUID ruuid = UUID.randomUUID();
+ UUID tuuid = UUIDGen.getTimeUUID();
+
+ createTable("CREATE TABLE %s (key int primary key, " +
+ "tival tinyint, sival smallint, ival int, lval bigint, fval float, dval double, vval varint, ddval decimal, " +
+ "timval time, dtval date, tsval timestamp, uval uuid, tuval timeuuid)");
+ execute("INSERT INTO %s (key, tival, sival, ival, lval, fval, dval, vval, ddval, timval, dtval, tsval, uval, tuval) VALUES " +
+ "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 1,
+ (byte)1, (short)1, 1, 1L, 1f, 1d, BigInteger.valueOf(1L), BigDecimal.valueOf(1d), 1L, Integer.MAX_VALUE, new Date(1), ruuid, tuuid);
+
+ Object[][] variations = {
+ new Object[] { "tinyint", "tival", (byte)1, (byte)2 },
+ new Object[] { "smallint", "sival", (short)1, (short)2 },
+ new Object[] { "int", "ival", 1, 2 },
+ new Object[] { "bigint", "lval", 1L, 2L },
+ new Object[] { "float", "fval", 1f, 2f },
+ new Object[] { "double", "dval", 1d, 2d },
+ new Object[] { "varint", "vval", BigInteger.valueOf(1L), BigInteger.valueOf(2L) },
+ new Object[] { "decimal", "ddval", BigDecimal.valueOf(1d), BigDecimal.valueOf(2d) },
+ new Object[] { "time", "timval", 1L, 2L },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val+1;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+
+ variations = new Object[][] {
+ new Object[] { "timestamp","tsval", new Date(1), new Date(1) },
+ new Object[] { "uuid", "uval", ruuid, ruuid },
+ new Object[] { "timeuuid", "tuval", tuuid, tuuid },
+ new Object[] { "date", "dtval", Integer.MAX_VALUE, Integer.MAX_VALUE },
+ };
+
+ for (Object[] variation : variations)
+ {
+ Object type = variation[0];
+ Object col = variation[1];
+ Object expected1 = variation[2];
+ Object expected2 = variation[3];
+ String fName = createFunction(KEYSPACE, type.toString(),
+ "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS " + type + ' ' +
+ "LANGUAGE javascript " +
+ "AS 'val;';");
+ assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
+ row(1, expected1, expected2));
+ }
+ }
+}
[03/25] cassandra git commit: testall failure in
org.apache.cassandra.cql3.validation.entities.UFTest.testAllNativeTypes
Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0b97c5d1/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
index bcfe871..d4d2a10 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
@@ -17,9 +17,6 @@
*/
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;
@@ -34,14 +31,9 @@ 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;
@@ -50,13 +42,11 @@ 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
@@ -295,7 +285,7 @@ public class UFTest extends CQLTester
return prepared;
}
- public void checkDelayedValuesCorrectlyIdentifyFunctionsInUse(boolean dropKeyspace) throws Throwable
+ private void checkDelayedValuesCorrectlyIdentifyFunctionsInUse(boolean dropKeyspace) throws Throwable
{
// prepare a statement which doesn't use any function for a control
createTable("CREATE TABLE %s (" +
@@ -584,164 +574,6 @@ public class UFTest extends CQLTester
}
@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 testJavaFunctionCounter() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val counter)");
-
- String fName = createFunction(KEYSPACE, "counter",
- "CREATE OR REPLACE FUNCTION %s(val counter) " +
- "CALLED ON NULL INPUT " +
- "RETURNS bigint " +
- "LANGUAGE JAVA " +
- "AS 'return val + 1;';");
-
- execute("UPDATE %s SET val = val + 1 WHERE key = 1");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 1L, 2L));
- execute("UPDATE %s SET val = val + 1 WHERE key = 1");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 2L, 3L));
- execute("UPDATE %s SET val = val + 2 WHERE key = 1");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 4L, 5L));
- execute("UPDATE %s SET val = val - 2 WHERE key = 1");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 2L, 3L));
- }
-
- @Test
public void testFunctionInTargetKeyspace() throws Throwable
{
createTable("CREATE TABLE %s (key int primary key, val double)");
@@ -869,140 +701,6 @@ public class UFTest extends CQLTester
}
@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)");
@@ -1135,206 +833,6 @@ public class UFTest extends CQLTester
}
@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)");
@@ -1372,686 +870,22 @@ public class UFTest extends CQLTester
}
@Test
- public void testJavaUserTypeRenameField() throws Throwable
+ public void testDuplicateArgNames() throws Throwable
{
- String type = KEYSPACE + '.' + createType("CREATE TYPE %s (txt text, i int)");
+ assertInvalidMessage("duplicate argument names for given function",
+ "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double, val text) " +
+ "RETURNS NULL ON NULL INPUT " +
+ "RETURNS text " +
+ "LANGUAGE javascript\n" +
+ "AS '\"foo bar\";';");
+ }
- 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"),
- row(1d));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup3 + "(tup) FROM %s WHERE key = 1"),
- row(list));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup4 + "(tup) FROM %s WHERE key = 1"),
- row(set));
- assertRowsNet(version,
- executeNet(version, "SELECT " + fTup5 + "(tup) FROM %s WHERE key = 1"),
- row(map));
- }
- }
-
- @Test
- public void testJavascriptUserType() throws Throwable
- {
- String type = createType("CREATE TYPE %s (txt text, i int)");
-
- createTable("CREATE TABLE %s (key int primary key, udt frozen<" + type + ">)");
-
- String fUdt1 = createFunction(KEYSPACE, type,
- "CREATE FUNCTION %s( udt " + type + " ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS " + type + " " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " udt;$$;");
- String fUdt2 = createFunction(KEYSPACE, type,
- "CREATE FUNCTION %s( udt " + type + " ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " udt.getString(\"txt\");$$;");
- String fUdt3 = createFunction(KEYSPACE, type,
- "CREATE FUNCTION %s( udt " + type + " ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " udt.getInt(\"i\");$$;");
-
- execute("INSERT INTO %s (key, udt) VALUES (1, {txt: 'one', i:1})");
-
- UntypedResultSet rows = execute("SELECT " + fUdt1 + "(udt) FROM %s WHERE key = 1");
- Assert.assertEquals(1, rows.size());
- assertRows(execute("SELECT " + fUdt2 + "(udt) FROM %s WHERE key = 1"),
- row("one"));
- assertRows(execute("SELECT " + fUdt3 + "(udt) FROM %s WHERE key = 1"),
- row(1));
- }
-
- @Test
- public void testJavascriptUTCollections() throws Throwable
- {
- String type = 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 fName = createFunction(KEYSPACE, "list<frozen<" + type + ">>",
- "CREATE FUNCTION %s( lst list<frozen<" + type + ">> ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " lst.get(1).getString(\"txt\");$$;");
- createFunctionOverload(fName, "set<frozen<" + type + ">>",
- "CREATE FUNCTION %s( st set<frozen<" + type + ">> ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " st.iterator().next().getString(\"txt\");$$;");
- createFunctionOverload(fName, "map<int, frozen<" + type + ">>",
- "CREATE FUNCTION %s( mp map<int, frozen<" + type + ">> ) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS $$" +
- " mp.get(java.lang.Integer.valueOf(3)).getString(\"txt\");$$;");
-
- execute("INSERT INTO %s (key, lst, st, mp) values (1, " +
- // list<frozen<UDT>>
- "[ {txt: 'one', i:1}, {txt: 'three', i:1}, {txt: 'one', i:1} ] , " +
- // set<frozen<UDT>>
- "{ {txt: 'one', i:1}, {txt: 'three', i:3}, {txt: 'two', i:2} }, " +
- // map<int, frozen<UDT>>
- "{ 1: {txt: 'one', i:1}, 2: {txt: 'one', i:3}, 3: {txt: 'two', i:2} })");
-
- assertRows(execute("SELECT " + fName + "(lst) FROM %s WHERE key = 1"),
- row("three"));
- assertRows(execute("SELECT " + fName + "(st) FROM %s WHERE key = 1"),
- row("one"));
- assertRows(execute("SELECT " + fName + "(mp) FROM %s WHERE key = 1"),
- row("two"));
-
- String cqlSelect = "SELECT " + fName + "(lst), " + fName + "(st), " + fName + "(mp) FROM %s WHERE key = 1";
- assertRows(execute(cqlSelect),
- row("three", "one", "two"));
-
- // same test - but via native protocol
- for (int version = Server.VERSION_2; version <= maxProtocolVersion; version++)
- assertRowsNet(version,
- executeNet(version, cqlSelect),
- row("three", "one", "two"));
- }
-
- @Test
- public void testJavascriptFunction() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val double)");
-
- String functionBody = '\n' +
- " Math.sin(val);\n";
-
- String fName = createFunction(KEYSPACE, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\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("javascript", 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 testJavascriptBadReturnType() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val double)");
-
- String fName = createFunction(KEYSPACE, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS '\"string\";';");
-
- execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
- // throws IRE with ClassCastException
- assertInvalidMessage("Invalid value for CQL type double", "SELECT key, val, " + fName + "(val) FROM %s");
- }
-
- @Test
- public void testJavascriptThrow() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val double)");
-
- String fName = createFunction(KEYSPACE, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS 'throw \"fool\";';");
-
- execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
- // throws IRE with ScriptException
- assertInvalidThrowMessage("fool", FunctionExecutionException.class,
- "SELECT key, val, " + fName + "(val) FROM %s");
- }
-
- @Test
- public void testDuplicateArgNames() throws Throwable
- {
- assertInvalidMessage("duplicate argument names for given function",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double, val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE javascript\n" +
- "AS '\"foo bar\";';");
- }
-
- @Test
- public void testJavascriptCompileFailure() throws Throwable
- {
- assertInvalidMessage("Failed to compile function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE javascript\n" +
- "AS 'foo bar';");
- }
-
- @Test
- public void testScriptInvalidLanguage() throws Throwable
- {
- assertInvalidMessage("Invalid language 'artificial_intelligence' for function 'cql_test_keyspace.scrinv'",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".scrinv(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS double " +
- "LANGUAGE artificial_intelligence\n" +
- "AS 'question for 42?';");
- }
-
- @Test
- public void testScriptReturnTypeCasting() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, val double)");
- execute("INSERT INTO %s (key, val) VALUES (?, ?)", 1, 1d);
-
- Object[][] variations = {
- new Object[] { "true", "boolean", true },
- new Object[] { "false", "boolean", false },
- new Object[] { "100", "tinyint", (byte)100 },
- new Object[] { "100.", "tinyint", (byte)100 },
- new Object[] { "100", "smallint", (short)100 },
- new Object[] { "100.", "smallint", (short)100 },
- new Object[] { "100", "int", 100 },
- new Object[] { "100.", "int", 100 },
- new Object[] { "100", "double", 100d },
- new Object[] { "100.", "double", 100d },
- new Object[] { "100", "bigint", 100L },
- new Object[] { "100.", "bigint", 100L },
- new Object[] { "100", "varint", BigInteger.valueOf(100L) },
- new Object[] { "100.", "varint", BigInteger.valueOf(100L) },
- new Object[] { "parseInt(\"100\");", "decimal", BigDecimal.valueOf(100d) },
- new Object[] { "100.", "decimal", BigDecimal.valueOf(100d) },
- };
-
- for (Object[] variation : variations)
- {
- Object functionBody = variation[0];
- Object returnType = variation[1];
- Object expectedResult = variation[2];
-
- String fName = createFunction(KEYSPACE, "double",
- "CREATE OR REPLACE FUNCTION %s(val double) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS " +returnType + ' ' +
- "LANGUAGE javascript " +
- "AS '" + functionBody + ";';");
- assertRows(execute("SELECT key, val, " + fName + "(val) FROM %s"),
- row(1, 1d, expectedResult));
- }
- }
-
- @Test
- public void testScriptParamReturnTypes() throws Throwable
- {
- UUID ruuid = UUID.randomUUID();
- UUID tuuid = UUIDGen.getTimeUUID();
-
- createTable("CREATE TABLE %s (key int primary key, " +
- "tival tinyint, sival smallint, ival int, lval bigint, fval float, dval double, vval varint, ddval decimal, " +
- "timval time, dtval date, tsval timestamp, uval uuid, tuval timeuuid)");
- execute("INSERT INTO %s (key, tival, sival, ival, lval, fval, dval, vval, ddval, timval, dtval, tsval, uval, tuval) VALUES " +
- "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 1,
- (byte)1, (short)1, 1, 1L, 1f, 1d, BigInteger.valueOf(1L), BigDecimal.valueOf(1d), 1L, Integer.MAX_VALUE, new Date(1), ruuid, tuuid);
-
- Object[][] variations = {
- new Object[] { "tinyint", "tival", (byte)1, (byte)2 },
- new Object[] { "smallint", "sival", (short)1, (short)2 },
- new Object[] { "int", "ival", 1, 2 },
- new Object[] { "bigint", "lval", 1L, 2L },
- new Object[] { "float", "fval", 1f, 2f },
- new Object[] { "double", "dval", 1d, 2d },
- new Object[] { "varint", "vval", BigInteger.valueOf(1L), BigInteger.valueOf(2L) },
- new Object[] { "decimal", "ddval", BigDecimal.valueOf(1d), BigDecimal.valueOf(2d) },
- new Object[] { "time", "timval", 1L, 2L },
- };
-
- for (Object[] variation : variations)
- {
- Object type = variation[0];
- Object col = variation[1];
- Object expected1 = variation[2];
- Object expected2 = variation[3];
- String fName = createFunction(KEYSPACE, type.toString(),
- "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS " + type + ' ' +
- "LANGUAGE javascript " +
- "AS 'val+1;';");
- assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
- row(1, expected1, expected2));
- }
-
- variations = new Object[][] {
- new Object[] { "timestamp","tsval", new Date(1), new Date(1) },
- new Object[] { "uuid", "uval", ruuid, ruuid },
- new Object[] { "timeuuid", "tuval", tuuid, tuuid },
- new Object[] { "date", "dtval", Integer.MAX_VALUE, Integer.MAX_VALUE },
- };
-
- for (Object[] variation : variations)
- {
- Object type = variation[0];
- Object col = variation[1];
- Object expected1 = variation[2];
- Object expected2 = variation[3];
- String fName = createFunction(KEYSPACE, type.toString(),
- "CREATE OR REPLACE FUNCTION %s(val " + type + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS " + type + ' ' +
- "LANGUAGE javascript " +
- "AS 'val;';");
- assertRows(execute("SELECT key, " + col + ", " + fName + '(' + col + ") FROM %s"),
- row(1, expected1, expected2));
- }
- }
-
- static class TypesTestDef
- {
- final String udfType;
- final String tableType;
- final String columnName;
- final Object referenceValue;
+ private static class TypesTestDef
+ {
+ final String udfType;
+ final String tableType;
+ final String columnName;
+ final Object referenceValue;
String fCheckArgAndReturn;
@@ -2274,416 +1108,4 @@ public class UFTest extends CQLTester
}
}
}
-
- @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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenSetArg(values frozen<set<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<set<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "set<int>",
- "CREATE FUNCTION %s (values set<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS set<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<list<int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<list<int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "list<int>",
- "CREATE FUNCTION %s (values list<int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS list<int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", set(1, 2, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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, 1, 2, 2, 3, 3));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 2, map(4, 4, 5, 5, 6, 6));
- execute("INSERT INTO %s (a, b) VALUES (?, ?)", 3, map(7, 7, 8, 8, 9, 9));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<map<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += value;} return sum;';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<map<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE java\n" +
- "AS 'int sum = 0; for (Object value : values.values()) {sum += ((Integer) value);} return sum;';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, 0),
- row(1, 6),
- row(2, 15),
- row(3, 24));
-
- functionName = createFunction(KEYSPACE,
- "map<int, int>",
- "CREATE FUNCTION %s (values map<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS map<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", map(1, 1, 2, 2, 3, 3)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(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));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<tuple<int, int>>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<tuple<int, int>> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, "(null, null)"),
- row(1, "(1, 2)"),
- row(2, "(4, 5)"),
- row(3, "(7, 8)"));
-
- functionName = createFunction(KEYSPACE,
- "tuple<int, int>",
- "CREATE FUNCTION %s (values tuple<int, int>) " +
- "CALLED ON NULL INPUT " +
- "RETURNS tuple<int, int> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "(?)", tuple(1, 2)),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<tuple<int, int>>);");
- }
-
- @Test
- public void testFunctionWithFrozenUDType() 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, 0);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 1, 1);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 2, 4);
- execute("INSERT INTO %s (a, b) VALUES (?, {f : ?})", 3, 7);
-
- assertInvalidMessage("The function arguments should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".withFrozenArg(values frozen<" + myType + ">) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertInvalidMessage("The function return type should not be frozen",
- "CREATE OR REPLACE FUNCTION " + KEYSPACE + ".frozenReturnType(values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS frozen<" + myType + "> " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- String functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE java\n" +
- "AS 'return values.toString();';");
-
- assertRows(execute("SELECT a, " + functionName + "(b) FROM %s"),
- row(0, "{f:0}"),
- row(1, "{f:1}"),
- row(2, "{f:4}"),
- row(3, "{f:7}"));
-
- functionName = createFunction(KEYSPACE,
- myType,
- "CREATE FUNCTION %s (values " + myType + ") " +
- "CALLED ON NULL INPUT " +
- "RETURNS " + myType + " " +
- "LANGUAGE java\n" +
- "AS 'return values;';");
-
- assertRows(execute("SELECT a FROM %s WHERE b = " + functionName + "({f: ?})", 1),
- row(1));
-
- assertInvalidMessage("The function arguments should not be frozen",
- "DROP FUNCTION " + functionName + "(frozen<" + myType + ">);");
- }
-
- @Test
- public void testEmptyString() throws Throwable
- {
- createTable("CREATE TABLE %s (key int primary key, sval text, aval ascii, bval blob, empty_int int)");
- execute("INSERT INTO %s (key, sval, aval, bval, empty_int) VALUES (?, ?, ?, ?, blobAsInt(0x))", 1, "", "", ByteBuffer.allocate(0));
-
- String fNameSRC = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameSCC = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "CALLED ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return \"\";'");
-
- String fNameSRN = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameSCN = createFunction(KEYSPACE_PER_TEST, "text",
- "CREATE OR REPLACE FUNCTION %s(val text) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS text " +
- "LANGUAGE JAVA\n" +
- "AS 'return \"\";'");
-
- String fNameBRC = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "CALLED ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameBCC = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "CALLED ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return ByteBuffer.allocate(0);'");
-
- String fNameBRN = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameBCN = createFunction(KEYSPACE_PER_TEST, "blob",
- "CREATE OR REPLACE FUNCTION %s(val blob) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS blob " +
- "LANGUAGE JAVA\n" +
- "AS 'return ByteBuffer.allocate(0);'");
-
- String fNameIRC = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameICC = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "CALLED ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- String fNameIRN = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return val;'");
-
- String fNameICN = createFunction(KEYSPACE_PER_TEST, "int",
- "CREATE OR REPLACE FUNCTION %s(val int) " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- assertRows(execute("SELECT " + fNameSRC + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRN + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCC + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCN + "(sval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRC + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSRN + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCC + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameSCN + "(aval) FROM %s"), row(""));
- assertRows(execute("SELECT " + fNameBRC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBRN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBCC + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameBCN + "(bval) FROM %s"), row(ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertRows(execute("SELECT " + fNameIRC + "(empty_int) FROM %s"), row(new Object[]{null}));
- assertRows(execute("SELECT " + fNameIRN + "(empty_int) FROM %s"), row(new Object[]{null}));
- assertRows(execute("SELECT " + fNameICC + "(empty_int) FROM %s"), row(0));
- assertRows(execute("SELECT " + fNameICN + "(empty_int) FROM %s"), row(new Object[]{null}));
- }
-
- @Test
- public void testAllNativeTypes() throws Throwable
- {
- StringBuilder sig = new StringBuilder();
- StringBuilder args = new StringBuilder();
- for (CQL3Type.Native type : CQL3Type.Native.values())
- {
- if (sig.length() > 0)
- sig.append(',');
- sig.append(type.toString());
-
- if (args.length() > 0)
- args.append(',');
- args.append("arg").append(type.toString()).append(' ').append(type.toString());
- }
- createFunction(KEYSPACE, sig.toString(),
- "CREATE OR REPLACE FUNCTION %s(" + args + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
-
- for (CQL3Type.Native type : CQL3Type.Native.values())
- {
- createFunction(KEYSPACE_PER_TEST, type.toString(),
- "CREATE OR REPLACE FUNCTION %s(val " + type.toString() + ") " +
- "RETURNS NULL ON NULL INPUT " +
- "RETURNS int " +
- "LANGUAGE JAVA\n" +
- "AS 'return 0;'");
- }
- }
}