public Signature getCoercion(Type fromType, Type toType) { return getCoercion(fromType.getTypeSignature(), toType.getTypeSignature()); }
static OptionalDouble toStatsRepresentation(FunctionRegistry functionRegistry, ConnectorSession session, Type type, Object value) { if (convertibleToDoubleWithCast(type)) { InterpretedFunctionInvoker functionInvoker = new InterpretedFunctionInvoker(functionRegistry); Signature castSignature = functionRegistry.getCoercion(type, DoubleType.DOUBLE); return OptionalDouble.of((double) functionInvoker.invoke(castSignature, session, singletonList(value))); } if (DateType.DATE.equals(type)) { return OptionalDouble.of(((Long) value).doubleValue()); } return OptionalDouble.empty(); }
private static String castToVarchar(Type type, Object value, FunctionRegistry functionRegistry, Session session) { if (value == null) { return "NULL"; } try { Signature coercion = functionRegistry.getCoercion(type, VARCHAR); Slice coerced = (Slice) new InterpretedFunctionInvoker(functionRegistry).invoke(coercion, session.toConnectorSession(), value); return coerced.toStringUtf8(); } catch (OperatorNotFoundException e) { return "<UNREPRESENTABLE VALUE>"; } } }
@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; } }
private int compareOriginalValueToCoerced(Type originalValueType, Object originalValue, Type coercedValueType, Object coercedValue) { Signature castToOriginalTypeOperator = metadata.getFunctionRegistry().getCoercion(coercedValueType, originalValueType); Object coercedValueInOriginalType = functionInvoker.invoke(castToOriginalTypeOperator, session.toConnectorSession(), coercedValue); Block originalValueBlock = Utils.nativeValueToBlock(originalValueType, originalValue); Block coercedValueBlock = Utils.nativeValueToBlock(originalValueType, coercedValueInOriginalType); return originalValueType.compareTo(originalValueBlock, 0, coercedValueBlock, 0); }
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)); } }
Signature firstCast = metadata.getFunctionRegistry().getCoercion(firstType, commonType); Signature secondCast = metadata.getFunctionRegistry().getCoercion(secondType, commonType);
registry.getCoercion(call.getArguments().get(0).getType(), call.getType()), call.getType(), call.getArguments());
@Override public ScalarFunctionImplementation specialize(BoundVariables boundVariables, int arity, TypeManager typeManager, FunctionRegistry functionRegistry) { Type fromType = boundVariables.getTypeVariable("F"); Type toType = boundVariables.getTypeVariable("T"); Class<?> returnType = Primitives.wrap(toType.getJavaType()); List<ArgumentProperty> argumentProperties; MethodHandle tryCastHandle; // the resulting method needs to return a boxed type Signature signature = functionRegistry.getCoercion(fromType, toType); ScalarFunctionImplementation implementation = functionRegistry.getScalarFunctionImplementation(signature); argumentProperties = ImmutableList.of(implementation.getArgumentProperty(0)); MethodHandle coercion = implementation.getMethodHandle(); coercion = coercion.asType(methodType(returnType, coercion.type())); MethodHandle exceptionHandler = dropArguments(constant(returnType, null), 0, RuntimeException.class); tryCastHandle = catchException(coercion, RuntimeException.class, exceptionHandler); return new ScalarFunctionImplementation(true, argumentProperties, tryCastHandle, isDeterministic()); } }
@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); }
@Override public Type visitCast(Cast node, StackableAstVisitorContext<Context> context) { Type type; try { type = typeManager.getType(parseTypeSignature(node.getType())); } catch (IllegalArgumentException e) { throw new SemanticException(TYPE_MISMATCH, node, "Unknown type: " + node.getType()); } if (type.equals(UNKNOWN)) { throw new SemanticException(TYPE_MISMATCH, node, "UNKNOWN is not a valid type"); } Type value = process(node.getExpression(), context); if (!value.equals(UNKNOWN) && !node.isTypeOnly()) { try { functionRegistry.getCoercion(value, type); } catch (OperatorNotFoundException e) { throw new SemanticException(TYPE_MISMATCH, node, "Cannot cast %s to %s", value, type); } } return setExpressionType(node, type); }
@Override protected Type visitGenericLiteral(GenericLiteral node, StackableAstVisitorContext<Context> context) { Type type; try { type = typeManager.getType(parseTypeSignature(node.getType())); } catch (IllegalArgumentException e) { throw new SemanticException(TYPE_MISMATCH, node, "Unknown type: " + node.getType()); } if (!JSON.equals(type)) { try { functionRegistry.getCoercion(VARCHAR, type); } catch (IllegalArgumentException e) { throw new SemanticException(TYPE_MISMATCH, node, "No literal form for type %s", type); } } return setExpressionType(node, type); }
@Override protected Object visitGenericLiteral(GenericLiteral node, ConnectorSession session) { Type type = metadata.getType(parseTypeSignature(node.getType())); if (type == null) { throw new SemanticException(TYPE_MISMATCH, node, "Unknown type: " + node.getType()); } if (JSON.equals(type)) { Signature operatorSignature = new Signature("json_parse", SCALAR, JSON.getTypeSignature(), VARCHAR.getTypeSignature()); return functionInvoker.invoke(operatorSignature, session, ImmutableList.of(utf8Slice(node.getValue()))); } try { Signature signature = metadata.getFunctionRegistry().getCoercion(VARCHAR, type); return functionInvoker.invoke(signature, session, ImmutableList.of(utf8Slice(node.getValue()))); } catch (IllegalArgumentException e) { throw new SemanticException(TYPE_MISMATCH, node, "No literal form for type %s", type); } }
Signature operator = metadata.getFunctionRegistry().getCoercion(sourceType, targetType);
/** * The signature of the returned MethodHandle is (Block fromMap, int position, ConnectorSession session, BlockBuilder mapBlockBuilder)void. * The processor will get the value from fromMap, cast it and write to toBlock. */ private MethodHandle buildProcessor(FunctionRegistry functionRegistry, Type fromType, Type toType, boolean isKey) { MethodHandle getter = nativeValueGetter(fromType); // Adapt cast that takes ([ConnectorSession,] ?) to one that takes (?, ConnectorSession), where ? is the return type of getter. ScalarFunctionImplementation castImplementation = functionRegistry.getScalarFunctionImplementation(functionRegistry.getCoercion(fromType, toType)); MethodHandle cast = castImplementation.getMethodHandle(); if (cast.type().parameterArray()[0] != ConnectorSession.class) { cast = MethodHandles.dropArguments(cast, 0, ConnectorSession.class); } cast = permuteArguments(cast, methodType(cast.type().returnType(), cast.type().parameterArray()[1], cast.type().parameterArray()[0]), 1, 0); MethodHandle target = compose(cast, getter); // If the key cast function is nullable, check the result is not null. if (isKey && castImplementation.isNullable()) { target = compose(nullChecker(target.type().returnType()), target); } MethodHandle writer = nativeValueWriter(toType); writer = permuteArguments(writer, methodType(void.class, writer.type().parameterArray()[1], writer.type().parameterArray()[0]), 1, 0); return compose(writer, target.asType(methodType(unwrap(target.type().returnType()), target.type().parameterArray()))); }
public Signature getCoercion(Type fromType, Type toType) { return getCoercion(fromType.getTypeSignature(), toType.getTypeSignature()); }
@Override public BytecodeNode generateExpression(Signature signature, BytecodeGeneratorContext generatorContext, Type returnType, List<RowExpression> arguments) { RowExpression argument = arguments.get(0); Signature function = generatorContext .getRegistry() .getCoercion(argument.getType(), returnType); return generatorContext.generateCall(function.getName(), generatorContext.getRegistry().getScalarFunctionImplementation(function), ImmutableList.of(generatorContext.generate(argument))); } }
private Optional<NullableValue> coerce(NullableValue value, Type targetType) { if (!TypeRegistry.canCoerce(value.getType(), targetType)) { return Optional.empty(); } if (value.isNull()) { return Optional.of(NullableValue.asNull(targetType)); } Object coercedValue = new FunctionInvoker(metadata.getFunctionRegistry()) .invoke(metadata.getFunctionRegistry().getCoercion(value.getType(), targetType), session.toConnectorSession(), value.getValue()); return Optional.of(NullableValue.of(targetType, coercedValue)); }
@Override protected Type visitGenericLiteral(GenericLiteral node, StackableAstVisitorContext<AnalysisContext> context) { Type type = typeManager.getType(parseTypeSignature(node.getType())); if (type == null) { throw new SemanticException(TYPE_MISMATCH, node, "Unknown type: " + node.getType()); } if (!JSON.equals(type)) { try { functionRegistry.getCoercion(VARCHAR, type); } catch (IllegalArgumentException e) { throw new SemanticException(TYPE_MISMATCH, node, "No literal form for type %s", type); } } expressionTypes.put(node, type); return type; }
@Test public void testIdentityCast() { TypeRegistry typeManager = new TypeRegistry(); FunctionRegistry registry = new FunctionRegistry(typeManager, new BlockEncodingManager(typeManager), true); 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); }