use of org.apache.cassandra.cql3.functions.FunctionName in project cassandra by apache.
the class SchemaKeyspace method createUDAFromRow.
private static UDAggregate createUDAFromRow(UntypedResultSet.Row row, Functions 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;
try {
return UDAggregate.create(functions, name, argTypes, returnType, stateFunc, finalFunc, stateType, initcond);
} catch (InvalidRequestException reason) {
return UDAggregate.createBroken(name, argTypes, returnType, initcond, reason);
}
}
use of org.apache.cassandra.cql3.functions.FunctionName in project cassandra by apache.
the class FunctionResolver method get.
/**
* @param keyspace the current keyspace
* @param name the name of the function
* @param providedArgs the arguments provided for the function call
* @param receiverKs the receiver's keyspace
* @param receiverCf the receiver's table
* @param receiverType if the receiver type is known (during inserts, for example), this should be the type of
* the receiver
* @throws InvalidRequestException
*/
public static Function get(String keyspace, FunctionName name, List<? extends AssignmentTestable> providedArgs, String receiverKs, String receiverCf, AbstractType<?> receiverType) throws InvalidRequestException {
if (name.equalsNativeFunction(TOKEN_FUNCTION_NAME))
return new TokenFct(Schema.instance.getTableMetadata(receiverKs, receiverCf));
// due to needing to know the argument types in advance).
if (name.equalsNativeFunction(ToJsonFct.NAME))
throw new InvalidRequestException("toJson() may only be used within the selection clause of SELECT statements");
// Similarly, we can only use fromJson when we know the receiver type (such as inserts)
if (name.equalsNativeFunction(FromJsonFct.NAME)) {
if (receiverType == null)
throw new InvalidRequestException("fromJson() cannot be used in the selection clause of a SELECT statement");
return FromJsonFct.getInstance(receiverType);
}
Collection<Function> candidates;
if (!name.hasKeyspace()) {
// function name not fully qualified
candidates = new ArrayList<>();
// add 'SYSTEM' (native) candidates
candidates.addAll(Schema.instance.getFunctions(name.asNativeFunction()));
// add 'current keyspace' candidates
candidates.addAll(Schema.instance.getFunctions(new FunctionName(keyspace, name.name)));
} else {
// function name is fully qualified (keyspace + name)
candidates = Schema.instance.getFunctions(name);
}
if (candidates.isEmpty())
return null;
// Fast path if there is only one choice
if (candidates.size() == 1) {
Function fun = candidates.iterator().next();
validateTypes(keyspace, fun, providedArgs, receiverKs, receiverCf);
return fun;
}
List<Function> compatibles = null;
for (Function toTest : candidates) {
if (matchReturnType(toTest, receiverType)) {
AssignmentTestable.TestResult r = matchAguments(keyspace, toTest, providedArgs, receiverKs, receiverCf);
switch(r) {
case EXACT_MATCH:
// We always favor exact matches
return toTest;
case WEAKLY_ASSIGNABLE:
if (compatibles == null)
compatibles = new ArrayList<>();
compatibles.add(toTest);
break;
}
}
}
if (compatibles == null) {
if (OperationFcts.isOperation(name))
throw invalidRequest("the '%s' operation is not supported between %s and %s", OperationFcts.getOperator(name), providedArgs.get(0), providedArgs.get(1));
throw invalidRequest("Invalid call to function %s, none of its type signatures match (known type signatures: %s)", name, format(candidates));
}
if (compatibles.size() > 1) {
if (OperationFcts.isOperation(name)) {
if (receiverType != null && !containsMarkers(providedArgs)) {
for (Function toTest : compatibles) {
List<AbstractType<?>> argTypes = toTest.argTypes();
if (receiverType.equals(argTypes.get(0)) && receiverType.equals(argTypes.get(1)))
return toTest;
}
}
throw invalidRequest("Ambiguous '%s' operation: use type casts to disambiguate", OperationFcts.getOperator(name), providedArgs.get(0), providedArgs.get(1));
}
if (OperationFcts.isNegation(name))
throw invalidRequest("Ambiguous negation: use type casts to disambiguate");
throw invalidRequest("Ambiguous call to function %s (can be matched by following signatures: %s): use type casts to disambiguate", name, format(compatibles));
}
return compatibles.get(0);
}
use of org.apache.cassandra.cql3.functions.FunctionName in project cassandra by apache.
the class UFJavaTest method testJavaFunction.
@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)));
}
use of org.apache.cassandra.cql3.functions.FunctionName in project cassandra by apache.
the class UFScriptTest method testJavascriptFunction.
@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)));
}
use of org.apache.cassandra.cql3.functions.FunctionName in project cassandra by apache.
the class UFTest method testFunctionDropPreparedStatement.
@Test
public void testFunctionDropPreparedStatement() throws Throwable {
createTable("CREATE TABLE %s (key int PRIMARY KEY, d double)");
String fSin = createFunction(KEYSPACE_PER_TEST, "double", "CREATE FUNCTION %s ( input double ) " + "CALLED ON NULL INPUT " + "RETURNS double " + "LANGUAGE java " + "AS 'return Double.valueOf(Math.sin(input.doubleValue()));'");
FunctionName fSinName = parseFunctionName(fSin);
Assert.assertEquals(1, Schema.instance.getFunctions(parseFunctionName(fSin)).size());
// create a pairs of Select and Inserts. One statement in each pair uses the function so when we
// drop it those statements should be removed from the cache in QueryProcessor. The other statements
// should be unaffected.
ResultMessage.Prepared preparedSelect1 = QueryProcessor.prepare(String.format("SELECT key, %s(d) FROM %s.%s", fSin, KEYSPACE, currentTable()), ClientState.forInternalCalls());
ResultMessage.Prepared preparedSelect2 = QueryProcessor.prepare(String.format("SELECT key FROM %s.%s", KEYSPACE, currentTable()), ClientState.forInternalCalls());
ResultMessage.Prepared preparedInsert1 = QueryProcessor.prepare(String.format("INSERT INTO %s.%s (key, d) VALUES (?, %s(?))", KEYSPACE, currentTable(), fSin), ClientState.forInternalCalls());
ResultMessage.Prepared preparedInsert2 = QueryProcessor.prepare(String.format("INSERT INTO %s.%s (key, d) VALUES (?, ?)", KEYSPACE, currentTable()), ClientState.forInternalCalls());
Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedSelect1.statementId));
Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedSelect2.statementId));
Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedInsert1.statementId));
Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedInsert2.statementId));
execute("DROP FUNCTION " + fSin + "(double);");
// the statements which use the dropped function should be removed from cache, with the others remaining
Assert.assertNull(QueryProcessor.instance.getPrepared(preparedSelect1.statementId));
Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedSelect2.statementId));
Assert.assertNull(QueryProcessor.instance.getPrepared(preparedInsert1.statementId));
Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedInsert2.statementId));
execute("CREATE FUNCTION " + fSin + " ( input double ) " + "RETURNS NULL ON NULL INPUT " + "RETURNS double " + "LANGUAGE java " + "AS 'return Double.valueOf(Math.sin(input));'");
Assert.assertEquals(1, Schema.instance.getFunctions(fSinName).size());
preparedSelect1 = QueryProcessor.prepare(String.format("SELECT key, %s(d) FROM %s.%s", fSin, KEYSPACE, currentTable()), ClientState.forInternalCalls());
preparedInsert1 = QueryProcessor.prepare(String.format("INSERT INTO %s.%s (key, d) VALUES (?, %s(?))", KEYSPACE, currentTable(), fSin), ClientState.forInternalCalls());
Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedSelect1.statementId));
Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedInsert1.statementId));
dropPerTestKeyspace();
// again, only the 2 statements referencing the function should be removed from cache
// this time because the statements select from tables in KEYSPACE, only the function
// is scoped to KEYSPACE_PER_TEST
Assert.assertNull(QueryProcessor.instance.getPrepared(preparedSelect1.statementId));
Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedSelect2.statementId));
Assert.assertNull(QueryProcessor.instance.getPrepared(preparedInsert1.statementId));
Assert.assertNotNull(QueryProcessor.instance.getPrepared(preparedInsert2.statementId));
}
Aggregations