use of org.apache.cassandra.cql3.functions.UDFunction in project cassandra by apache.
the class CreateFunctionStatement method apply.
// TODO: replace affected aggregates !!
public Keyspaces apply(Keyspaces schema) {
if (ifNotExists && orReplace)
throw ire("Cannot use both 'OR REPLACE' and 'IF NOT EXISTS' directives");
UDFunction.assertUdfsEnabled(language);
if (new HashSet<>(argumentNames).size() != argumentNames.size())
throw ire("Duplicate argument names for given function %s with argument names %s", functionName, argumentNames);
rawArgumentTypes.stream().filter(raw -> !raw.isTuple() && raw.isFrozen()).findFirst().ifPresent(t -> {
throw ire("Argument '%s' cannot be frozen; remove frozen<> modifier from '%s'", t, t);
});
if (!rawReturnType.isTuple() && rawReturnType.isFrozen())
throw ire("Return type '%s' cannot be frozen; remove frozen<> modifier from '%s'", rawReturnType, rawReturnType);
KeyspaceMetadata keyspace = schema.getNullable(keyspaceName);
if (null == keyspace)
throw ire("Keyspace '%s' doesn't exist", keyspaceName);
List<AbstractType<?>> argumentTypes = rawArgumentTypes.stream().map(t -> t.prepare(keyspaceName, keyspace.types).getType()).collect(toList());
AbstractType<?> returnType = rawReturnType.prepare(keyspaceName, keyspace.types).getType();
UDFunction function = UDFunction.create(new FunctionName(keyspaceName, functionName), argumentNames, argumentTypes, returnType, calledOnNullInput, language, body);
Function existingFunction = keyspace.functions.find(function.name(), argumentTypes).orElse(null);
if (null != existingFunction) {
if (existingFunction.isAggregate())
throw ire("Function '%s' cannot replace an aggregate", functionName);
if (ifNotExists)
return schema;
if (!orReplace)
throw ire("Function '%s' already exists", functionName);
if (calledOnNullInput != ((UDFunction) existingFunction).isCalledOnNullInput()) {
throw ire("Function '%s' must have %s directive", functionName, calledOnNullInput ? "CALLED ON NULL INPUT" : "RETURNS NULL ON NULL INPUT");
}
if (!returnType.isCompatibleWith(existingFunction.returnType())) {
throw ire("Cannot replace function '%s', the new return type %s is not compatible with the return type %s of existing function", functionName, returnType.asCQL3Type(), existingFunction.returnType().asCQL3Type());
}
// TODO: update dependent aggregates
}
return schema.withAddedOrUpdated(keyspace.withSwapped(keyspace.functions.withAddedOrUpdated(function)));
}
use of org.apache.cassandra.cql3.functions.UDFunction in project cassandra by apache.
the class SchemaKeyspace method createUDAFromRow.
private static UDAggregate createUDAFromRow(UntypedResultSet.Row row, Collection<UDFunction> functions, Types types) {
String ksName = row.getString("keyspace_name");
String functionName = row.getString("aggregate_name");
FunctionName name = new FunctionName(ksName, functionName);
List<AbstractType<?>> argTypes = row.getFrozenList("argument_types", UTF8Type.instance).stream().map(t -> CQLTypeParser.parse(ksName, t, types)).collect(toList());
AbstractType<?> returnType = CQLTypeParser.parse(ksName, row.getString("return_type"), types);
FunctionName stateFunc = new FunctionName(ksName, (row.getString("state_func")));
FunctionName finalFunc = row.has("final_func") ? new FunctionName(ksName, row.getString("final_func")) : null;
AbstractType<?> stateType = row.has("state_type") ? CQLTypeParser.parse(ksName, row.getString("state_type"), types) : null;
ByteBuffer initcond = row.has("initcond") ? Terms.asBytes(ksName, row.getString("initcond"), stateType) : null;
return UDAggregate.create(functions, name, argTypes, returnType, stateFunc, finalFunc, stateType, initcond);
}
use of org.apache.cassandra.cql3.functions.UDFunction in project cassandra by apache.
the class UFJavaTest method testUDAToCqlString.
@Test
public void testUDAToCqlString() throws Throwable {
// we have to create this function in DB otherwise UDAggregate creation below fails
String stateFunctionName = createFunction(KEYSPACE, "int,int", "CREATE OR REPLACE FUNCTION %s(state int, val int)\n" + " CALLED ON NULL INPUT\n" + " RETURNS int\n" + " LANGUAGE java\n" + " AS $$\n" + " return state + val;\n" + " $$;");
// Java representation of state function so we can construct aggregate programmatically
UDFunction stateFunction = UDFunction.create(new FunctionName(KEYSPACE, stateFunctionName.split("\\.")[1]), Arrays.asList(ColumnIdentifier.getInterned("state", false), ColumnIdentifier.getInterned("val", false)), Arrays.asList(Int32Type.instance, Int32Type.instance), Int32Type.instance, true, "java", "return state + val;");
UDAggregate aggregate = UDAggregate.create(Collections.singleton(stateFunction), new FunctionName(KEYSPACE, "my_aggregate"), Collections.singletonList(Int32Type.instance), Int32Type.instance, new FunctionName(KEYSPACE, stateFunctionName.split("\\.")[1]), null, Int32Type.instance, null);
Assert.assertTrue(aggregate.toCqlString(true, true).contains("CREATE AGGREGATE IF NOT EXISTS"));
Assert.assertFalse(aggregate.toCqlString(true, false).contains("CREATE AGGREGATE IF NOT EXISTS"));
Assert.assertEquals(aggregate.toCqlString(true, true), aggregate.toCqlString(false, true));
Assert.assertEquals(aggregate.toCqlString(true, false), aggregate.toCqlString(false, false));
}
use of org.apache.cassandra.cql3.functions.UDFunction in project cassandra by apache.
the class UFJavaTest method testUDFToCqlString.
@Test
public void testUDFToCqlString() {
UDFunction function = UDFunction.create(new FunctionName("my_ks", "my_function"), Arrays.asList(ColumnIdentifier.getInterned("column", false)), Arrays.asList(UTF8Type.instance), Int32Type.instance, false, "java", "return 0;");
Assert.assertTrue(function.toCqlString(true, true).contains("CREATE FUNCTION IF NOT EXISTS"));
Assert.assertFalse(function.toCqlString(true, false).contains("CREATE FUNCTION IF NOT EXISTS"));
Assert.assertEquals(function.toCqlString(true, true), function.toCqlString(false, true));
Assert.assertEquals(function.toCqlString(true, false), function.toCqlString(false, false));
}
use of org.apache.cassandra.cql3.functions.UDFunction in project cassandra by apache.
the class UFTest method testBrokenFunction.
@Test
public void testBrokenFunction() throws Throwable {
createTable("CREATE TABLE %s (key int primary key, dval double)");
execute("INSERT INTO %s (key, dval) VALUES (?, ?)", 1, 1d);
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 'throw new RuntimeException();';");
KeyspaceMetadata ksm = Schema.instance.getKeyspaceMetadata(KEYSPACE_PER_TEST);
UDFunction f = (UDFunction) ksm.functions.get(parseFunctionName(fName)).iterator().next();
UDFunction broken = UDFunction.createBrokenFunction(f.name(), f.argNames(), f.argTypes(), f.returnType(), true, "java", f.body(), new InvalidRequestException("foo bar is broken"));
Schema.instance.load(ksm.withSwapped(ksm.functions.without(f.name(), f.argTypes()).with(broken)));
assertInvalidThrowMessage("foo bar is broken", InvalidRequestException.class, "SELECT key, " + fName + "(dval) FROM %s");
}
Aggregations