Search in sources :

Example 6 with UDFunction

use of org.apache.cassandra.cql3.functions.UDFunction in project cassandra by apache.

the class CreateAggregateStatement method apply.

public Keyspaces apply(Keyspaces schema) {
    if (ifNotExists && orReplace)
        throw ire("Cannot use both 'OR REPLACE' and 'IF NOT EXISTS' directives");
    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 (!rawStateType.isTuple() && rawStateType.isFrozen())
        throw ire("State type '%s' cannot be frozen; remove frozen<> modifier from '%s'", rawStateType, rawStateType);
    KeyspaceMetadata keyspace = schema.getNullable(keyspaceName);
    if (null == keyspace)
        throw ire("Keyspace '%s' doesn't exist", keyspaceName);
    /*
         * Resolve the state function
         */
    List<AbstractType<?>> argumentTypes = rawArgumentTypes.stream().map(t -> t.prepare(keyspaceName, keyspace.types).getType()).collect(toList());
    AbstractType<?> stateType = rawStateType.prepare(keyspaceName, keyspace.types).getType();
    List<AbstractType<?>> stateFunctionArguments = Lists.newArrayList(concat(singleton(stateType), argumentTypes));
    Function stateFunction = keyspace.functions.find(stateFunctionName, stateFunctionArguments).orElseThrow(() -> ire("State function %s doesn't exist", stateFunctionString()));
    if (stateFunction.isAggregate())
        throw ire("State function %s isn't a scalar function", stateFunctionString());
    if (!stateFunction.returnType().equals(stateType)) {
        throw ire("State function %s return type must be the same as the first argument type - check STYPE, argument and return types", stateFunctionString());
    }
    /*
         * Resolve the final function and return type
         */
    Function finalFunction = null;
    AbstractType<?> returnType = stateFunction.returnType();
    if (null != finalFunctionName) {
        finalFunction = keyspace.functions.find(finalFunctionName, singletonList(stateType)).orElse(null);
        if (null == finalFunction)
            throw ire("Final function %s doesn't exist", finalFunctionString());
        if (finalFunction.isAggregate())
            throw ire("Final function %s isn't a scalar function", finalFunctionString());
        // override return type with that of the final function
        returnType = finalFunction.returnType();
    }
    /*
         * Validate initial condition
         */
    ByteBuffer initialValue = null;
    if (null != rawInitialValue) {
        initialValue = Terms.asBytes(keyspaceName, rawInitialValue.toString(), stateType);
        if (null != initialValue) {
            try {
                stateType.validate(initialValue);
            } catch (MarshalException e) {
                throw ire("Invalid value for INITCOND of type %s", stateType.asCQL3Type());
            }
        }
        // Converts initcond to a CQL literal and parse it back to avoid another CASSANDRA-11064
        String initialValueString = stateType.asCQL3Type().toCQLLiteral(initialValue, ProtocolVersion.CURRENT);
        assert Objects.equal(initialValue, Terms.asBytes(keyspaceName, initialValueString, stateType));
        if (Constants.NULL_LITERAL != rawInitialValue && UDHelper.isNullOrEmpty(stateType, initialValue))
            throw ire("INITCOND must not be empty for all types except TEXT, ASCII, BLOB");
    }
    if (!((UDFunction) stateFunction).isCalledOnNullInput() && null == initialValue) {
        throw ire("Cannot create aggregate '%s' without INITCOND because state function %s does not accept 'null' arguments", aggregateName, stateFunctionName);
    }
    /*
         * Create or replace
         */
    UDAggregate aggregate = new UDAggregate(new FunctionName(keyspaceName, aggregateName), argumentTypes, returnType, (ScalarFunction) stateFunction, (ScalarFunction) finalFunction, initialValue);
    Function existingAggregate = keyspace.functions.find(aggregate.name(), argumentTypes).orElse(null);
    if (null != existingAggregate) {
        if (!existingAggregate.isAggregate())
            throw ire("Aggregate '%s' cannot replace a function", aggregateName);
        if (ifNotExists)
            return schema;
        if (!orReplace)
            throw ire("Aggregate '%s' already exists", aggregateName);
        if (!returnType.isCompatibleWith(existingAggregate.returnType())) {
            throw ire("Cannot replace aggregate '%s', the new return type %s isn't compatible with the return type %s of existing function", aggregateName, returnType.asCQL3Type(), existingAggregate.returnType().asCQL3Type());
        }
    }
    return schema.withAddedOrUpdated(keyspace.withSwapped(keyspace.functions.withAddedOrUpdated(aggregate)));
}
Also used : AuditLogContext(org.apache.cassandra.audit.AuditLogContext) Change(org.apache.cassandra.transport.Event.SchemaChange.Change) FunctionResource(org.apache.cassandra.auth.FunctionResource) Iterables.transform(com.google.common.collect.Iterables.transform) Permission(org.apache.cassandra.auth.Permission) IResource(org.apache.cassandra.auth.IResource) AbstractType(org.apache.cassandra.db.marshal.AbstractType) ByteBuffer(java.nio.ByteBuffer) org.apache.cassandra.cql3(org.apache.cassandra.cql3) Schema(org.apache.cassandra.schema.Schema) Collections.singletonList(java.util.Collections.singletonList) Lists(com.google.common.collect.Lists) String.join(java.lang.String.join) Collections.singleton(java.util.Collections.singleton) Iterables.concat(com.google.common.collect.Iterables.concat) ProtocolVersion(org.apache.cassandra.transport.ProtocolVersion) org.apache.cassandra.cql3.functions(org.apache.cassandra.cql3.functions) FunctionsDiff(org.apache.cassandra.schema.Functions.FunctionsDiff) Objects(com.google.common.base.Objects) KeyspacesDiff(org.apache.cassandra.schema.Keyspaces.KeyspacesDiff) ImmutableSet(com.google.common.collect.ImmutableSet) Keyspaces(org.apache.cassandra.schema.Keyspaces) SchemaChange(org.apache.cassandra.transport.Event.SchemaChange) ClientState(org.apache.cassandra.service.ClientState) Set(java.util.Set) String.format(java.lang.String.format) AuditLogEntryType(org.apache.cassandra.audit.AuditLogEntryType) List(java.util.List) Collectors.toList(java.util.stream.Collectors.toList) Target(org.apache.cassandra.transport.Event.SchemaChange.Target) KeyspaceMetadata(org.apache.cassandra.schema.KeyspaceMetadata) MarshalException(org.apache.cassandra.serializers.MarshalException) MarshalException(org.apache.cassandra.serializers.MarshalException) AbstractType(org.apache.cassandra.db.marshal.AbstractType) KeyspaceMetadata(org.apache.cassandra.schema.KeyspaceMetadata) ByteBuffer(java.nio.ByteBuffer)

Aggregations

UDFunction (org.apache.cassandra.cql3.functions.UDFunction)4 Collectors.toList (java.util.stream.Collectors.toList)3 FunctionName (org.apache.cassandra.cql3.functions.FunctionName)3 KeyspaceMetadata (org.apache.cassandra.schema.KeyspaceMetadata)3 KeyspacesDiff (org.apache.cassandra.schema.Keyspaces.KeyspacesDiff)3 Test (org.junit.Test)3 ImmutableSet (com.google.common.collect.ImmutableSet)2 Lists (com.google.common.collect.Lists)2 String.format (java.lang.String.format)2 ByteBuffer (java.nio.ByteBuffer)2 List (java.util.List)2 Set (java.util.Set)2 AuditLogContext (org.apache.cassandra.audit.AuditLogContext)2 AuditLogEntryType (org.apache.cassandra.audit.AuditLogEntryType)2 org.apache.cassandra.cql3 (org.apache.cassandra.cql3)2 org.apache.cassandra.cql3.functions (org.apache.cassandra.cql3.functions)2 InvalidRequestException (org.apache.cassandra.exceptions.InvalidRequestException)2 VisibleForTesting (com.google.common.annotations.VisibleForTesting)1 Objects (com.google.common.base.Objects)1 com.google.common.collect (com.google.common.collect)1