Search in sources :

Example 1 with AssignmentTestable

use of org.apache.cassandra.cql3.AssignmentTestable 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);
}
Also used : AssignmentTestable(org.apache.cassandra.cql3.AssignmentTestable) ArrayList(java.util.ArrayList) AbstractType(org.apache.cassandra.db.marshal.AbstractType) InvalidRequestException(org.apache.cassandra.exceptions.InvalidRequestException)

Example 2 with AssignmentTestable

use of org.apache.cassandra.cql3.AssignmentTestable in project cassandra by apache.

the class FunctionResolver method validateTypes.

// This method and matchArguments are somewhat duplicate, but this method allows us to provide more precise errors in the common
// case where there is no override for a given function. This is thus probably worth the minor code duplication.
private static void validateTypes(String keyspace, Function fun, List<? extends AssignmentTestable> providedArgs, String receiverKs, String receiverCf) {
    if (providedArgs.size() != fun.argTypes().size())
        throw invalidRequest("Invalid number of arguments in call to function %s: %d required but %d provided", fun.name(), fun.argTypes().size(), providedArgs.size());
    for (int i = 0; i < providedArgs.size(); i++) {
        AssignmentTestable provided = providedArgs.get(i);
        // We'll validate the actually provided value at execution time.
        if (provided == null)
            continue;
        ColumnSpecification expected = makeArgSpec(receiverKs, receiverCf, fun, i);
        if (!provided.testAssignment(keyspace, expected).isAssignable())
            throw invalidRequest("Type error: %s cannot be passed as argument %d of function %s of type %s", provided, i, fun.name(), expected.type.asCQL3Type());
    }
}
Also used : AssignmentTestable(org.apache.cassandra.cql3.AssignmentTestable) ColumnSpecification(org.apache.cassandra.cql3.ColumnSpecification)

Example 3 with AssignmentTestable

use of org.apache.cassandra.cql3.AssignmentTestable in project cassandra by apache.

the class FunctionResolver method matchAguments.

private static AssignmentTestable.TestResult matchAguments(String keyspace, Function fun, List<? extends AssignmentTestable> providedArgs, String receiverKs, String receiverCf) {
    if (providedArgs.size() != fun.argTypes().size())
        return AssignmentTestable.TestResult.NOT_ASSIGNABLE;
    // It's an exact match if all are exact match, but is not assignable as soon as any is non assignable.
    AssignmentTestable.TestResult res = AssignmentTestable.TestResult.EXACT_MATCH;
    for (int i = 0; i < providedArgs.size(); i++) {
        AssignmentTestable provided = providedArgs.get(i);
        if (provided == null) {
            res = AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
            continue;
        }
        ColumnSpecification expected = makeArgSpec(receiverKs, receiverCf, fun, i);
        AssignmentTestable.TestResult argRes = provided.testAssignment(keyspace, expected);
        if (argRes == AssignmentTestable.TestResult.NOT_ASSIGNABLE)
            return AssignmentTestable.TestResult.NOT_ASSIGNABLE;
        if (argRes == AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE)
            res = AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
    }
    return res;
}
Also used : AssignmentTestable(org.apache.cassandra.cql3.AssignmentTestable) ColumnSpecification(org.apache.cassandra.cql3.ColumnSpecification)

Aggregations

AssignmentTestable (org.apache.cassandra.cql3.AssignmentTestable)3 ColumnSpecification (org.apache.cassandra.cql3.ColumnSpecification)2 ArrayList (java.util.ArrayList)1 AbstractType (org.apache.cassandra.db.marshal.AbstractType)1 InvalidRequestException (org.apache.cassandra.exceptions.InvalidRequestException)1