diff --git a/presto-main/src/main/java/io/prestosql/metadata/FunctionAndTypeManager.java b/presto-main/src/main/java/io/prestosql/metadata/FunctionAndTypeManager.java index bce51cdac658d77d5e9d25eddd5ec12b128dee9a..8f427de3df7d811be27980e94e8c937c0e5c038b 100644 --- a/presto-main/src/main/java/io/prestosql/metadata/FunctionAndTypeManager.java +++ b/presto-main/src/main/java/io/prestosql/metadata/FunctionAndTypeManager.java @@ -213,7 +213,7 @@ public class FunctionAndTypeManager Map properties) { requireNonNull(hetuMetaStoreManager, "hetuMetaStoreManager is nll"); - FunctionNamespaceManagerContextInstance functionNamespaceManagerContextInstance = new FunctionNamespaceManagerContextInstance(hetuMetaStoreManager.getHetuMetastore()); + FunctionNamespaceManagerContextInstance functionNamespaceManagerContextInstance = new FunctionNamespaceManagerContextInstance(hetuMetaStoreManager.getHetuMetastore(), this); requireNonNull(functionNamespaceManagerName, "functionNamespaceManagerName is null"); FunctionNamespaceManagerFactory factory = functionNamespaceManagerFactories.get(functionNamespaceManagerName); checkState(factory != null, "No factory for function namespace manager %s", functionNamespaceManagerName); @@ -239,6 +239,11 @@ public class FunctionAndTypeManager return functionInvokerProvider; } + public Map> getFunctionNamespaceManagers() + { + return functionNamespaceManagers; + } + public void addFunctionNamespaceFactory(FunctionNamespaceManagerFactory factory) { if (functionNamespaceManagerFactories.putIfAbsent(factory.getName(), factory) != null) { @@ -539,6 +544,11 @@ public class FunctionAndTypeManager Optional transactionHandle = transactionId .map(id -> transactionManager.getFunctionNamespaceTransaction(id, functionName.getCatalogSchemaName().getCatalogName())); + + if (functionNamespaceManager.canResolveFunction()) { + return functionNamespaceManager.resolveFunction(transactionHandle, functionName, + parameterTypes.stream().map(TypeSignatureProvider::getTypeSignature).collect(toImmutableList())); + } Collection candidates = functionNamespaceManager.getFunctions(transactionHandle, functionName); return functionResolver.resolveFunction(functionNamespaceManager, transactionHandle, functionName, parameterTypes, candidates); diff --git a/presto-main/src/main/java/io/prestosql/metadata/FunctionNamespaceManagerContextInstance.java b/presto-main/src/main/java/io/prestosql/metadata/FunctionNamespaceManagerContextInstance.java index 36c26a857a43651442bfce6f0d08648a9d9caaef..eaaf689528bcec064226283f5cf62aefd02063cc 100644 --- a/presto-main/src/main/java/io/prestosql/metadata/FunctionNamespaceManagerContextInstance.java +++ b/presto-main/src/main/java/io/prestosql/metadata/FunctionNamespaceManagerContextInstance.java @@ -15,6 +15,7 @@ package io.prestosql.metadata; import io.prestosql.spi.function.FunctionNamespaceManagerContext; import io.prestosql.spi.metastore.HetuMetastore; +import io.prestosql.spi.type.TypeManager; import java.util.Optional; @@ -23,9 +24,12 @@ public class FunctionNamespaceManagerContextInstance { private final HetuMetastore hetuMetastore; - public FunctionNamespaceManagerContextInstance(HetuMetastore hetuMetastore) + private final TypeManager typeManager; + + public FunctionNamespaceManagerContextInstance(HetuMetastore hetuMetastore, TypeManager typeManager) { this.hetuMetastore = hetuMetastore; + this.typeManager = typeManager; } @Override @@ -36,4 +40,13 @@ public class FunctionNamespaceManagerContextInstance } return Optional.of(hetuMetastore); } + + @Override + public Optional getTypeManager() + { + if (typeManager == null) { + return Optional.empty(); + } + return Optional.of(typeManager); + } } diff --git a/presto-main/src/main/java/io/prestosql/sql/InterpretedFunctionInvoker.java b/presto-main/src/main/java/io/prestosql/sql/InterpretedFunctionInvoker.java index d0ec2db90784cc1e4921abae74454c072bd6fb31..b459fd6acf70630960f3cf85d2f987d1681a80d4 100644 --- a/presto-main/src/main/java/io/prestosql/sql/InterpretedFunctionInvoker.java +++ b/presto-main/src/main/java/io/prestosql/sql/InterpretedFunctionInvoker.java @@ -19,6 +19,7 @@ import io.prestosql.spi.connector.ConnectorSession; import io.prestosql.spi.function.BuiltInScalarFunctionImplementation; import io.prestosql.spi.function.BuiltInScalarFunctionImplementation.ArgumentProperty; import io.prestosql.spi.function.FunctionHandle; +import io.prestosql.spi.function.ScalarFunctionImplementation; import java.lang.invoke.MethodHandle; import java.util.ArrayList; @@ -29,6 +30,7 @@ import static com.google.common.base.Throwables.throwIfUnchecked; import static io.prestosql.spi.function.BuiltInScalarFunctionImplementation.ArgumentType.VALUE_TYPE; import static io.prestosql.spi.function.BuiltInScalarFunctionImplementation.NullConvention.RETURN_NULL_ON_NULL; import static io.prestosql.spi.function.BuiltInScalarFunctionImplementation.NullConvention.USE_NULL_FLAG; +import static io.prestosql.sql.gen.BytecodeUtils.getAllScalarFunctionImplementationChoices; import static java.lang.invoke.MethodHandleProxies.asInterfaceInstance; import static java.util.Objects.requireNonNull; @@ -48,7 +50,7 @@ public class InterpretedFunctionInvoker public Object invoke(FunctionHandle functionHandle, ConnectorSession session, List arguments) { - return invoke(functionAndTypeManager.getBuiltInScalarFunctionImplementation(functionHandle), session, arguments); + return invoke(functionAndTypeManager.getScalarFunctionImplementation(functionHandle), session, arguments); } /** @@ -56,8 +58,9 @@ public class InterpretedFunctionInvoker *

* Returns a value in the native container type corresponding to the declared SQL return type */ - private Object invoke(BuiltInScalarFunctionImplementation function, ConnectorSession session, List arguments) + private Object invoke(ScalarFunctionImplementation function, ConnectorSession session, List arguments) { + BuiltInScalarFunctionImplementation.ScalarImplementationChoice choice = getAllScalarFunctionImplementationChoices(function).get(0); MethodHandle method = function.getMethodHandle(); // handle function on instance method, to allow use of fields @@ -69,15 +72,15 @@ public class InterpretedFunctionInvoker List actualArguments = new ArrayList<>(); for (int i = 0; i < arguments.size(); i++) { Object argument = arguments.get(i); - ArgumentProperty argumentProperty = function.getArgumentProperty(i); + ArgumentProperty argumentProperty = choice.getArgumentProperty(i); if (argumentProperty.getArgumentType() == VALUE_TYPE) { - if (function.getArgumentProperty(i).getNullConvention() == RETURN_NULL_ON_NULL) { + if (choice.getArgumentProperty(i).getNullConvention() == RETURN_NULL_ON_NULL) { if (argument == null) { return null; } actualArguments.add(argument); } - else if (function.getArgumentProperty(i).getNullConvention() == USE_NULL_FLAG) { + else if (choice.getArgumentProperty(i).getNullConvention() == USE_NULL_FLAG) { boolean isNull = argument == null; if (isNull) { argument = Defaults.defaultValue(method.type().parameterType(actualArguments.size())); @@ -103,14 +106,19 @@ public class InterpretedFunctionInvoker } } - private static MethodHandle bindInstanceFactory(MethodHandle method, BuiltInScalarFunctionImplementation implementation) + private static MethodHandle bindInstanceFactory(MethodHandle method, ScalarFunctionImplementation implementation) { - if (!implementation.getInstanceFactory().isPresent()) { + if (!(implementation instanceof BuiltInScalarFunctionImplementation)) { + return method; + } + + BuiltInScalarFunctionImplementation builtInImplementation = (BuiltInScalarFunctionImplementation) implementation; + if (!builtInImplementation.getInstanceFactory().isPresent()) { return method; } try { - return method.bindTo(implementation.getInstanceFactory().get().invoke()); + return method.bindTo(builtInImplementation.getInstanceFactory().get().invoke()); } catch (Throwable throwable) { throw propagate(throwable); diff --git a/presto-main/src/main/java/io/prestosql/sql/gen/BytecodeGeneratorContext.java b/presto-main/src/main/java/io/prestosql/sql/gen/BytecodeGeneratorContext.java index 10e2b33a1c58199f0e12190909f7bf32b04240fa..fdf30fda43240177f4acc4fc553642e3abfe3aa5 100644 --- a/presto-main/src/main/java/io/prestosql/sql/gen/BytecodeGeneratorContext.java +++ b/presto-main/src/main/java/io/prestosql/sql/gen/BytecodeGeneratorContext.java @@ -19,6 +19,7 @@ import io.airlift.bytecode.Scope; import io.airlift.bytecode.Variable; import io.prestosql.metadata.FunctionAndTypeManager; import io.prestosql.spi.function.BuiltInScalarFunctionImplementation; +import io.prestosql.spi.function.ScalarFunctionImplementation; import io.prestosql.spi.relation.RowExpression; import java.util.List; @@ -85,11 +86,11 @@ public class BytecodeGeneratorContext /** * Generates a function call with null handling, automatic binding of session parameter, etc. */ - public BytecodeNode generateCall(String name, BuiltInScalarFunctionImplementation function, List arguments) + public BytecodeNode generateCall(String name, ScalarFunctionImplementation function, List arguments) { Optional instance = Optional.empty(); - if (function.getInstanceFactory().isPresent()) { - FieldDefinition field = cachedInstanceBinder.getCachedInstance(function.getInstanceFactory().get()); + if (function instanceof BuiltInScalarFunctionImplementation && ((BuiltInScalarFunctionImplementation) function).getInstanceFactory().isPresent()) { + FieldDefinition field = cachedInstanceBinder.getCachedInstance(((BuiltInScalarFunctionImplementation) function).getInstanceFactory().get()); instance = Optional.of(scope.getThis().getField(field)); } return generateInvocation(scope, name, function, instance, arguments, callSiteBinder); diff --git a/presto-main/src/main/java/io/prestosql/sql/gen/BytecodeUtils.java b/presto-main/src/main/java/io/prestosql/sql/gen/BytecodeUtils.java index eedeb98456d6e0c0627548b1efd489805f40481a..f161870d4022d45579dfe345e457022e62bf57f5 100644 --- a/presto-main/src/main/java/io/prestosql/sql/gen/BytecodeUtils.java +++ b/presto-main/src/main/java/io/prestosql/sql/gen/BytecodeUtils.java @@ -31,6 +31,7 @@ import io.prestosql.spi.function.BuiltInScalarFunctionImplementation; import io.prestosql.spi.function.BuiltInScalarFunctionImplementation.ArgumentProperty; import io.prestosql.spi.function.BuiltInScalarFunctionImplementation.NullConvention; import io.prestosql.spi.function.BuiltInScalarFunctionImplementation.ScalarImplementationChoice; +import io.prestosql.spi.function.ScalarFunctionImplementation; import io.prestosql.spi.type.Type; import io.prestosql.sql.gen.InputReferenceCompiler.InputReferenceNode; @@ -42,11 +43,18 @@ import java.util.Optional; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.ImmutableList.toImmutableList; import static io.airlift.bytecode.OpCode.NOP; import static io.airlift.bytecode.expression.BytecodeExpressions.constantFalse; import static io.airlift.bytecode.expression.BytecodeExpressions.constantTrue; import static io.airlift.bytecode.expression.BytecodeExpressions.invokeDynamic; +import static io.prestosql.spi.function.BuiltInScalarFunctionImplementation.ArgumentProperty.valueTypeArgumentProperty; import static io.prestosql.spi.function.BuiltInScalarFunctionImplementation.ArgumentType.VALUE_TYPE; +import static io.prestosql.spi.function.BuiltInScalarFunctionImplementation.NullConvention.BLOCK_AND_POSITION; +import static io.prestosql.spi.function.BuiltInScalarFunctionImplementation.NullConvention.RETURN_NULL_ON_NULL; +import static io.prestosql.spi.function.BuiltInScalarFunctionImplementation.NullConvention.USE_BOXED_TYPE; +import static io.prestosql.spi.function.BuiltInScalarFunctionImplementation.NullConvention.USE_NULL_FLAG; +import static io.prestosql.spi.function.BuiltInScalarFunctionImplementation.ReturnPlaceConvention.STACK; import static io.prestosql.sql.gen.Bootstrap.BOOTSTRAP_METHOD; import static java.lang.String.format; @@ -159,14 +167,14 @@ public final class BytecodeUtils binding.getType().returnType()); } - public static BytecodeNode generateInvocation(Scope scope, String name, BuiltInScalarFunctionImplementation function, Optional instance, List arguments, CallSiteBinder binder) + public static BytecodeNode generateInvocation(Scope scope, String name, ScalarFunctionImplementation function, Optional instance, List arguments, CallSiteBinder binder) { LabelNode end = new LabelNode("end"); BytecodeBlock block = new BytecodeBlock() .setDescription("invoke " + name); List> stackTypes = new ArrayList<>(); - if (function.getInstanceFactory().isPresent()) { + if (function instanceof BuiltInScalarFunctionImplementation && ((BuiltInScalarFunctionImplementation) function).getInstanceFactory().isPresent()) { checkArgument(instance.isPresent()); } @@ -177,7 +185,7 @@ public final class BytecodeUtils int realParameterIndex = 0; // Go through all the choices in the function and then pick the best one - List choices = function.getAllChoices(); + List choices = getAllScalarFunctionImplementationChoices(function); ScalarImplementationChoice bestChoice = null; for (ScalarImplementationChoice currentChoice : choices) { boolean isValid = true; @@ -373,4 +381,30 @@ public final class BytecodeUtils .getVariable(tempValue) .invokeInterface(Type.class, methodName, void.class, BlockBuilder.class, valueJavaType))); } + + public static List getAllScalarFunctionImplementationChoices(ScalarFunctionImplementation function) + { + if (function instanceof BuiltInScalarFunctionImplementation) { + return ((BuiltInScalarFunctionImplementation) function).getAllChoices(); + } + return ImmutableList.of(new ScalarImplementationChoice( + function.isNullable(), + function.getInvocationConvention().getArgumentConventions().stream().map(invocationArgumentConvention -> { + switch (invocationArgumentConvention) { + case NEVER_NULL: + return valueTypeArgumentProperty(RETURN_NULL_ON_NULL); + case BOXED_NULLABLE: + return valueTypeArgumentProperty(USE_BOXED_TYPE); + case NULL_FLAG: + return valueTypeArgumentProperty(USE_NULL_FLAG); + case BLOCK_POSITION: + return valueTypeArgumentProperty(BLOCK_AND_POSITION); + default: + throw new UnsupportedOperationException(format("InvocationArgumentConvention %s cannot be a value type", invocationArgumentConvention)); + } + }).collect(toImmutableList()), + STACK, + function.getMethodHandle(), + Optional.empty())); + } } diff --git a/presto-main/src/main/java/io/prestosql/sql/gen/FunctionCallCodeGenerator.java b/presto-main/src/main/java/io/prestosql/sql/gen/FunctionCallCodeGenerator.java index 9700e7ce6dcead13c29765821334d05dac3bb9db..a1ca66fd6c3b965f0aa983bc5c500e7857850ed2 100644 --- a/presto-main/src/main/java/io/prestosql/sql/gen/FunctionCallCodeGenerator.java +++ b/presto-main/src/main/java/io/prestosql/sql/gen/FunctionCallCodeGenerator.java @@ -17,6 +17,7 @@ import io.airlift.bytecode.BytecodeNode; import io.prestosql.metadata.FunctionAndTypeManager; import io.prestosql.spi.function.BuiltInScalarFunctionImplementation; import io.prestosql.spi.function.FunctionHandle; +import io.prestosql.spi.function.ScalarFunctionImplementation; import io.prestosql.spi.relation.RowExpression; import io.prestosql.spi.type.Type; @@ -25,6 +26,7 @@ import java.util.List; import java.util.Optional; import static io.prestosql.spi.function.BuiltInScalarFunctionImplementation.ArgumentType.VALUE_TYPE; +import static io.prestosql.sql.gen.BytecodeUtils.getAllScalarFunctionImplementationChoices; public class FunctionCallCodeGenerator implements BytecodeGenerator @@ -34,12 +36,14 @@ public class FunctionCallCodeGenerator { FunctionAndTypeManager functionAndTypeManager = context.getFunctionManager(); - BuiltInScalarFunctionImplementation function = functionAndTypeManager.getBuiltInScalarFunctionImplementation(functionHandle); + ScalarFunctionImplementation function = functionAndTypeManager.getScalarFunctionImplementation(functionHandle); List argumentsBytecode = new ArrayList<>(); + BuiltInScalarFunctionImplementation.ScalarImplementationChoice choice = getAllScalarFunctionImplementationChoices(function).get(0); + for (int i = 0; i < arguments.size(); i++) { RowExpression argument = arguments.get(i); - BuiltInScalarFunctionImplementation.ArgumentProperty argumentProperty = function.getArgumentProperty(i); + BuiltInScalarFunctionImplementation.ArgumentProperty argumentProperty = choice.getArgumentProperty(i); if (argumentProperty.getArgumentType() == VALUE_TYPE) { argumentsBytecode.add(context.generate(argument)); } diff --git a/presto-main/src/main/java/io/prestosql/sql/planner/sanity/ExternalFunctionPushDownChecker.java b/presto-main/src/main/java/io/prestosql/sql/planner/sanity/ExternalFunctionPushDownChecker.java index 8c7124428517ac236313d2379feda693b0137ae6..f493e1031d42d69999e377086aa852dac4e148d1 100644 --- a/presto-main/src/main/java/io/prestosql/sql/planner/sanity/ExternalFunctionPushDownChecker.java +++ b/presto-main/src/main/java/io/prestosql/sql/planner/sanity/ExternalFunctionPushDownChecker.java @@ -17,9 +17,11 @@ package io.prestosql.sql.planner.sanity; import io.prestosql.Session; import io.prestosql.execution.warnings.WarningCollector; import io.prestosql.expressions.DefaultRowExpressionTraversalVisitor; +import io.prestosql.metadata.FunctionAndTypeManager; import io.prestosql.metadata.Metadata; import io.prestosql.spi.ErrorCodeSupplier; import io.prestosql.spi.PrestoException; +import io.prestosql.spi.connector.CatalogSchemaName; import io.prestosql.spi.plan.AggregationNode; import io.prestosql.spi.plan.FilterNode; import io.prestosql.spi.plan.JoinNode; @@ -50,7 +52,6 @@ import java.util.Set; import java.util.stream.Collectors; import static io.prestosql.spi.StandardErrorCode.GENERIC_USER_ERROR; -import static io.prestosql.spi.connector.CatalogSchemaName.DEFAULT_NAMESPACE; import static io.prestosql.sql.relational.OriginalExpressionUtils.isOriginalExpression; import static java.lang.String.format; import static java.util.Objects.requireNonNull; @@ -66,7 +67,7 @@ public class ExternalFunctionPushDownChecker public void validate(PlanNode planNode, Session session, Metadata metadata, TypeAnalyzer typeAnalyzer, TypeProvider types, WarningCollector warningCollector) { Set set = new HashSet<>(); - planNode.accept(new ExternalFunctionFinder(), set); + planNode.accept(new ExternalFunctionFinder(metadata.getFunctionAndTypeManager()), set); if (set.size() > 0) { String allErrorFun = set.stream().map(String::toString).collect(Collectors.joining(", ")); throw new IllegalExternalFunctionUsageException( @@ -78,6 +79,18 @@ public class ExternalFunctionPushDownChecker private static class ExternalFunctionFinder extends InternalPlanVisitor> { + public static List functionNamespaces = new ArrayList<>(); + + public ExternalFunctionFinder(FunctionAndTypeManager functionAndTypeManager) + { + for (String catalog : functionAndTypeManager.getFunctionNamespaceManagers().keySet()) { + CatalogSchemaName namespace = new CatalogSchemaName(catalog, "default"); + if (!functionNamespaces.contains(namespace)) { + functionNamespaces.add(namespace); + } + } + } + @Override public Void visitPlan(PlanNode node, Set context) { @@ -282,7 +295,7 @@ public class ExternalFunctionPushDownChecker private static boolean isDefaultFunction(CallExpression callExpression) { - return DEFAULT_NAMESPACE.equals(callExpression.getFunctionHandle().getFunctionNamespace()); + return ExternalFunctionFinder.functionNamespaces.contains(callExpression.getFunctionHandle().getFunctionNamespace()); } } diff --git a/presto-spi/src/main/java/io/prestosql/spi/function/FunctionNamespaceManager.java b/presto-spi/src/main/java/io/prestosql/spi/function/FunctionNamespaceManager.java index d45c4e1a3cd74ad858147027aa39c12da8f7555c..1de96c2afb2c9767380b0bac7deef88cad0495e9 100644 --- a/presto-spi/src/main/java/io/prestosql/spi/function/FunctionNamespaceManager.java +++ b/presto-spi/src/main/java/io/prestosql/spi/function/FunctionNamespaceManager.java @@ -18,6 +18,7 @@ import io.prestosql.spi.block.Block; import io.prestosql.spi.connector.ConnectorSession; import io.prestosql.spi.connector.QualifiedObjectName; import io.prestosql.spi.type.TypeManager; +import io.prestosql.spi.type.TypeSignature; import java.util.List; import java.util.Optional; @@ -69,4 +70,14 @@ public interface FunctionNamespaceManager { throw new UnsupportedOperationException(); } + + default boolean canResolveFunction() + { + return false; + } + + default FunctionHandle resolveFunction(Optional transactionHandle, QualifiedObjectName functionName, List parameterTypes) + { + throw new UnsupportedOperationException("Does not support resolving function"); + } } diff --git a/presto-spi/src/main/java/io/prestosql/spi/function/FunctionNamespaceManagerContext.java b/presto-spi/src/main/java/io/prestosql/spi/function/FunctionNamespaceManagerContext.java index c4e6310d6869da5f143e0fd3de180e5a0855272a..0762bea81e76e547690fcce8c5ab462b31e91f3f 100644 --- a/presto-spi/src/main/java/io/prestosql/spi/function/FunctionNamespaceManagerContext.java +++ b/presto-spi/src/main/java/io/prestosql/spi/function/FunctionNamespaceManagerContext.java @@ -14,6 +14,7 @@ package io.prestosql.spi.function; import io.prestosql.spi.metastore.HetuMetastore; +import io.prestosql.spi.type.TypeManager; import java.util.Optional; @@ -23,4 +24,9 @@ public interface FunctionNamespaceManagerContext { throw new UnsupportedOperationException(); } + + default Optional getTypeManager() + { + throw new UnsupportedOperationException(); + } } diff --git a/presto-spi/src/main/java/io/prestosql/spi/function/InvocationConvention.java b/presto-spi/src/main/java/io/prestosql/spi/function/InvocationConvention.java index 83e9f559aec13be8d7d7a1bca7537ddb4bae5d9b..51c46d799a32d419af42cbe0552add6961616c87 100644 --- a/presto-spi/src/main/java/io/prestosql/spi/function/InvocationConvention.java +++ b/presto-spi/src/main/java/io/prestosql/spi/function/InvocationConvention.java @@ -33,6 +33,11 @@ public class InvocationConvention return returnConvention; } + public List getArgumentConventions() + { + return argumentConventionList; + } + public InvocationArgumentConvention getArgumentConvention(int index) { return argumentConventionList.get(index); diff --git a/presto-spi/src/main/java/io/prestosql/spi/function/ScalarFunctionImplementation.java b/presto-spi/src/main/java/io/prestosql/spi/function/ScalarFunctionImplementation.java index adb5a368c176e441deba07fefe98e838d9e00df9..e580db5e735be94aef5fb81a718759c3c606d601 100644 --- a/presto-spi/src/main/java/io/prestosql/spi/function/ScalarFunctionImplementation.java +++ b/presto-spi/src/main/java/io/prestosql/spi/function/ScalarFunctionImplementation.java @@ -13,6 +13,22 @@ */ package io.prestosql.spi.function; +import java.lang.invoke.MethodHandle; + public interface ScalarFunctionImplementation { + default InvocationConvention getInvocationConvention() + { + throw new UnsupportedOperationException("Not support this ScalarFunctionImplementation to get InvocationConvention"); + } + + default MethodHandle getMethodHandle() + { + throw new UnsupportedOperationException("Not support this ScalarFunctionImplementation to get MethodHandle"); + } + + default boolean isNullable() + { + throw new UnsupportedOperationException("Not support this ScalarFunctionImplementation to check whether isNullable"); + } }