diff --git a/presto-main-base/src/main/java/com/facebook/presto/metadata/FunctionAndTypeManager.java b/presto-main-base/src/main/java/com/facebook/presto/metadata/FunctionAndTypeManager.java index 7547a8cbd26cd..e1527797bc129 100644 --- a/presto-main-base/src/main/java/com/facebook/presto/metadata/FunctionAndTypeManager.java +++ b/presto-main-base/src/main/java/com/facebook/presto/metadata/FunctionAndTypeManager.java @@ -61,6 +61,7 @@ import com.facebook.presto.sql.analyzer.FeaturesConfig; import com.facebook.presto.sql.analyzer.FunctionAndTypeResolver; import com.facebook.presto.sql.analyzer.FunctionsConfig; +import com.facebook.presto.sql.analyzer.SemanticException; import com.facebook.presto.sql.analyzer.TypeSignatureProvider; import com.facebook.presto.sql.gen.CacheStatsMBean; import com.facebook.presto.sql.tree.QualifiedName; @@ -80,6 +81,7 @@ import org.weakref.jmx.Managed; import org.weakref.jmx.Nested; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -100,6 +102,7 @@ import static com.facebook.presto.metadata.BuiltInTypeAndFunctionNamespaceManager.JAVA_BUILTIN_NAMESPACE; import static com.facebook.presto.metadata.CastType.toOperatorType; import static com.facebook.presto.metadata.FunctionSignatureMatcher.constructFunctionNotFoundErrorMessage; +import static com.facebook.presto.metadata.FunctionSignatureMatcher.decideAndThrow; import static com.facebook.presto.metadata.SessionFunctionHandle.SESSION_NAMESPACE; import static com.facebook.presto.metadata.SignatureBinder.applyBoundVariables; import static com.facebook.presto.spi.StandardErrorCode.AMBIGUOUS_FUNCTION_CALL; @@ -1044,12 +1047,58 @@ private FunctionHandle getMatchingFunctionHandle( List parameterTypes, boolean coercionAllowed) { - Optional matchingDefaultFunctionSignature = - getMatchingFunction(functionNamespaceManager.getFunctions(transactionHandle, functionName), parameterTypes, coercionAllowed); - Optional matchingPluginFunctionSignature = - getMatchingFunction(builtInPluginFunctionNamespaceManager.getFunctions(transactionHandle, functionName), parameterTypes, coercionAllowed); - Optional matchingWorkerFunctionSignature = - getMatchingFunction(builtInWorkerFunctionNamespaceManager.getFunctions(transactionHandle, functionName), parameterTypes, coercionAllowed); + boolean foundMatch = false; + List exceptions = new ArrayList<>(); + List allCandidates = new ArrayList<>(); + Optional matchingDefaultFunctionSignature = Optional.empty(); + Optional matchingPluginFunctionSignature = Optional.empty(); + Optional matchingWorkerFunctionSignature = Optional.empty(); + + try { + Collection defaultCandidates = functionNamespaceManager.getFunctions(transactionHandle, functionName); + allCandidates.addAll(defaultCandidates); + matchingDefaultFunctionSignature = + getMatchingFunction(defaultCandidates, parameterTypes, coercionAllowed); + if (matchingDefaultFunctionSignature.isPresent()) { + foundMatch = true; + } + } + catch (SemanticException e) { + exceptions.add(e); + } + + try { + Collection pluginCandidates = builtInPluginFunctionNamespaceManager.getFunctions(transactionHandle, functionName); + allCandidates.addAll(pluginCandidates); + matchingPluginFunctionSignature = + getMatchingFunction(pluginCandidates, parameterTypes, coercionAllowed); + if (matchingPluginFunctionSignature.isPresent()) { + foundMatch = true; + } + } + catch (SemanticException e) { + exceptions.add(e); + } + + try { + Collection workerCandidates = builtInWorkerFunctionNamespaceManager.getFunctions(transactionHandle, functionName); + allCandidates.addAll(workerCandidates); + matchingWorkerFunctionSignature = + getMatchingFunction(workerCandidates, parameterTypes, coercionAllowed); + if (matchingWorkerFunctionSignature.isPresent()) { + foundMatch = true; + } + } + catch (SemanticException e) { + exceptions.add(e); + } + + if (!foundMatch && !exceptions.isEmpty()) { + decideAndThrow(exceptions, + allCandidates.stream().findFirst() + .map(function -> function.getSignature().getName().getObjectName()) + .orElse("")); + } if (matchingDefaultFunctionSignature.isPresent() && matchingPluginFunctionSignature.isPresent()) { throw new PrestoException(AMBIGUOUS_FUNCTION_CALL, format("Function '%s' has two matching signatures. Please specify parameter types. \n" + diff --git a/presto-main-base/src/main/java/com/facebook/presto/metadata/FunctionSignatureMatcher.java b/presto-main-base/src/main/java/com/facebook/presto/metadata/FunctionSignatureMatcher.java index 46d34dc13d61b..bba1d4fb1e1b4 100644 --- a/presto-main-base/src/main/java/com/facebook/presto/metadata/FunctionSignatureMatcher.java +++ b/presto-main-base/src/main/java/com/facebook/presto/metadata/FunctionSignatureMatcher.java @@ -338,7 +338,7 @@ private static boolean returnsNullOnGivenInputTypes(ApplicableFunction applicabl * If there's only one SemanticException, it throws that SemanticException directly. * If there are multiple SemanticExceptions, it throws the SignatureMatchingException. */ - private static void decideAndThrow(List failedExceptions, String functionName) + public static void decideAndThrow(List failedExceptions, String functionName) throws SemanticException { if (failedExceptions.size() == 1) { diff --git a/presto-native-execution/src/test/java/com/facebook/presto/nativeworker/PrestoNativeQueryRunnerUtils.java b/presto-native-execution/src/test/java/com/facebook/presto/nativeworker/PrestoNativeQueryRunnerUtils.java index e287ef7e0cb20..072ba5be1d47b 100644 --- a/presto-native-execution/src/test/java/com/facebook/presto/nativeworker/PrestoNativeQueryRunnerUtils.java +++ b/presto-native-execution/src/test/java/com/facebook/presto/nativeworker/PrestoNativeQueryRunnerUtils.java @@ -225,6 +225,10 @@ public HiveQueryRunnerBuilder setCoordinatorSidecarEnabled(boolean coordinatorSi public HiveQueryRunnerBuilder setBuiltInWorkerFunctionsEnabled(boolean builtInWorkerFunctionsEnabled) { this.builtInWorkerFunctionsEnabled = builtInWorkerFunctionsEnabled; + if (builtInWorkerFunctionsEnabled) { + this.extraProperties.put("built-in-sidecar-functions-enabled", "true"); + } + return this; } diff --git a/presto-native-execution/src/test/java/com/facebook/presto/nativeworker/TestPrestoNativeBuiltInFunctions.java b/presto-native-execution/src/test/java/com/facebook/presto/nativeworker/TestPrestoNativeBuiltInFunctions.java index 4e5836a56bc97..59263a302113c 100644 --- a/presto-native-execution/src/test/java/com/facebook/presto/nativeworker/TestPrestoNativeBuiltInFunctions.java +++ b/presto-native-execution/src/test/java/com/facebook/presto/nativeworker/TestPrestoNativeBuiltInFunctions.java @@ -214,5 +214,8 @@ public void testUdfQueries() assertPlan("SELECT test_agg_function(cast(orderkey as integer), cast(orderkey as integer), cast(orderkey as bigint)) FROM tpch.tiny.orders", anyTree(any())); assertPlan("SELECT test_agg_function(5, cast(orderkey as smallint), orderkey) FROM tpch.tiny.orders", anyTree(any())); + + assertQuerySucceeds("SELECT ARRAY_SORT( ARRAY[ ARRAY['a', 'b', 'c'] ], (x, y) -> IF( COALESCE( x[1], '' ) > COALESCE( y[1], '' ), 1, IF( COALESCE( x[1], '' ) < COALESCE( y[1], '' ), -1, 0 ) ) )"); + assertQuerySucceeds("SELECT ARRAY_SORT( ARRAY[ ARRAY['a', 'b', 'c'] ], (x, y) -> IF( COALESCE( x[1], '' ) > COALESCE( y[1], '' ), cast(1 as bigint), IF( COALESCE( x[1], '' ) < COALESCE( y[1], '' ), cast(-1 as bigint), cast(0 as bigint) ) ) )"); } }