@Override public String toString() { return signature.getName() + "(" + Joiner.on(", ").join(arguments) + ")"; }
public static BytecodeExpression invoke(Binding binding, Signature signature) { return invoke(binding, signature.getName()); }
@Override public final WindowFunction createWindowFunction(List<Integer> argumentChannels) { requireNonNull(argumentChannels, "inputs is null"); checkArgument(argumentChannels.size() == signature.getArgumentTypes().size(), "Expected %s arguments for function %s, but got %s", signature.getArgumentTypes().size(), signature.getName(), argumentChannels.size()); return newWindowFunction(argumentChannels); }
public static List<RowExpression> flattenNestedCallArgs(CallExpression call) { String callName = call.getSignature().getName(); ImmutableList.Builder<RowExpression> newArguments = ImmutableList.builder(); for (RowExpression argument : call.getArguments()) { if (argument instanceof CallExpression && callName.equals(((CallExpression) argument).getSignature().getName())) { // same call type, so flatten the args newArguments.addAll(flattenNestedCallArgs((CallExpression) argument)); } else { newArguments.add(argument); } } return newArguments.build(); }
private static boolean isOperator(Signature signature) { for (OperatorType operator : OperatorType.values()) { if (signature.getName().equals(FunctionRegistry.mangleOperatorName(operator))) { return true; } } return false; }
@VisibleForTesting public List<SqlFunction> listOperators() { Set<String> operatorNames = Arrays.asList(OperatorType.values()).stream() .map(FunctionRegistry::mangleOperatorName) .collect(toImmutableSet()); return functions.list().stream() .filter(function -> operatorNames.contains(function.getSignature().getName())) .collect(toImmutableList()); }
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 static boolean isCountOverConstant(AggregationNode.Aggregation aggregation, Assignments inputs) { Signature signature = aggregation.getSignature(); if (!signature.getName().equals("count") || signature.getArgumentTypes().size() != 1) { return false; } Expression argument = aggregation.getCall().getArguments().get(0); if (argument instanceof SymbolReference) { argument = inputs.get(Symbol.from(argument)); } return argument instanceof Literal && !(argument instanceof NullLiteral); } }
@Override public ScalarFunctionImplementation specialize(BoundVariables boundVariables, int arity, TypeManager typeManager, FunctionRegistry functionRegistry) { Type type = boundVariables.getTypeVariable("E"); checkArgument(type.isOrderable(), "Type must be orderable"); MethodHandle compareMethod = functionRegistry.getScalarFunctionImplementation(internalOperator(operatorType, BOOLEAN, ImmutableList.of(type, type))).getMethodHandle(); List<Class<?>> javaTypes = IntStream.range(0, arity) .mapToObj(i -> type.getJavaType()) .collect(toImmutableList()); Class<?> clazz = generate(javaTypes, type, compareMethod); MethodHandle methodHandle = methodHandle(clazz, getSignature().getName(), javaTypes.toArray(new Class<?>[javaTypes.size()])); return new ScalarFunctionImplementation( false, nCopies(javaTypes.size(), valueTypeArgumentProperty(RETURN_NULL_ON_NULL)), methodHandle, isDeterministic()); }
@Override public BytecodeNode generateExpression(Signature signature, BytecodeGeneratorContext generatorContext, Type returnType, List<RowExpression> arguments, Optional<Variable> outputBlockVariable) { RowExpression argument = arguments.get(0); Signature function = generatorContext .getRegistry() .getCoercion(argument.getType(), returnType); BytecodeBlock block = new BytecodeBlock() .append(generatorContext.generateCall( function.getName(), generatorContext.getRegistry().getScalarFunctionImplementation(function), ImmutableList.of(generatorContext.generate(argument, Optional.empty())))); outputBlockVariable.ifPresent(output -> block.append(generateWrite(generatorContext, returnType, output))); return block; } }
@Test public void testListingHiddenFunctions() { TypeRegistry typeManager = new TypeRegistry(); FunctionRegistry registry = new FunctionRegistry(typeManager, new BlockEncodingManager(typeManager), new FeaturesConfig()); List<SqlFunction> functions = registry.list(); List<String> names = transform(functions, input -> input.getSignature().getName()); assertTrue(names.contains("length"), "Expected function names " + names + " to contain 'length'"); assertTrue(names.contains("stddev"), "Expected function names " + names + " to contain 'stddev'"); assertTrue(names.contains("rank"), "Expected function names " + names + " to contain 'rank'"); assertFalse(names.contains("like"), "Expected function names " + names + " not to contain 'like'"); assertFalse(names.contains("$internal$sum_data_size_for_stats"), "Expected function names " + names + " not to contain '$internal$sum_data_size_for_stats'"); assertFalse(names.contains("$internal$max_data_size_for_stats"), "Expected function names " + names + " not to contain '$internal$max_data_size_for_stats'"); }
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); }
@Override public Result apply(AggregationNode parent, Captures captures, Context context) { if (!parent.hasDefaultOutput() || parent.getOutputSymbols().size() != 1) { return Result.empty(); } Map<Symbol, AggregationNode.Aggregation> assignments = parent.getAggregations(); for (Map.Entry<Symbol, AggregationNode.Aggregation> entry : assignments.entrySet()) { AggregationNode.Aggregation aggregation = entry.getValue(); requireNonNull(aggregation, "aggregation is null"); Signature signature = aggregation.getSignature(); FunctionCall functionCall = aggregation.getCall(); if (!"count".equals(signature.getName()) || !functionCall.getArguments().isEmpty()) { return Result.empty(); } } if (!assignments.isEmpty() && isScalar(parent.getSource(), context.getLookup())) { return Result.ofPlanNode(new ValuesNode(parent.getId(), parent.getOutputSymbols(), ImmutableList.of(ImmutableList.of(new LongLiteral("1"))))); } return Result.empty(); } }
private static BytecodeNode cast( BytecodeGeneratorContext generatorContext, BytecodeNode argument, Type actualType, TypeSignature requiredType) { if (actualType.getTypeSignature().equals(requiredType)) { return argument; } Signature function = generatorContext .getRegistry() .getCoercion(actualType.getTypeSignature(), requiredType); // TODO: do we need a full function call? (nullability checks, etc) return generatorContext.generateCall(function.getName(), generatorContext.getRegistry().getScalarFunctionImplementation(function), ImmutableList.of(argument)); } }
private static FunctionCall colorLiteral(long value) { return new FunctionCall(QualifiedName.of(getMagicLiteralFunctionSignature(COLOR).getName()), ImmutableList.of(bigintLiteral(value))); }
@Test public void testMagicLiteralFunction() { Signature signature = getMagicLiteralFunctionSignature(TIMESTAMP_WITH_TIME_ZONE); assertEquals(signature.getName(), "$literal$timestamp with time zone"); assertEquals(signature.getArgumentTypes(), ImmutableList.of(parseTypeSignature(StandardTypes.BIGINT))); assertEquals(signature.getReturnType().getBase(), StandardTypes.TIMESTAMP_WITH_TIME_ZONE); TypeRegistry typeManager = new TypeRegistry(); FunctionRegistry registry = new FunctionRegistry(typeManager, new BlockEncodingManager(typeManager), new FeaturesConfig()); Signature function = registry.resolveFunction(QualifiedName.of(signature.getName()), fromTypeSignatures(signature.getArgumentTypes())); assertEquals(function.getArgumentTypes(), ImmutableList.of(parseTypeSignature(StandardTypes.BIGINT))); assertEquals(signature.getReturnType().getBase(), StandardTypes.TIMESTAMP_WITH_TIME_ZONE); }
@Test public void testIdentityCast() { TypeRegistry typeManager = new TypeRegistry(); FunctionRegistry registry = new FunctionRegistry(typeManager, new BlockEncodingManager(typeManager), new FeaturesConfig()); Signature exactOperator = registry.getCoercion(HYPER_LOG_LOG, HYPER_LOG_LOG); assertEquals(exactOperator.getName(), mangleOperatorName(OperatorType.CAST.name())); assertEquals(transform(exactOperator.getArgumentTypes(), Functions.toStringFunction()), ImmutableList.of(StandardTypes.HYPER_LOG_LOG)); assertEquals(exactOperator.getReturnType().getBase(), StandardTypes.HYPER_LOG_LOG); }
@Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "\\QFunction already registered: custom_add(bigint,bigint):bigint\\E") public void testDuplicateFunctions() { List<SqlFunction> functions = new FunctionListBuilder() .scalars(CustomFunctions.class) .getFunctions() .stream() .filter(input -> input.getSignature().getName().equals("custom_add")) .collect(toImmutableList()); TypeRegistry typeManager = new TypeRegistry(); FunctionRegistry registry = new FunctionRegistry(typeManager, new BlockEncodingManager(typeManager), new FeaturesConfig()); registry.addFunctions(functions); registry.addFunctions(functions); }
@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()); } }