use of org.apache.cassandra.cql3.functions.Function 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.Function in project cassandra by apache.
the class Terms method ofListMarker.
/**
* Creates a {@code Terms} for the specified list marker.
*
* @param marker the list marker
* @param type the element type
* @return a {@code Terms} for the specified list marker
*/
public static Terms ofListMarker(final Lists.Marker marker, final AbstractType<?> type) {
return new Terms() {
@Override
public void addFunctionsTo(List<Function> functions) {
}
@Override
public void collectMarkerSpecification(VariableSpecifications boundNames) {
marker.collectMarkerSpecification(boundNames);
}
@Override
public List<ByteBuffer> bindAndGet(QueryOptions options) {
Terminal terminal = marker.bind(options);
if (terminal == null)
return null;
if (terminal == Constants.UNSET_VALUE)
return UNSET_LIST;
return ((MultiItemTerminal) terminal).getElements();
}
@Override
public List<Terminal> bind(QueryOptions options) {
Terminal terminal = marker.bind(options);
if (terminal == null)
return null;
if (terminal == Constants.UNSET_VALUE)
return UNSET_LIST;
java.util.function.Function<ByteBuffer, Term.Terminal> deserializer = deserializer(options.getProtocolVersion());
List<ByteBuffer> boundValues = ((MultiItemTerminal) terminal).getElements();
List<Term.Terminal> values = new ArrayList<>(boundValues.size());
for (int i = 0, m = boundValues.size(); i < m; i++) {
ByteBuffer buffer = boundValues.get(i);
Term.Terminal value = buffer == null ? null : deserializer.apply(buffer);
values.add(value);
}
return values;
}
public java.util.function.Function<ByteBuffer, Term.Terminal> deserializer(ProtocolVersion version) {
if (type.isCollection()) {
switch(((CollectionType<?>) type).kind) {
case LIST:
return e -> Lists.Value.fromSerialized(e, (ListType<?>) type, version);
case SET:
return e -> Sets.Value.fromSerialized(e, (SetType<?>) type, version);
case MAP:
return e -> Maps.Value.fromSerialized(e, (MapType<?, ?>) type, version);
}
throw new AssertionError();
}
return e -> new Constants.Value(e);
}
};
}
use of org.apache.cassandra.cql3.functions.Function in project cassandra by apache.
the class UFIdentificationTest method assertFunctions.
private void assertFunctions(String cql, String... function) {
CQLStatement stmt = QueryProcessor.getStatement(cql, ClientState.forInternalCalls());
assertFunctions(stmt, function);
}
use of org.apache.cassandra.cql3.functions.Function in project cassandra by apache.
the class UFJavaTest method testJavaKeyspaceFunction.
@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)));
}
use of org.apache.cassandra.cql3.functions.Function 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));
}
Aggregations