This is an automated email from the ASF dual-hosted git repository.
lzljs3620320 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git
The following commit(s) were added to refs/heads/master by this push:
new 892646ea85 [core] fix: function need belong to database (#5613)
892646ea85 is described below
commit 892646ea85e2ab5baf0eb022c172166f5e8b164d
Author: jerry <[email protected]>
AuthorDate: Fri May 16 17:48:34 2025 +0800
[core] fix: function need belong to database (#5613)
---
docs/static/rest-catalog-open-api.yaml | 37 ++++++-
.../java/org/apache/paimon/function/Function.java | 9 +-
.../org/apache/paimon/function/FunctionImpl.java | 28 +++---
.../main/java/org/apache/paimon/rest/RESTApi.java | 71 +++++++++++---
.../java/org/apache/paimon/rest/ResourcePaths.java | 14 ++-
.../rest/requests/CreateFunctionRequest.java | 4 +-
.../paimon/rest/responses/GetFunctionResponse.java | 6 +-
.../org/apache/paimon/catalog/AbstractCatalog.java | 14 +--
.../java/org/apache/paimon/catalog/Catalog.java | 109 ++++++++++++---------
.../org/apache/paimon/catalog/DelegateCatalog.java | 22 ++---
.../java/org/apache/paimon/rest/RESTCatalog.java | 42 ++++----
.../org/apache/paimon/rest/MockRESTMessage.java | 19 ++--
.../org/apache/paimon/rest/RESTCatalogServer.java | 86 ++++++----------
.../org/apache/paimon/rest/RESTCatalogTest.java | 64 ++++++------
14 files changed, 299 insertions(+), 226 deletions(-)
diff --git a/docs/static/rest-catalog-open-api.yaml
b/docs/static/rest-catalog-open-api.yaml
index efd483e7b6..acb7d57f2a 100644
--- a/docs/static/rest-catalog-open-api.yaml
+++ b/docs/static/rest-catalog-open-api.yaml
@@ -1272,7 +1272,7 @@ paths:
$ref: '#/components/responses/ViewAlreadyExistErrorResponse'
"500":
$ref: '#/components/responses/ServerErrorResponse'
- /v1/{prefix}/functions:
+ /v1/{prefix}/databases/{database}/functions:
get:
tags:
- function
@@ -1284,6 +1284,11 @@ paths:
required: true
schema:
type: string
+ - name: database
+ in: path
+ required: true
+ schema:
+ type: string
- name: maxResults
in: query
schema:
@@ -1302,6 +1307,8 @@ paths:
$ref: '#/components/schemas/ListFunctionsResponse'
"401":
$ref: '#/components/responses/UnauthorizedErrorResponse'
+ "404":
+ $ref: '#/components/responses/DatabaseNotExistErrorResponse'
"500":
$ref: '#/components/responses/ServerErrorResponse'
post:
@@ -1315,6 +1322,11 @@ paths:
required: true
schema:
type: string
+ - name: database
+ in: path
+ required: true
+ schema:
+ type: string
requestBody:
content:
application/json:
@@ -1327,12 +1339,14 @@ paths:
$ref: '#/components/responses/BadRequestErrorResponse'
"401":
$ref: '#/components/responses/UnauthorizedErrorResponse'
+ "404":
+ $ref: '#/components/responses/DatabaseNotExistErrorResponse'
"409":
$ref: '#/components/responses/FunctionAlreadyExistErrorResponse'
"500":
$ref: '#/components/responses/ServerErrorResponse'
- /v1/{prefix}/functions/{function}:
+ /v1/{prefix}/databases/{database}/functions/{function}:
get:
tags:
- function
@@ -1344,6 +1358,11 @@ paths:
required: true
schema:
type: string
+ - name: database
+ in: path
+ required: true
+ schema:
+ type: string
- name: function
in: path
required: true
@@ -1359,7 +1378,7 @@ paths:
"401":
$ref: '#/components/responses/UnauthorizedErrorResponse'
"404":
- $ref: '#/components/responses/DatabaseNotExistErrorResponse'
+ $ref: '#/components/responses/FunctionNotExistErrorResponse'
"500":
$ref: '#/components/responses/ServerErrorResponse'
post:
@@ -1373,6 +1392,11 @@ paths:
required: true
schema:
type: string
+ - name: database
+ in: path
+ required: true
+ schema:
+ type: string
- name: function
in: path
required: true
@@ -1403,6 +1427,11 @@ paths:
required: true
schema:
type: string
+ - name: database
+ in: path
+ required: true
+ schema:
+ type: string
- name: function
in: path
required: true
@@ -2573,8 +2602,6 @@ components:
GetFunctionResponse:
type: object
properties:
- uuid:
- type: string
name:
type: string
inputParams:
diff --git a/paimon-api/src/main/java/org/apache/paimon/function/Function.java
b/paimon-api/src/main/java/org/apache/paimon/function/Function.java
index 1f892387d4..b5d01e63c1 100644
--- a/paimon-api/src/main/java/org/apache/paimon/function/Function.java
+++ b/paimon-api/src/main/java/org/apache/paimon/function/Function.java
@@ -22,17 +22,18 @@ import org.apache.paimon.types.DataField;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
/** Interface for function. */
public interface Function {
- String uuid();
-
String name();
- List<DataField> inputParams();
+ String fullName();
+
+ Optional<List<DataField>> inputParams();
- List<DataField> returnParams();
+ Optional<List<DataField>> returnParams();
boolean isDeterministic();
diff --git
a/paimon-api/src/main/java/org/apache/paimon/function/FunctionImpl.java
b/paimon-api/src/main/java/org/apache/paimon/function/FunctionImpl.java
index 85ad987de9..b0290ea50e 100644
--- a/paimon-api/src/main/java/org/apache/paimon/function/FunctionImpl.java
+++ b/paimon-api/src/main/java/org/apache/paimon/function/FunctionImpl.java
@@ -18,17 +18,17 @@
package org.apache.paimon.function;
+import org.apache.paimon.catalog.Identifier;
import org.apache.paimon.types.DataField;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
/** Function implementation. */
public class FunctionImpl implements Function {
- private final String uuid;
-
- private final String name;
+ private final Identifier identifier;
private final List<DataField> inputParams;
@@ -43,16 +43,14 @@ public class FunctionImpl implements Function {
private final Map<String, String> options;
public FunctionImpl(
- String uuid,
- String functionName,
+ Identifier identifier,
List<DataField> inputParams,
List<DataField> returnParams,
boolean deterministic,
Map<String, FunctionDefinition> definitions,
String comment,
Map<String, String> options) {
- this.uuid = uuid;
- this.name = functionName;
+ this.identifier = identifier;
this.inputParams = inputParams;
this.returnParams = returnParams;
this.deterministic = deterministic;
@@ -62,23 +60,23 @@ public class FunctionImpl implements Function {
}
@Override
- public String uuid() {
- return this.uuid;
+ public String name() {
+ return identifier.getObjectName();
}
@Override
- public String name() {
- return this.name;
+ public String fullName() {
+ return identifier.getFullName();
}
@Override
- public List<DataField> inputParams() {
- return inputParams;
+ public Optional<List<DataField>> inputParams() {
+ return Optional.ofNullable(inputParams);
}
@Override
- public List<DataField> returnParams() {
- return returnParams;
+ public Optional<List<DataField>> returnParams() {
+ return Optional.ofNullable(returnParams);
}
@Override
diff --git a/paimon-api/src/main/java/org/apache/paimon/rest/RESTApi.java
b/paimon-api/src/main/java/org/apache/paimon/rest/RESTApi.java
index 0dece3bc79..b08af5ab17 100644
--- a/paimon-api/src/main/java/org/apache/paimon/rest/RESTApi.java
+++ b/paimon-api/src/main/java/org/apache/paimon/rest/RESTApi.java
@@ -753,38 +753,79 @@ public class RESTApi {
return response.branches();
}
- /** TODO. */
- public List<String> listFunctions() {
+ /**
+ * List functions for database.
+ *
+ * @param databaseName
+ * @return a list of function name
+ */
+ public List<String> listFunctions(String databaseName) {
return listDataFromPageApi(
queryParams ->
client.get(
- resourcePaths.functions(),
+ resourcePaths.functions(databaseName),
queryParams,
ListFunctionsResponse.class,
restAuthFunction));
}
- /** TODO. */
- public GetFunctionResponse getFunction(String functionName) {
+ /**
+ * Get a function by identifier.
+ *
+ * @param identifier the identifier of the function to retrieve
+ * @return the function response object
+ * @throws NoSuchResourceException if the function does not exist
+ * @throws ForbiddenException if the user lacks permission to access the
function
+ */
+ public GetFunctionResponse getFunction(Identifier identifier) {
return client.get(
- resourcePaths.function(functionName),
GetFunctionResponse.class, restAuthFunction);
+ resourcePaths.function(identifier.getDatabaseName(),
identifier.getObjectName()),
+ GetFunctionResponse.class,
+ restAuthFunction);
}
- /** TODO. */
- public void createFunction(org.apache.paimon.function.Function function) {
+ /**
+ * Create a function.
+ *
+ * @param identifier database name and function name.
+ * @param function the function to be created
+ * @throws AlreadyExistsException Exception thrown on HTTP 409 means a
function already exists
+ * @throws ForbiddenException Exception thrown on HTTP 403 means don't
have the permission for
+ * creating function
+ */
+ public void createFunction(
+ Identifier identifier, org.apache.paimon.function.Function
function) {
client.post(
- resourcePaths.functions(), new
CreateFunctionRequest(function), restAuthFunction);
+ resourcePaths.functions(identifier.getDatabaseName()),
+ new CreateFunctionRequest(function),
+ restAuthFunction);
}
- /** TODO. */
- public void dropFunction(String functionName) {
- client.delete(resourcePaths.function(functionName), restAuthFunction);
+ /**
+ * Drop a function.
+ *
+ * @param identifier database name and function name.
+ * @throws NoSuchResourceException Exception thrown on HTTP 404 means the
function not exists
+ * @throws ForbiddenException Exception thrown on HTTP 403 means don't
have the permission for
+ * this function
+ */
+ public void dropFunction(Identifier identifier) {
+ client.delete(
+ resourcePaths.function(identifier.getDatabaseName(),
identifier.getObjectName()),
+ restAuthFunction);
}
- /** TODO. */
- public void alterFunction(String functionName, List<FunctionChange>
changes) {
+ /**
+ * Alter a function.
+ *
+ * @param identifier database name and function name.
+ * @param changes list of function changes to apply
+ * @throws NoSuchResourceException if the function does not exist
+ * @throws ForbiddenException if the user lacks permission to modify the
function
+ */
+ public void alterFunction(Identifier identifier, List<FunctionChange>
changes) {
client.post(
- resourcePaths.function(functionName),
+ resourcePaths.function(identifier.getDatabaseName(),
identifier.getObjectName()),
new AlterFunctionRequest(changes),
restAuthFunction);
}
diff --git a/paimon-api/src/main/java/org/apache/paimon/rest/ResourcePaths.java
b/paimon-api/src/main/java/org/apache/paimon/rest/ResourcePaths.java
index a378b8dd76..70048e2a16 100644
--- a/paimon-api/src/main/java/org/apache/paimon/rest/ResourcePaths.java
+++ b/paimon-api/src/main/java/org/apache/paimon/rest/ResourcePaths.java
@@ -223,11 +223,17 @@ public class ResourcePaths {
return SLASH.join(V1, prefix, VIEWS, "rename");
}
- public String functions() {
- return SLASH.join(V1, prefix, FUNCTIONS);
+ public String functions(String databaseName) {
+ return SLASH.join(V1, prefix, DATABASES, encodeString(databaseName),
FUNCTIONS);
}
- public String function(String functionName) {
- return SLASH.join(V1, prefix, FUNCTIONS, encodeString(functionName));
+ public String function(String databaseName, String functionName) {
+ return SLASH.join(
+ V1,
+ prefix,
+ DATABASES,
+ encodeString(databaseName),
+ FUNCTIONS,
+ encodeString(functionName));
}
}
diff --git
a/paimon-api/src/main/java/org/apache/paimon/rest/requests/CreateFunctionRequest.java
b/paimon-api/src/main/java/org/apache/paimon/rest/requests/CreateFunctionRequest.java
index 31c816f835..6700995691 100644
---
a/paimon-api/src/main/java/org/apache/paimon/rest/requests/CreateFunctionRequest.java
+++
b/paimon-api/src/main/java/org/apache/paimon/rest/requests/CreateFunctionRequest.java
@@ -84,8 +84,8 @@ public class CreateFunctionRequest implements RESTRequest {
public CreateFunctionRequest(Function function) {
this.functionName = function.name();
- this.inputParams = function.inputParams();
- this.returnParams = function.returnParams();
+ this.inputParams = function.inputParams().orElse(null);
+ this.returnParams = function.returnParams().orElse(null);
this.deterministic = function.isDeterministic();
this.definitions = function.definitions();
this.comment = function.comment();
diff --git
a/paimon-api/src/main/java/org/apache/paimon/rest/responses/GetFunctionResponse.java
b/paimon-api/src/main/java/org/apache/paimon/rest/responses/GetFunctionResponse.java
index 27fce00ef8..22c95cc648 100644
---
a/paimon-api/src/main/java/org/apache/paimon/rest/responses/GetFunctionResponse.java
+++
b/paimon-api/src/main/java/org/apache/paimon/rest/responses/GetFunctionResponse.java
@@ -18,6 +18,7 @@
package org.apache.paimon.rest.responses;
+import org.apache.paimon.catalog.Identifier;
import org.apache.paimon.function.Function;
import org.apache.paimon.function.FunctionDefinition;
import org.apache.paimon.function.FunctionImpl;
@@ -136,10 +137,9 @@ public class GetFunctionResponse extends AuditRESTResponse
{
return options;
}
- public Function toFunction() {
+ public Function toFunction(Identifier identifier) {
return new FunctionImpl(
- uuid,
- functionName,
+ identifier,
inputParams,
returnParams,
deterministic,
diff --git
a/paimon-core/src/main/java/org/apache/paimon/catalog/AbstractCatalog.java
b/paimon-core/src/main/java/org/apache/paimon/catalog/AbstractCatalog.java
index ca1d4f9b52..956efc0440 100644
--- a/paimon-core/src/main/java/org/apache/paimon/catalog/AbstractCatalog.java
+++ b/paimon-core/src/main/java/org/apache/paimon/catalog/AbstractCatalog.java
@@ -525,30 +525,30 @@ public abstract class AbstractCatalog implements Catalog {
throws TableNotExistException {}
@Override
- public List<String> listFunctions() {
+ public List<String> listFunctions(String databaseName) {
return Collections.emptyList();
}
@Override
- public Function getFunction(String functionName) throws
FunctionNotExistException {
- throw new FunctionNotExistException(functionName);
+ public Function getFunction(Identifier identifier) throws
FunctionNotExistException {
+ throw new FunctionNotExistException(identifier);
}
@Override
- public void createFunction(String functionName, Function function, boolean
ignoreIfExists)
- throws FunctionAlreadyExistException {
+ public void createFunction(Identifier identifier, Function function,
boolean ignoreIfExists)
+ throws FunctionAlreadyExistException, DatabaseNotExistException {
throw new UnsupportedOperationException();
}
@Override
- public void dropFunction(String functionName, boolean ignoreIfNotExists)
+ public void dropFunction(Identifier identifier, boolean ignoreIfNotExists)
throws FunctionNotExistException {
throw new UnsupportedOperationException();
}
@Override
public void alterFunction(
- String functionName, List<FunctionChange> changes, boolean
ignoreIfNotExists)
+ Identifier identifier, List<FunctionChange> changes, boolean
ignoreIfNotExists)
throws FunctionNotExistException, DefinitionAlreadyExistException,
DefinitionNotExistException {
throw new UnsupportedOperationException();
diff --git a/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java
b/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java
index b10bce009d..446a93b783 100644
--- a/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java
+++ b/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java
@@ -731,47 +731,59 @@ public interface Catalog extends AutoCloseable {
void alterPartitions(Identifier identifier, List<PartitionStatistics>
partitions)
throws TableNotExistException;
- /** List all functions in catalog. */
- List<String> listFunctions();
+ /**
+ * Get the names of all functions in this catalog.
+ *
+ * @return a list of the names of all functions
+ * @throws DatabaseNotExistException if the database does not exist
+ */
+ List<String> listFunctions(String databaseName) throws
DatabaseNotExistException;
/**
* Get function by name.
*
- * @param functionName
- * @throws FunctionNotExistException
+ * @param identifier Path of the function to get
+ * @return The requested function
+ * @throws FunctionNotExistException if the function does not exist
*/
- Function getFunction(String functionName) throws FunctionNotExistException;
+ Function getFunction(Identifier identifier) throws
FunctionNotExistException;
/**
- * Create function.
+ * Create a new function.
+ *
+ * <p>NOTE: System functions can not be created.
*
- * @param functionName
- * @param function
- * @param ignoreIfExists
- * @throws FunctionAlreadyExistException
+ * @param identifier path of the function to be created
+ * @param function the function definition
+ * @param ignoreIfExists flag to specify behavior when a function already
exists at the given
+ * path: if set to false, it throws a FunctionAlreadyExistException,
if set to true, do
+ * nothing.
+ * @throws FunctionAlreadyExistException if function already exists and
ignoreIfExists is false
+ * @throws DatabaseNotExistException if the database in identifier doesn't
exist
*/
- void createFunction(String functionName, Function function, boolean
ignoreIfExists)
- throws FunctionAlreadyExistException;
+ void createFunction(Identifier identifier, Function function, boolean
ignoreIfExists)
+ throws FunctionAlreadyExistException, DatabaseNotExistException;
/**
* Drop function.
*
- * @param functionName
+ * @param identifier
* @param ignoreIfNotExists
* @throws FunctionNotExistException
*/
- void dropFunction(String functionName, boolean ignoreIfNotExists)
+ void dropFunction(Identifier identifier, boolean ignoreIfNotExists)
throws FunctionNotExistException;
/**
* Alter function.
*
- * @param functionName
+ * @param identifier
* @param changes
* @param ignoreIfNotExists
* @throws FunctionNotExistException
*/
- void alterFunction(String functionName, List<FunctionChange> changes,
boolean ignoreIfNotExists)
+ void alterFunction(
+ Identifier identifier, List<FunctionChange> changes, boolean
ignoreIfNotExists)
throws FunctionNotExistException, DefinitionAlreadyExistException,
DefinitionNotExistException;
@@ -1211,19 +1223,19 @@ public interface Catalog extends AutoCloseable {
private static final String MSG = "Function %s already exists.";
- private final String functionName;
+ private final Identifier identifier;
- public FunctionAlreadyExistException(String functionName) {
- this(functionName, null);
+ public FunctionAlreadyExistException(Identifier identifier) {
+ this(identifier, null);
}
- public FunctionAlreadyExistException(String functionName, Throwable
cause) {
- super(String.format(MSG, functionName), cause);
- this.functionName = functionName;
+ public FunctionAlreadyExistException(Identifier identifier, Throwable
cause) {
+ super(String.format(MSG, identifier.getFullName()), cause);
+ this.identifier = identifier;
}
- public String functionName() {
- return functionName;
+ public Identifier identifier() {
+ return identifier;
}
}
@@ -1232,19 +1244,19 @@ public interface Catalog extends AutoCloseable {
private static final String MSG = "Function %s doesn't exist.";
- private final String functionName;
+ private final Identifier identifier;
- public FunctionNotExistException(String functionName) {
- this(functionName, null);
+ public FunctionNotExistException(Identifier identifier) {
+ this(identifier, null);
}
- public FunctionNotExistException(String functionName, Throwable cause)
{
- super(String.format(MSG, functionName), cause);
- this.functionName = functionName;
+ public FunctionNotExistException(Identifier identifier, Throwable
cause) {
+ super(String.format(MSG, identifier), cause);
+ this.identifier = identifier;
}
- public String functionName() {
- return functionName;
+ public Identifier identifier() {
+ return identifier;
}
}
@@ -1253,21 +1265,22 @@ public interface Catalog extends AutoCloseable {
private static final String MSG = "Definition %s in function %s
already exists.";
- private final String functionName;
+ private final Identifier identifier;
private final String name;
- public DefinitionAlreadyExistException(String functionName, String
name) {
- this(functionName, name, null);
+ public DefinitionAlreadyExistException(Identifier identifier, String
name) {
+ this(identifier, name, null);
}
- public DefinitionAlreadyExistException(String functionName, String
name, Throwable cause) {
- super(String.format(MSG, name, functionName), cause);
- this.functionName = functionName;
+ public DefinitionAlreadyExistException(
+ Identifier identifier, String name, Throwable cause) {
+ super(String.format(MSG, name, identifier.getFullName()), cause);
+ this.identifier = identifier;
this.name = name;
}
- public String functionName() {
- return functionName;
+ public Identifier identifier() {
+ return identifier;
}
public String name() {
@@ -1280,21 +1293,21 @@ public interface Catalog extends AutoCloseable {
private static final String MSG = "Definition %s in function %s
doesn't exist.";
- private final String functionName;
+ private final Identifier identifier;
private final String name;
- public DefinitionNotExistException(String functionName, String name) {
- this(functionName, name, null);
+ public DefinitionNotExistException(Identifier identifier, String name)
{
+ this(identifier, name, null);
}
- public DefinitionNotExistException(String functionName, String name,
Throwable cause) {
- super(String.format(MSG, name, functionName), cause);
- this.functionName = functionName;
+ public DefinitionNotExistException(Identifier identifier, String name,
Throwable cause) {
+ super(String.format(MSG, name, identifier.getFullName()), cause);
+ this.identifier = identifier;
this.name = name;
}
- public String functionName() {
- return functionName;
+ public Identifier identifier() {
+ return identifier;
}
public String name() {
diff --git
a/paimon-core/src/main/java/org/apache/paimon/catalog/DelegateCatalog.java
b/paimon-core/src/main/java/org/apache/paimon/catalog/DelegateCatalog.java
index 9438f8ef22..42dfd400b2 100644
--- a/paimon-core/src/main/java/org/apache/paimon/catalog/DelegateCatalog.java
+++ b/paimon-core/src/main/java/org/apache/paimon/catalog/DelegateCatalog.java
@@ -223,33 +223,33 @@ public abstract class DelegateCatalog implements Catalog {
}
@Override
- public List<String> listFunctions() {
- return wrapped.listFunctions();
+ public List<String> listFunctions(String databaseName) throws
DatabaseNotExistException {
+ return wrapped.listFunctions(databaseName);
}
@Override
- public Function getFunction(String functionName) throws
FunctionNotExistException {
- return wrapped.getFunction(functionName);
+ public Function getFunction(Identifier identifier) throws
FunctionNotExistException {
+ return wrapped.getFunction(identifier);
}
@Override
- public void createFunction(String functionName, Function function, boolean
ignoreIfExists)
- throws FunctionAlreadyExistException {
- wrapped.createFunction(functionName, function, ignoreIfExists);
+ public void createFunction(Identifier identifier, Function function,
boolean ignoreIfExists)
+ throws FunctionAlreadyExistException, DatabaseNotExistException {
+ wrapped.createFunction(identifier, function, ignoreIfExists);
}
@Override
- public void dropFunction(String functionName, boolean ignoreIfNotExists)
+ public void dropFunction(Identifier identifier, boolean ignoreIfNotExists)
throws FunctionNotExistException {
- wrapped.dropFunction(functionName, ignoreIfNotExists);
+ wrapped.dropFunction(identifier, ignoreIfNotExists);
}
@Override
public void alterFunction(
- String functionName, List<FunctionChange> changes, boolean
ignoreIfNotExists)
+ Identifier identifier, List<FunctionChange> changes, boolean
ignoreIfNotExists)
throws FunctionNotExistException, DefinitionAlreadyExistException,
DefinitionNotExistException {
- wrapped.alterFunction(functionName, changes, ignoreIfNotExists);
+ wrapped.alterFunction(identifier, changes, ignoreIfNotExists);
}
@Override
diff --git a/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java
b/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java
index d1b06c8569..2fabf3deee 100644
--- a/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java
+++ b/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java
@@ -626,65 +626,71 @@ public class RESTCatalog implements Catalog {
}
@Override
- public List<String> listFunctions() {
- return api.listFunctions();
+ public List<String> listFunctions(String databaseName) throws
DatabaseNotExistException {
+ try {
+ return api.listFunctions(databaseName);
+ } catch (NoSuchResourceException e) {
+ throw new DatabaseNotExistException(databaseName, e);
+ }
}
@Override
- public org.apache.paimon.function.Function getFunction(String functionName)
+ public org.apache.paimon.function.Function getFunction(Identifier
identifier)
throws FunctionNotExistException {
try {
- GetFunctionResponse response = api.getFunction(functionName);
- return response.toFunction();
+ GetFunctionResponse response = api.getFunction(identifier);
+ return response.toFunction(identifier);
} catch (NoSuchResourceException e) {
- throw new FunctionNotExistException(functionName, e);
+ throw new FunctionNotExistException(identifier, e);
}
}
@Override
public void createFunction(
- String functionName,
+ Identifier identifier,
org.apache.paimon.function.Function function,
boolean ignoreIfExists)
- throws FunctionAlreadyExistException {
+ throws FunctionAlreadyExistException, DatabaseNotExistException {
try {
- api.createFunction(function);
+ api.createFunction(identifier, function);
+ } catch (NoSuchResourceException e) {
+ throw new DatabaseNotExistException(identifier.getDatabaseName(),
e);
} catch (AlreadyExistsException e) {
if (ignoreIfExists) {
return;
}
- throw new FunctionAlreadyExistException(functionName, e);
+ throw new FunctionAlreadyExistException(identifier, e);
}
}
@Override
- public void dropFunction(String functionName, boolean ignoreIfNotExists)
+ public void dropFunction(Identifier identifier, boolean ignoreIfNotExists)
throws FunctionNotExistException {
try {
- api.dropFunction(functionName);
+ api.dropFunction(identifier);
} catch (NoSuchResourceException e) {
if (ignoreIfNotExists) {
return;
}
- throw new FunctionNotExistException(functionName, e);
+ throw new FunctionNotExistException(identifier, e);
}
}
@Override
public void alterFunction(
- String functionName, List<FunctionChange> changes, boolean
ignoreIfNotExists)
+ Identifier identifier, List<FunctionChange> changes, boolean
ignoreIfNotExists)
throws FunctionNotExistException, DefinitionAlreadyExistException,
DefinitionNotExistException {
try {
- api.alterFunction(functionName, changes);
+ api.alterFunction(identifier, changes);
} catch (AlreadyExistsException e) {
- throw new DefinitionAlreadyExistException(functionName,
e.resourceName());
+ throw new DefinitionAlreadyExistException(identifier,
e.resourceName());
} catch (NoSuchResourceException e) {
if (StringUtils.equals(e.resourceType(),
ErrorResponse.RESOURCE_TYPE_DEFINITION)) {
- throw new DefinitionNotExistException(functionName,
e.resourceName());
+ throw new DefinitionNotExistException(identifier,
e.resourceName());
}
if (!ignoreIfNotExists) {
- throw new FunctionNotExistException(functionName);
+ throw new FunctionNotExistException(identifier, e);
}
} catch (BadRequestException e) {
throw new IllegalArgumentException(e.getMessage());
diff --git
a/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java
b/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java
index 0bf9a17920..acb7a8ff56 100644
--- a/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java
+++ b/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java
@@ -286,12 +286,12 @@ public class MockRESTMessage {
}
public static GetFunctionResponse getFunctionResponse() {
- Function function = function("function");
+ Function function = function(Identifier.create(databaseName(),
"function"));
return new GetFunctionResponse(
- function.uuid(),
+ UUID.randomUUID().toString(),
function.name(),
- function.inputParams(),
- function.returnParams(),
+ function.inputParams().orElse(null),
+ function.returnParams().orElse(null),
function.isDeterministic(),
function.definitions(),
function.comment(),
@@ -304,18 +304,18 @@ public class MockRESTMessage {
}
public static CreateFunctionRequest createFunctionRequest() {
- Function function = function("function");
+ Function function = function(Identifier.create(databaseName(),
"function"));
return new CreateFunctionRequest(
function.name(),
- function.inputParams(),
- function.returnParams(),
+ function.inputParams().orElse(null),
+ function.returnParams().orElse(null),
function.isDeterministic(),
function.definitions(),
function.comment(),
function.options());
}
- public static Function function(String functionName) {
+ public static Function function(Identifier identifier) {
List<DataField> inputParams =
Lists.newArrayList(
new DataField(0, "length", DataTypes.DOUBLE()),
@@ -334,8 +334,7 @@ public class MockRESTMessage {
definitions.put("spark", sparkFunction);
definitions.put("trino", trinoFunction);
return new FunctionImpl(
- UUID.randomUUID().toString(),
- functionName,
+ identifier,
inputParams,
returnParams,
false,
diff --git
a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogServer.java
b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogServer.java
index ce31cdecb1..69a512f624 100644
--- a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogServer.java
+++ b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogServer.java
@@ -137,7 +137,6 @@ public class RESTCatalogServer {
public static final String AUTHORIZATION_HEADER_KEY = "Authorization";
private final String databaseUri;
- private final String functionUri;
private final FileSystemCatalog catalog;
private final MockWebServer server;
@@ -165,7 +164,6 @@ public class RESTCatalogServer {
this.configResponse.getDefaults().get(RESTCatalogInternalOptions.PREFIX.key());
this.resourcePaths = new ResourcePaths(prefix);
this.databaseUri = resourcePaths.databases();
- this.functionUri = resourcePaths.functions();
Options conf = new Options();
this.configResponse.getDefaults().forEach(conf::setString);
conf.setString(WAREHOUSE.key(), dataPath);
@@ -276,11 +274,6 @@ public class RESTCatalogServer {
} else if (databaseUri.equals(request.getPath())
|| request.getPath().contains(databaseUri + "?")) {
return databasesApiHandler(restAuthParameter.method(),
data, parameters);
- } else if (functionUri.equals(request.getPath())) {
- return functionsApiHandler(restAuthParameter.method(),
data, parameters);
- } else if (request.getPath().startsWith(functionUri)) {
- return functionApiHandler(
- request.getPath(), restAuthParameter.method(),
data, parameters);
} else if
(resourcePaths.renameTable().equals(request.getPath())) {
return renameTableHandle(restAuthParameter.data());
} else if
(resourcePaths.renameView().equals(request.getPath())) {
@@ -301,6 +294,10 @@ public class RESTCatalogServer {
if (!databaseStore.containsKey(databaseName)) {
throw new
Catalog.DatabaseNotExistException(databaseName);
}
+ boolean isFunctions =
+ resources.length == 2 &&
resources[1].startsWith("functions");
+ boolean isFunction =
+ resources.length == 3 &&
resources[1].startsWith("functions");
boolean isViews = resources.length == 2 &&
resources[1].startsWith("views");
boolean isViewsDetails =
resources.length == 2 &&
resources[1].startsWith("view-details");
@@ -435,6 +432,12 @@ public class RESTCatalogServer {
parameters);
} else if (isTableDetails) {
return tableDetailsHandle(parameters,
databaseName);
+ } else if (isFunctions) {
+ return functionsApiHandler(
+ databaseName, restAuthParameter.method(),
data, parameters);
+ } else if (isFunction) {
+ return functionApiHandler(
+ identifier, restAuthParameter.method(),
data, parameters);
} else if (isViews) {
return viewsHandle(
restAuthParameter.method(),
@@ -524,8 +527,8 @@ public class RESTCatalogServer {
} catch (Catalog.FunctionAlreadyExistException e) {
response =
new ErrorResponse(
- ErrorResponse.RESOURCE_TYPE_COLUMN,
- e.functionName(),
+ ErrorResponse.RESOURCE_TYPE_DEFINITION,
+ e.identifier().getObjectName(),
e.getMessage(),
409);
return mockResponse(response, 409);
@@ -533,7 +536,7 @@ public class RESTCatalogServer {
response =
new ErrorResponse(
ErrorResponse.RESOURCE_TYPE_DEFINITION,
- e.functionName(),
+ e.name(),
e.getMessage(),
409);
return mockResponse(response, 409);
@@ -557,7 +560,7 @@ public class RESTCatalogServer {
response =
new ErrorResponse(
ErrorResponse.RESOURCE_TYPE_FUNCTION,
- e.functionName(),
+ e.identifier().getObjectName(),
e.getMessage(),
404);
return mockResponse(response, 404);
@@ -565,7 +568,7 @@ public class RESTCatalogServer {
response =
new ErrorResponse(
ErrorResponse.RESOURCE_TYPE_DEFINITION,
- e.functionName(),
+ e.name(),
e.getMessage(),
404);
return mockResponse(response, 404);
@@ -763,32 +766,9 @@ public class RESTCatalogServer {
}
}
- private MockResponse functionDetailsHandler(String functionName) throws
Exception {
- if (functionStore.containsKey(functionName)) {
- Function function = functionStore.get(functionName);
- GetFunctionResponse response =
- new GetFunctionResponse(
- function.uuid(),
- function.name(),
- function.inputParams(),
- function.returnParams(),
- function.isDeterministic(),
- function.definitions(),
- function.comment(),
- function.options(),
- "owner",
- 1L,
- "owner",
- 1L,
- "owner");
- return mockResponse(response, 200);
- } else {
- throw new Catalog.FunctionNotExistException(functionName);
- }
- }
-
private MockResponse functionsApiHandler(
- String method, String data, Map<String, String> parameters) throws
Exception {
+ String databaseName, String method, String data, Map<String,
String> parameters)
+ throws Exception {
switch (method) {
case "GET":
List<String> functions = new
ArrayList<>(functionStore.keySet());
@@ -800,8 +780,7 @@ public class RESTCatalogServer {
if (!functionStore.containsKey(functionName)) {
Function function =
new FunctionImpl(
- UUID.randomUUID().toString(),
- functionName,
+ Identifier.create(databaseName,
functionName),
requestBody.inputParams(),
requestBody.returnParams(),
requestBody.isDeterministic(),
@@ -811,7 +790,8 @@ public class RESTCatalogServer {
functionStore.put(functionName, function);
return new MockResponse().setResponseCode(200);
} else {
- throw new
Catalog.FunctionAlreadyExistException(functionName);
+ throw new Catalog.FunctionAlreadyExistException(
+ Identifier.create(databaseName, functionName));
}
default:
return new MockResponse().setResponseCode(404);
@@ -819,12 +799,11 @@ public class RESTCatalogServer {
}
private MockResponse functionApiHandler(
- String path, String method, String data, Map<String, String>
parameters)
+ Identifier identifier, String method, String data, Map<String,
String> parameters)
throws Exception {
- String[] resources = path.substring((functionUri +
"/").length()).split("/");
- String functionName = RESTUtil.decodeString(resources[0]);
+ String functionName = identifier.getObjectName();
if (!functionStore.containsKey(functionName)) {
- throw new Catalog.FunctionNotExistException(functionName);
+ throw new Catalog.FunctionNotExistException(identifier);
}
Function function = functionStore.get(functionName);
switch (method) {
@@ -834,10 +813,10 @@ public class RESTCatalogServer {
case "GET":
GetFunctionResponse response =
new GetFunctionResponse(
- function.uuid(),
+ UUID.randomUUID().toString(),
function.name(),
- function.inputParams(),
- function.returnParams(),
+ function.inputParams().orElse(null),
+ function.returnParams().orElse(null),
function.isDeterministic(),
function.definitions(),
function.comment(),
@@ -873,7 +852,7 @@ public class RESTCatalogServer {
(FunctionChange.AddDefinition) functionChange;
if (function.definition(addDefinition.name()) != null)
{
throw new Catalog.DefinitionAlreadyExistException(
- functionName, addDefinition.name());
+ identifier, addDefinition.name());
}
newDefinitions.put(addDefinition.name(),
addDefinition.definition());
} else if (functionChange instanceof
FunctionChange.UpdateDefinition) {
@@ -884,7 +863,7 @@ public class RESTCatalogServer {
updateDefinition.name(),
updateDefinition.definition());
} else {
throw new Catalog.DefinitionNotExistException(
- functionName, updateDefinition.name());
+ identifier, updateDefinition.name());
}
} else if (functionChange instanceof
FunctionChange.DropDefinition) {
FunctionChange.DropDefinition dropDefinition =
@@ -893,16 +872,15 @@ public class RESTCatalogServer {
newDefinitions.remove(dropDefinition.name());
} else {
throw new Catalog.DefinitionNotExistException(
- functionName, dropDefinition.name());
+ identifier, dropDefinition.name());
}
}
}
function =
new FunctionImpl(
- functionName,
- function.uuid(),
- function.inputParams(),
- function.returnParams(),
+ Identifier.create(null, functionName),
+ function.inputParams().orElse(null),
+ function.returnParams().orElse(null),
function.isDeterministic(),
newDefinitions,
newComment,
diff --git
a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java
b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java
index ad5d5ed1ea..8657e220e9 100644
--- a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java
+++ b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java
@@ -1549,86 +1549,90 @@ public abstract class RESTCatalogTest extends
CatalogTestBase {
@Test
void testFunction() throws Exception {
- Function function = MockRESTMessage.function("function");
+ Identifier identifier = new Identifier("rest_catalog_db", "function");
+ catalog.createDatabase(identifier.getDatabaseName(), false);
+ Function function = MockRESTMessage.function(identifier);
- catalog.createFunction(function.name(), function, true);
+ catalog.createFunction(identifier, function, true);
assertThrows(
Catalog.FunctionAlreadyExistException.class,
- () -> catalog.createFunction(function.name(), function,
false));
+ () -> catalog.createFunction(identifier, function, false));
- assertThat(catalog.listFunctions().contains(function.name())).isTrue();
+
assertThat(catalog.listFunctions(identifier.getDatabaseName()).contains(function.name()))
+ .isTrue();
- Function getFunction = catalog.getFunction(function.name());
+ Function getFunction = catalog.getFunction(identifier);
assertThat(getFunction.name()).isEqualTo(function.name());
for (String dialect : function.definitions().keySet()) {
assertThat(getFunction.definition(dialect)).isEqualTo(function.definition(dialect));
}
- catalog.dropFunction(function.name(), true);
+ catalog.dropFunction(identifier, true);
-
assertThat(catalog.listFunctions().contains(function.name())).isFalse();
+
assertThat(catalog.listFunctions(identifier.getDatabaseName()).contains(function.name()))
+ .isFalse();
assertThrows(
Catalog.FunctionNotExistException.class,
- () -> catalog.dropFunction(function.name(), false));
+ () -> catalog.dropFunction(identifier, false));
assertThrows(
- Catalog.FunctionNotExistException.class,
- () -> catalog.getFunction(function.name()));
+ Catalog.FunctionNotExistException.class, () ->
catalog.getFunction(identifier));
}
@Test
void testAlterFunction() throws Exception {
- String functionName = "alter_function_name";
- Function function = MockRESTMessage.function(functionName);
+ Identifier identifier = new Identifier("rest_catalog_db",
"alter_function_name");
+ catalog.createDatabase(identifier.getDatabaseName(), false);
+ Function function = MockRESTMessage.function(identifier);
FunctionDefinition definition = FunctionDefinition.sql("x * y + 1");
FunctionChange.AddDefinition addDefinition =
(FunctionChange.AddDefinition)
FunctionChange.addDefinition("flink_1", definition);
assertDoesNotThrow(
- () -> catalog.alterFunction(functionName,
ImmutableList.of(addDefinition), true));
+ () -> catalog.alterFunction(identifier,
ImmutableList.of(addDefinition), true));
assertThrows(
Catalog.FunctionNotExistException.class,
- () -> catalog.alterFunction(functionName,
ImmutableList.of(addDefinition), false));
- catalog.createFunction(function.name(), function, true);
+ () -> catalog.alterFunction(identifier,
ImmutableList.of(addDefinition), false));
+ catalog.createFunction(identifier, function, true);
// set options
String key = UUID.randomUUID().toString();
String value = UUID.randomUUID().toString();
FunctionChange setOption = FunctionChange.setOption(key, value);
- catalog.alterFunction(functionName, ImmutableList.of(setOption),
false);
- Function catalogFunction = catalog.getFunction(functionName);
+ catalog.alterFunction(identifier, ImmutableList.of(setOption), false);
+ Function catalogFunction = catalog.getFunction(identifier);
assertThat(catalogFunction.options().get(key)).isEqualTo(value);
// remove options
catalog.alterFunction(
- functionName,
ImmutableList.of(FunctionChange.removeOption(key)), false);
- catalogFunction = catalog.getFunction(functionName);
+ identifier,
ImmutableList.of(FunctionChange.removeOption(key)), false);
+ catalogFunction = catalog.getFunction(identifier);
assertThat(catalogFunction.options().containsKey(key)).isEqualTo(false);
// update comment
String newComment = "new comment";
catalog.alterFunction(
- functionName,
ImmutableList.of(FunctionChange.updateComment(newComment)), false);
- catalogFunction = catalog.getFunction(functionName);
+ identifier,
ImmutableList.of(FunctionChange.updateComment(newComment)), false);
+ catalogFunction = catalog.getFunction(identifier);
assertThat(catalogFunction.comment()).isEqualTo(newComment);
// add definition
- catalog.alterFunction(functionName, ImmutableList.of(addDefinition),
false);
- catalogFunction = catalog.getFunction(functionName);
+ catalog.alterFunction(identifier, ImmutableList.of(addDefinition),
false);
+ catalogFunction = catalog.getFunction(identifier);
assertThat(catalogFunction.definition(addDefinition.name()))
.isEqualTo(addDefinition.definition());
assertThrows(
Catalog.DefinitionAlreadyExistException.class,
- () -> catalog.alterFunction(functionName,
ImmutableList.of(addDefinition), false));
+ () -> catalog.alterFunction(identifier,
ImmutableList.of(addDefinition), false));
// update definition
FunctionChange.UpdateDefinition updateDefinition =
(FunctionChange.UpdateDefinition)
FunctionChange.updateDefinition("flink_1", definition);
- catalog.alterFunction(functionName,
ImmutableList.of(updateDefinition), false);
- catalogFunction = catalog.getFunction(functionName);
+ catalog.alterFunction(identifier, ImmutableList.of(updateDefinition),
false);
+ catalogFunction = catalog.getFunction(identifier);
assertThat(catalogFunction.definition(updateDefinition.name()))
.isEqualTo(updateDefinition.definition());
assertThrows(
Catalog.DefinitionNotExistException.class,
() ->
catalog.alterFunction(
- functionName,
+ identifier,
ImmutableList.of(
FunctionChange.updateDefinition("no_exist", definition)),
false));
@@ -1637,13 +1641,13 @@ public abstract class RESTCatalogTest extends
CatalogTestBase {
FunctionChange.DropDefinition dropDefinition =
(FunctionChange.DropDefinition)
FunctionChange.dropDefinition(updateDefinition.name());
- catalog.alterFunction(functionName, ImmutableList.of(dropDefinition),
false);
- catalogFunction = catalog.getFunction(functionName);
+ catalog.alterFunction(identifier, ImmutableList.of(dropDefinition),
false);
+ catalogFunction = catalog.getFunction(identifier);
assertThat(catalogFunction.definition(updateDefinition.name())).isNull();
assertThrows(
Catalog.DefinitionNotExistException.class,
- () -> catalog.alterFunction(functionName,
ImmutableList.of(dropDefinition), false));
+ () -> catalog.alterFunction(identifier,
ImmutableList.of(dropDefinition), false));
}
@Test