protected SqlScalarFunction(Signature signature) { this.signature = requireNonNull(signature, "signature is null"); checkArgument(signature.getKind() == SCALAR, "function kind must be SCALAR"); }
private static String getFunctionType(SqlFunction function) { FunctionKind kind = function.getSignature().getKind(); switch (kind) { case AGGREGATE: return "aggregate"; case WINDOW: return "window"; case SCALAR: return "scalar"; } throw new IllegalArgumentException("Unsupported function kind: " + kind); }
public WindowFunctionSupplier getWindowFunctionImplementation(Signature signature) { checkArgument(signature.getKind() == WINDOW || signature.getKind() == AGGREGATE, "%s is not a window function", signature); checkArgument(signature.getTypeVariableConstraints().isEmpty(), "%s has unbound type parameters", signature); try { return specializedWindowCache.getUnchecked(getSpecializedFunctionKey(signature)); } catch (UncheckedExecutionException e) { throwIfInstanceOf(e.getCause(), PrestoException.class); throw e; } }
public boolean isAggregationFunction(QualifiedName name) { return Iterables.any(functions.get(name), function -> function.getSignature().getKind() == AGGREGATE); }
public InternalAggregationFunction getAggregateFunctionImplementation(Signature signature) { checkArgument(signature.getKind() == AGGREGATE, "%s is not an aggregate function", signature); checkArgument(signature.getTypeVariableConstraints().isEmpty(), "%s has unbound type parameters", signature); try { return specializedAggregationCache.getUnchecked(getSpecializedFunctionKey(signature)); } catch (UncheckedExecutionException e) { throwIfInstanceOf(e.getCause(), PrestoException.class); throw e; } }
public ScalarFunctionImplementation getScalarFunctionImplementation(Signature signature) { checkArgument(signature.getKind() == SCALAR, "%s is not a scalar function", signature); checkArgument(signature.getTypeVariableConstraints().isEmpty(), "%s has unbound type parameters", signature); try { return specializedScalarCache.getUnchecked(getSpecializedFunctionKey(signature)); } catch (UncheckedExecutionException e) { throwIfInstanceOf(e.getCause(), PrestoException.class); throw e; } }
public FunctionMap(FunctionMap map, Iterable<? extends SqlFunction> functions) { this.functions = ImmutableListMultimap.<QualifiedName, SqlFunction>builder() .putAll(map.functions) .putAll(Multimaps.index(functions, function -> QualifiedName.of(function.getSignature().getName()))) .build(); // Make sure all functions with the same name are aggregations or none of them are for (Map.Entry<QualifiedName, Collection<SqlFunction>> entry : this.functions.asMap().entrySet()) { Collection<SqlFunction> values = entry.getValue(); long aggregations = values.stream() .map(function -> function.getSignature().getKind()) .filter(kind -> kind == AGGREGATE) .count(); checkState(aggregations == 0 || aggregations == values.size(), "'%s' is both an aggregation and a scalar function", entry.getKey()); } }
@Override protected Void visitFunctionCall(FunctionCall functionCall, Analysis analysis) { requireNonNull(analysis, "analysis is null"); Signature signature = analysis.getFunctionSignature(functionCall); if (signature != null && signature.getKind() == WINDOW && !functionCall.getWindow().isPresent()) { throw new SemanticException(WINDOW_REQUIRES_OVER, functionCall, "Window function %s requires an OVER clause", signature.getName()); } return super.visitFunctionCall(functionCall, analysis); } }
private boolean returnsNullOnGivenInputTypes(ApplicableFunction applicableFunction, List<Type> parameterTypes) { Signature boundSignature = applicableFunction.getBoundSignature(); FunctionKind functionKind = boundSignature.getKind(); // Window and Aggregation functions have fixed semantic where NULL values are always skipped if (functionKind != SCALAR) { return true; } for (int i = 0; i < parameterTypes.size(); i++) { Type parameterType = parameterTypes.get(i); if (parameterType.equals(UNKNOWN)) { // TODO: Move information about nullable arguments to FunctionSignature. Remove this hack. ScalarFunctionImplementation implementation = getScalarFunctionImplementation(boundSignature); if (implementation.getArgumentProperty(i).getNullConvention() != RETURN_NULL_ON_NULL) { return false; } } } return true; }
public static Signature applyBoundVariables(Signature signature, BoundVariables boundVariables, int arity) { List<TypeSignature> argumentSignatures; if (signature.isVariableArity()) { argumentSignatures = expandVarargFormalTypeSignature(signature.getArgumentTypes(), arity); } else { checkArgument(signature.getArgumentTypes().size() == arity); argumentSignatures = signature.getArgumentTypes(); } List<TypeSignature> boundArgumentSignatures = applyBoundVariables(argumentSignatures, boundVariables); TypeSignature boundReturnTypeSignature = applyBoundVariables(signature.getReturnType(), boundVariables); return new Signature( signature.getName(), signature.getKind(), ImmutableList.of(), ImmutableList.of(), boundReturnTypeSignature, boundArgumentSignatures, false); }
FunctionKind kind = metadata.getFunctionRegistry().resolveFunction(windowFunction.getName(), fromTypeSignatures(argumentTypes)).getKind(); if (kind != AGGREGATE && kind != WINDOW) { throw new SemanticException(MUST_BE_WINDOW_FUNCTION, node, "Not a window function: %s", windowFunction.getName());
@Test public void testSerializationRoundTrip() { ObjectMapperProvider objectMapperProvider = new ObjectMapperProvider(); objectMapperProvider.setJsonDeserializers(ImmutableMap.of(Type.class, new TypeDeserializer(new TypeRegistry()))); JsonCodec<Signature> codec = new JsonCodecFactory(objectMapperProvider, true).jsonCodec(Signature.class); Signature expected = new Signature( "function", SCALAR, parseTypeSignature(StandardTypes.BIGINT), ImmutableList.of(parseTypeSignature(StandardTypes.BOOLEAN), parseTypeSignature(StandardTypes.DOUBLE), parseTypeSignature(StandardTypes.VARCHAR))); String json = codec.toJson(expected); Signature actual = codec.fromJson(json); assertEquals(actual.getName(), expected.getName()); assertEquals(actual.getKind(), expected.getKind()); assertEquals(actual.getReturnType(), expected.getReturnType()); assertEquals(actual.getArgumentTypes(), expected.getArgumentTypes()); } }
private static String getFunctionType(SqlFunction function) { FunctionKind kind = function.getSignature().getKind(); switch (kind) { case AGGREGATE: case APPROXIMATE_AGGREGATE: return "aggregate"; case WINDOW: return "window"; case SCALAR: return "scalar"; } throw new IllegalArgumentException("Unsupported function kind: " + kind); }
public FunctionMap(FunctionMap map, Iterable<? extends SqlFunction> functions) { this.functions = ImmutableListMultimap.<QualifiedName, SqlFunction>builder() .putAll(map.functions) .putAll(Multimaps.index(functions, function -> QualifiedName.of(function.getSignature().getName()))) .build(); // Make sure all functions with the same name are aggregations or none of them are for (Map.Entry<QualifiedName, Collection<SqlFunction>> entry : this.functions.asMap().entrySet()) { Collection<SqlFunction> values = entry.getValue(); long aggregations = values.stream() .map(function -> function.getSignature().getKind()) .filter(kind -> kind == AGGREGATE || kind == APPROXIMATE_AGGREGATE) .count(); checkState(aggregations == 0 || aggregations == values.size(), "'%s' is both an aggregation and a scalar function", entry.getKey()); } }
@Override protected Void visitFunctionCall(FunctionCall functionCall, Analysis analysis) { requireNonNull(analysis, "analysis is null"); Signature signature = analysis.getFunctionSignature(functionCall); if (signature != null && signature.getKind() == WINDOW && !functionCall.getWindow().isPresent()) { throw new SemanticException(WINDOW_REQUIRES_OVER, functionCall, "Window function %s requires an OVER clause", signature.getName()); } return super.visitFunctionCall(functionCall, analysis); } }
public static Signature bindSignature(Signature signature, Map<String, Type> boundParameters, int arity) { checkArgument((signature.isVariableArity() && arity >= signature.getArgumentTypes().size() - 1) || arity == signature.getArgumentTypes().size(), "Illegal arity %d for function %s", arity, signature); List<TypeSignature> argumentTypes = signature.getArgumentTypes(); ImmutableList.Builder<TypeSignature> boundArguments = ImmutableList.builder(); for (int i = 0; i < argumentTypes.size() - 1; i++) { boundArguments.add(argumentTypes.get(i).bindParameters(boundParameters)); } if (!argumentTypes.isEmpty()) { TypeSignature lastArgument = argumentTypes.get(argumentTypes.size() - 1).bindParameters(boundParameters); if (signature.isVariableArity()) { for (int i = 0; i < arity - (argumentTypes.size() - 1); i++) { boundArguments.add(lastArgument); } } else { boundArguments.add(lastArgument); } } return new Signature(signature.getName(), signature.getKind(), signature.getReturnType().bindParameters(boundParameters), boundArguments.build()); }
public InternalAggregationFunction getAggregateFunctionImplementation(Signature signature) { checkArgument(signature.getKind() == AGGREGATE || signature.getKind() == APPROXIMATE_AGGREGATE, "%s is not an aggregate function", signature); checkArgument(signature.getTypeParameterRequirements().isEmpty(), "%s has unbound type parameters", signature); Iterable<SqlFunction> candidates = functions.get(QualifiedName.of(signature.getName())); // search for exact match for (SqlFunction operator : candidates) { Type returnType = typeManager.getType(signature.getReturnType()); List<Type> argumentTypes = resolveTypes(signature.getArgumentTypes(), typeManager); Map<String, Type> boundTypeParameters = operator.getSignature().bindTypeParameters(returnType, argumentTypes, false, typeManager); if (boundTypeParameters != null) { try { return specializedAggregationCache.getUnchecked(new SpecializedFunctionKey(operator, boundTypeParameters, signature.getArgumentTypes().size())); } catch (UncheckedExecutionException e) { throw Throwables.propagate(e.getCause()); } } } throw new PrestoException(FUNCTION_IMPLEMENTATION_MISSING, format("%s not found", signature)); }
public WindowFunctionSupplier getWindowFunctionImplementation(Signature signature) { checkArgument(signature.getKind() == WINDOW || signature.getKind() == AGGREGATE, "%s is not a window function", signature); checkArgument(signature.getTypeParameterRequirements().isEmpty(), "%s has unbound type parameters", signature); Iterable<SqlFunction> candidates = functions.get(QualifiedName.of(signature.getName())); // search for exact match for (SqlFunction operator : candidates) { Type returnType = typeManager.getType(signature.getReturnType()); List<Type> argumentTypes = resolveTypes(signature.getArgumentTypes(), typeManager); Map<String, Type> boundTypeParameters = operator.getSignature().bindTypeParameters(returnType, argumentTypes, false, typeManager); if (boundTypeParameters != null) { try { return specializedWindowCache.getUnchecked(new SpecializedFunctionKey(operator, boundTypeParameters, signature.getArgumentTypes().size())); } catch (UncheckedExecutionException e) { throw Throwables.propagate(e.getCause()); } } } throw new PrestoException(FUNCTION_IMPLEMENTATION_MISSING, format("%s not found", signature)); }
@Test public void testRoundTrip() { ObjectMapperProvider objectMapperProvider = new ObjectMapperProvider(); objectMapperProvider.setJsonDeserializers(ImmutableMap.<Class<?>, JsonDeserializer<?>>of(Type.class, new TypeDeserializer(new TypeRegistry()))); JsonCodec<Signature> codec = new JsonCodecFactory(objectMapperProvider, true).jsonCodec(Signature.class); Signature expected = new Signature("function", SCALAR, StandardTypes.BIGINT, ImmutableList.of(StandardTypes.BOOLEAN, StandardTypes.DOUBLE, StandardTypes.VARCHAR)); String json = codec.toJson(expected); Signature actual = codec.fromJson(json); assertEquals(actual.getName(), expected.getName()); assertEquals(actual.getKind(), expected.getKind()); assertEquals(actual.getReturnType(), expected.getReturnType()); assertEquals(actual.getArgumentTypes(), expected.getArgumentTypes()); }