use of org.apache.cassandra.cql3.functions.Function in project cassandra by apache.
the class ModificationStatement method checkAccess.
public void checkAccess(ClientState state) throws InvalidRequestException, UnauthorizedException {
state.hasColumnFamilyAccess(metadata, Permission.MODIFY);
// CAS updates can be used to simulate a SELECT query, so should require Permission.SELECT as well.
if (hasConditions())
state.hasColumnFamilyAccess(metadata, Permission.SELECT);
// MV updates need to get the current state from the table, and might update the views
// Require Permission.SELECT on the base table, and Permission.MODIFY on the views
Iterator<ViewMetadata> views = View.findAll(keyspace(), columnFamily()).iterator();
if (views.hasNext()) {
state.hasColumnFamilyAccess(metadata, Permission.SELECT);
do {
state.hasColumnFamilyAccess(views.next().metadata, Permission.MODIFY);
} while (views.hasNext());
}
for (Function function : getFunctions()) state.ensureHasPermission(Permission.EXECUTE, function);
}
use of org.apache.cassandra.cql3.functions.Function 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.Function in project cassandra by apache.
the class UDFunction method toCqlString.
@Override
public String toCqlString(boolean withInternals, boolean ifNotExists) {
CqlBuilder builder = new CqlBuilder();
builder.append("CREATE FUNCTION ");
if (ifNotExists) {
builder.append("IF NOT EXISTS ");
}
builder.append(name()).append("(");
for (int i = 0, m = argNames().size(); i < m; i++) {
if (i > 0)
builder.append(", ");
builder.append(argNames().get(i)).append(' ').append(toCqlString(argTypes().get(i)));
}
builder.append(')').newLine().increaseIndent().append(isCalledOnNullInput() ? "CALLED" : "RETURNS NULL").append(" ON NULL INPUT").newLine().append("RETURNS ").append(toCqlString(returnType())).newLine().append("LANGUAGE ").append(language()).newLine().append("AS $$").append(body()).append("$$;");
return builder.toString();
}
use of org.apache.cassandra.cql3.functions.Function 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());
}
}
use of org.apache.cassandra.cql3.functions.Function in project cassandra by apache.
the class StorageService method restoreReplicaCount.
/**
* Called when an endpoint is removed from the ring. This function checks
* whether this node becomes responsible for new ranges as a
* consequence and streams data if needed.
*
* This is rather ineffective, but it does not matter so much
* since this is called very seldom
*
* @param endpoint the node that left
*/
private void restoreReplicaCount(InetAddressAndPort endpoint, final InetAddressAndPort notifyEndpoint) {
Map<String, Multimap<InetAddressAndPort, FetchReplica>> replicasToFetch = new HashMap<>();
InetAddressAndPort myAddress = FBUtilities.getBroadcastAddressAndPort();
for (String keyspaceName : Schema.instance.getNonLocalStrategyKeyspaces()) {
logger.debug("Restoring replica count for keyspace {}", keyspaceName);
EndpointsByReplica changedReplicas = getChangedReplicasForLeaving(keyspaceName, endpoint, tokenMetadata, Keyspace.open(keyspaceName).getReplicationStrategy());
Set<LeavingReplica> myNewReplicas = new HashSet<>();
for (Map.Entry<Replica, Replica> entry : changedReplicas.flattenEntries()) {
Replica replica = entry.getValue();
if (replica.endpoint().equals(myAddress)) {
// Maybe we don't technically need to fetch transient data from somewhere
// but it's probably not a lot and it probably makes things a hair more resilient to people
// not running repair when they should.
myNewReplicas.add(new LeavingReplica(entry.getKey(), entry.getValue()));
}
}
logger.debug("Changed replicas for leaving {}, myNewReplicas {}", changedReplicas, myNewReplicas);
replicasToFetch.put(keyspaceName, getNewSourceReplicas(keyspaceName, myNewReplicas));
}
StreamPlan stream = new StreamPlan(StreamOperation.RESTORE_REPLICA_COUNT);
replicasToFetch.forEach((keyspaceName, sources) -> {
logger.debug("Requesting keyspace {} sources", keyspaceName);
sources.asMap().forEach((sourceAddress, fetchReplicas) -> {
logger.debug("Source and our replicas are {}", fetchReplicas);
// Remember whether this node is providing the full or transient replicas for this range. We are going
// to pass streaming the local instance of Replica for the range which doesn't tell us anything about the source
// By encoding it as two separate sets we retain this information about the source.
RangesAtEndpoint full = fetchReplicas.stream().filter(f -> f.remote.isFull()).map(f -> f.local).collect(RangesAtEndpoint.collector(myAddress));
RangesAtEndpoint transientReplicas = fetchReplicas.stream().filter(f -> f.remote.isTransient()).map(f -> f.local).collect(RangesAtEndpoint.collector(myAddress));
if (logger.isDebugEnabled())
logger.debug("Requesting from {} full replicas {} transient replicas {}", sourceAddress, StringUtils.join(full, ", "), StringUtils.join(transientReplicas, ", "));
stream.requestRanges(sourceAddress, keyspaceName, full, transientReplicas);
});
});
StreamResultFuture future = stream.execute();
future.addCallback(new FutureCallback<StreamState>() {
public void onSuccess(StreamState finalState) {
sendReplicationNotification(notifyEndpoint);
}
public void onFailure(Throwable t) {
logger.warn("Streaming to restore replica count failed", t);
// We still want to send the notification
sendReplicationNotification(notifyEndpoint);
}
});
}
Aggregations