diff --git a/presto-analyzer/src/main/java/com/facebook/presto/sql/analyzer/FunctionAndTypeResolver.java b/presto-analyzer/src/main/java/com/facebook/presto/sql/analyzer/FunctionAndTypeResolver.java index 652d06dc77a1c..03616d8690d51 100644 --- a/presto-analyzer/src/main/java/com/facebook/presto/sql/analyzer/FunctionAndTypeResolver.java +++ b/presto-analyzer/src/main/java/com/facebook/presto/sql/analyzer/FunctionAndTypeResolver.java @@ -52,4 +52,13 @@ FunctionHandle resolveFunction( FunctionHandle lookupCast(String castType, Type fromType, Type toType); QualifiedObjectName qualifyObjectName(QualifiedName name); + + /** + * Validate a function call during analysis phase on the coordinator. + * Delegates to the FunctionNamespaceManager for custom validation logic. + * + * @param functionHandle The function handle being validated + * @param arguments Raw argument expressions (not yet evaluated) + */ + void validateFunctionCall(FunctionHandle functionHandle, List arguments); } 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 e1527797bc129..1aac110ea88e5 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 @@ -319,6 +319,12 @@ public FunctionHandle lookupCast(String castType, Type fromType, Type toType) return FunctionAndTypeManager.this.lookupCast(CastType.valueOf(castType), fromType, toType); } + @Override + public void validateFunctionCall(FunctionHandle functionHandle, List arguments) + { + FunctionAndTypeManager.this.validateFunctionCall(functionHandle, arguments); + } + public QualifiedObjectName qualifyObjectName(QualifiedName name) { if (name.getSuffix().startsWith("$internal")) { @@ -719,6 +725,19 @@ public CompletableFuture executeFunction(String source, Funct return functionNamespaceManager.get().executeFunction(source, functionHandle, inputPage, channels, this); } + public void validateFunctionCall(FunctionHandle functionHandle, List arguments) + { + // Built-in functions don't need validation + if (functionHandle instanceof BuiltInFunctionHandle) { + return; + } + + Optional> functionNamespaceManager = getServingFunctionNamespaceManager(functionHandle.getCatalogSchemaName()); + if (functionNamespaceManager.isPresent()) { + functionNamespaceManager.get().validateFunctionCall(functionHandle, arguments); + } + } + public WindowFunctionSupplier getWindowFunctionImplementation(FunctionHandle functionHandle) { return builtInTypeAndFunctionNamespaceManager.getWindowFunctionImplementation(functionHandle); diff --git a/presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/ExpressionAnalyzer.java b/presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/ExpressionAnalyzer.java index 48917e5fcb61d..177e99402ca75 100644 --- a/presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/ExpressionAnalyzer.java +++ b/presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/ExpressionAnalyzer.java @@ -1120,6 +1120,10 @@ else if (frame.getType() == GROUPS) { FunctionHandle function = resolveFunction(sessionFunctions, transactionId, node, argumentTypes, functionAndTypeResolver); FunctionMetadata functionMetadata = functionAndTypeResolver.getFunctionMetadata(function); + // Delegate function-specific validation to the FunctionNamespaceManager + // This allows function namespaces to perform custom validation + functionAndTypeResolver.validateFunctionCall(function, node.getArguments()); + if (node.getOrderBy().isPresent()) { for (SortItem sortItem : node.getOrderBy().get().getSortItems()) { Type sortKeyType = process(sortItem.getSortKey(), context); diff --git a/presto-spi/src/main/java/com/facebook/presto/spi/function/FunctionNamespaceManager.java b/presto-spi/src/main/java/com/facebook/presto/spi/function/FunctionNamespaceManager.java index f6c4b8cb09ff2..eaa69b79df9fc 100644 --- a/presto-spi/src/main/java/com/facebook/presto/spi/function/FunctionNamespaceManager.java +++ b/presto-spi/src/main/java/com/facebook/presto/spi/function/FunctionNamespaceManager.java @@ -122,4 +122,18 @@ default AggregationFunctionImplementation getAggregateFunctionImplementation(Fun { throw new UnsupportedOperationException("Does not support get aggregation function"); } + + /** + * Validate a function call during analysis phase on the coordinator. + * This allows function namespace managers to perform custom validation logic + * such as security checks, argument validation, etc. + * + * @param functionHandle The function handle being validated + * @param arguments Raw argument expressions (not yet evaluated) - type is Object to avoid SPI module dependencies + * @throws RuntimeException if validation fails + */ + default void validateFunctionCall(FunctionHandle functionHandle, List arguments) + { + // Default implementation: no validation + } }