From 0af2540dc30340742506b3c61850f1e2d25f4d72 Mon Sep 17 00:00:00 2001 From: Feng Jin Date: Mon, 26 Feb 2024 19:25:43 +0800 Subject: [PATCH] [FLINK-34265][doc] Add the doc of named parameters (#24377) --- .../docs/dev/table/functions/udfs.md | 139 +++++++++++++++++ docs/content.zh/docs/dev/table/procedures.md | 146 ++++++++++++++++++ docs/content/docs/dev/table/functions/udfs.md | 137 ++++++++++++++++ docs/content/docs/dev/table/procedures.md | 144 +++++++++++++++++ 4 files changed, 566 insertions(+) diff --git a/docs/content.zh/docs/dev/table/functions/udfs.md b/docs/content.zh/docs/dev/table/functions/udfs.md index 5527cfcb978c3..f137b2ba4466e 100644 --- a/docs/content.zh/docs/dev/table/functions/udfs.md +++ b/docs/content.zh/docs/dev/table/functions/udfs.md @@ -77,6 +77,9 @@ env.from("MyTable").select(call("SubstringFunction", $("myField"), 5, 12)); // 在 SQL 里调用注册好的函数 env.sqlQuery("SELECT SubstringFunction(myField, 5, 12) FROM MyTable"); +// 在 SQL 里使用命名参数调用注册好的函数 +env.sqlQuery("SELECT SubstringFunction(param1 => myField, param2 => 5, param3 => 12) FROM MyTable"); + ``` {{< /tab >}} {{< tab "Scala" >}} @@ -599,6 +602,142 @@ public static class LiteralFunction extends ScalarFunction { For more examples of custom type inference, see also the `flink-examples-table` module with {{< gh_link file="flink-examples/flink-examples-table/src/main/java/org/apache/flink/table/examples/java/functions/AdvancedFunctionsExample.java" name="advanced function implementation" >}}. +### 命名参数 + +在调用函数时,可以使用参数名称来指定参数值。命名参数允许同时传递参数名和值给函数,避免了因为错误的参数顺序而导致混淆,并提高了代码的可读性和可维护性。 此外,命名参数还可以省略非必需的参数,默认情况下会使用 `null` 进行填充。 +我们可以通过 `@ArgumentHint` 注解来指定参数的名称,类型,是否是必需的参数等。 + +**`@ArgumentHint`** + +下面三个示例展示了如何在不同的范围内使用 `@ArgumentHint`。更多信息请参考注解类的文档。 + +1. 在 function 的 `eval` 方法的参数上使用 `@ArgumentHint` 注解。 + +{{< tabs "8064df87-eb42-4def-9bd2-0988fc246d37" >}} +{{< tab "Java" >}} + +```java +import com.sun.tracing.dtrace.ArgsAttributes; +import org.apache.flink.table.annotation.ArgumentHint; +import org.apache.flink.table.functions.ScalarFunction; + +public static class NamedParameterClass extends ScalarFunction { + + // 使用 @ArgumentHint 注解指定参数的名称,参数类型,以及是否是必需的参数 + public String eval(@ArgumentHint(name = "param1", isOptional = false, type = @DataTypeHint("STRING")) String s1, + @ArgumentHint(name = "param2", isOptional = true, type = @DataTypeHint("INT")) Integer s2) { + return s1 + ", " + s2; + } +} + +``` +{{< /tab >}} +{{< tab "Scala" >}} +```scala +import org.apache.flink.table.annotation.ArgumentHint; +import org.apache.flink.table.functions.ScalarFunction; + +class NamedParameterClass extends ScalarFunction { + + // 使用 @ArgumentHint 注解指定参数的名称,参数类型,以及是否是必需的参数 + def eval(@ArgumentHint(name = "param1", isOptional = false, `type` = @DataTypeHint("STRING")) s1: String, + @ArgumentHint(name = "param2", isOptional = true, `type` = @DataTypeHint("INTEGER")) s2: Integer) = { + s1 + ", " + s2 + } +} +``` +{{< /tab >}} +{{< /tabs >}} + +2. 在 function 的 `eval` 方法上使用 `@ArgumentHint` 注解。 + +{{< tabs "1356086c-189c-4932-a797-badf5b5e27ab" >}} +{{< tab "Java" >}} +```java +import org.apache.flink.table.annotation.ArgumentHint; +import org.apache.flink.table.functions.ScalarFunction; + +public static class NamedParameterClass extends ScalarFunction { + + // 使用 @ArgumentHint 注解指定参数的名称,参数类型,以及该参数是否是必需的参数 + @FunctionHint( + argument = {@ArgumentHint(name = "param1", isOptional = false, type = @DataTypeHint("STRING")), + @ArgumentHint(name = "param2", isOptional = true, type = @DataTypeHint("INTEGER"))} + ) + public String eval(String s1, Integer s2) { + return s1 + ", " + s2; + } +} +``` +{{< /tab >}} +{{< tab "Scala" >}} +```scala +import org.apache.flink.table.annotation.ArgumentHint; +import org.apache.flink.table.functions.ScalarFunction; + +class NamedParameterClass extends ScalarFunction { + + // 使用 @ArgumentHint 注解指定参数的名称,参数类型,以及是否是必需的参数 + @FunctionHint( + argument = Array(new ArgumentHint(name = "param1", isOptional = false, `type` = new DataTypeHint("STRING")), + new ArgumentHint(name = "param2", isOptional = true, `type` = new DataTypeHint("INTEGER"))) + ) + def eval(s1: String, s2: Int): String = { + s1 + ", " + s2 + } +} +``` +{{< /tab >}} +{{< /tabs >}} + +3. 在 function 的 class 上使用 `@ArgumentHint` 注解。 + +{{< tabs "ba00146a-08bf-496c-89bc-8d5e333f04f7" >}} +{{< tab "Java" >}} +```java +import org.apache.flink.table.annotation.ArgumentHint; +import org.apache.flink.table.functions.ScalarFunction; + +// 使用 @ArgumentHint 注解指定参数的名称,参数类型,以及是否是必需的参数 +@FunctionHint( + argument = {@ArgumentHint(name = "param1", isOptional = false, type = @DataTypeHint("STRING")), + @ArgumentHint(name = "param2", isOptional = true, type = @DataTypeHint("INTEGER"))} +) +public static class NamedParameterClass extends ScalarFunction { + + public String eval(String s1, Integer s2) { + return s1 + ", " + s2; + } +} +``` +{{< /tab >}} +{{< tab "Scala" >}} +```scala +import org.apache.flink.table.annotation.ArgumentHint; +import org.apache.flink.table.functions.ScalarFunction; + +// 使用 @ArgumentHint 注解指定参数的名称,参数类型,以及是否是必需的参数 +@FunctionHint( + argument = Array(new ArgumentHint(name = "param1", isOptional = false, `type` = new DataTypeHint("STRING")), + new ArgumentHint(name = "param2", isOptional = true, `type` = new DataTypeHint("INTEGER"))) +) +class NamedParameterClass extends ScalarFunction { + + // 使用 @ArgumentHint 注解指定参数的名称,参数类型,以及是否是必需的参数 + def eval(s1: String, s2: Int): String = { + s1 + ", " + s2 + } +} +``` +{{< /tab >}} +{{< /tabs >}} + + +{{< hint info >}} +* `@ArgumentHint` 内部包含了 `@DataTypeHint` 注解,因此在 `@FunctionHint` 中不能同时声明 `input` 和 `argument` ,当作用于函数的参数时 `@ArgumentHint` 也不能和 `@DataTypeHint` 同时使用,推荐使用 `@ArgumentHint` 。 +* 命名参数只有在对应的类不包含重载函数和可变参函数才会生效,否则使用命名参数会导致报错。 +{{< /hint >}} + ### 确定性 每个用户自定义函数类都可以通过重写 `isDeterministic()` 方法来声明它是否产生确定性的结果。如果该函数不是纯粹函数式的(如`random()`, `date()`, 或`now()`),该方法必须返回 `false`。默认情况下,`isDeterministic()` 返回 `true`。 diff --git a/docs/content.zh/docs/dev/table/procedures.md b/docs/content.zh/docs/dev/table/procedures.md index cb70d759ebcb4..d7efa89b31fe8 100644 --- a/docs/content.zh/docs/dev/table/procedures.md +++ b/docs/content.zh/docs/dev/table/procedures.md @@ -338,6 +338,152 @@ class OverloadedProcedure extends Procedure { {{< /tab >}} {{< /tabs >}} +### 命名参数 + +在调用存储过程时,可以使用参数名称来指定参数值。命名参数允许同时传递参数名和值给存储过程,避免了因为错误的参数顺序而导致混淆,并提高了代码的可读性和可维护性。 此外,命名参数还可以省略非必需的参数,默认情况下会使用 `null` 进行填充。 +我们可以通过 `@ArgumentHint` 注解来指定参数的名称,类型,是否是必需的参数等。 + +下面三个示例展示了如何在不同的范围内使用 `@ArgumentHint`。更多信息请参考注解类的文档。 + +1. 在存储过程的 `call` 方法的参数上使用 `@ArgumentHint` 注解。 + +{{< tabs "d2132879-26dc-45ba-8daa-365733a738e0" >}} +{{< tab "Java" >}} +```java +import org.apache.flink.table.annotation.DataTypeHint; +import org.apache.flink.table.annotation.ProcedureHint; +import org.apache.flink.table.procedure.ProcedureContext; +import org.apache.flink.table.procedures.Procedure; +import org.apache.flink.types.Row; + +public static class NamedParameterProcedure extends Procedure { + + public @DataTypeHint("INT") Integer[] call(ProcedureContext context, @ArgumentHint(name = "a", isOption = true) Integer a, @ArgumentHint(name = "b") Integer b) { + return new Integer[] {a + (b == null ? 0 : b)}; + } +} +``` +{{< /tab >}} +{{< tab "Scala" >}} +```scala + +import org.apache.flink.table.annotation.DataTypeHint +import org.apache.flink.table.annotation.ProcedureHint +import org.apache.flink.table.procedure.ProcedureContext +import org.apache.flink.table.procedures.Procedure +import org.apache.flink.types.Row +import scala.annotation.varargs + +class NamedParameterProcedure extends Procedure { + + def call(context: ProcedureContext, @ArgumentHint(name = "param1", isOptional = true) a: Integer, @ArgumentHint(name = "param2") b: Integer): Array[Integer] = { + Array(a + (if (b == null) 0 else b)) + } +} +``` +{{< /tab >}} +{{< /tabs >}} + +2. 在存储过程的 `call` 方法上使用 `@ArgumentHint` 注解。 + +{{< tabs "5c682030-fdbd-485c-9961-b402971e14d4" >}} +{{< tab "Java" >}} +```java +import org.apache.flink.table.annotation.DataTypeHint; +import org.apache.flink.table.annotation.ProcedureHint; +import org.apache.flink.table.procedure.ProcedureContext; +import org.apache.flink.table.procedures.Procedure; +import org.apache.flink.types.Row; + +public static class NamedParameterProcedure extends Procedure { + + @ProcedureHint( + argument = {@ArgumentHint(name = "param1", type = @DataTypeHint("INTEGER"), isOptional = false), + @ArgumentHint(name = "param2", type = @DataTypeHint("INTEGER"), isOptional = true)} + ) + public @DataTypeHint("INT") Integer[] call(ProcedureContext context, Integer a, Integer b) { + return new Integer[] {a + (b == null ? 0 : b)}; + } +} +``` +{{< /tab >}} +{{< tab "Scala" >}} +```scala + +import org.apache.flink.table.annotation.DataTypeHint +import org.apache.flink.table.annotation.ProcedureHint +import org.apache.flink.table.procedure.ProcedureContext +import org.apache.flink.table.procedures.Procedure +import org.apache.flink.types.Row +import scala.annotation.varargs + +class NamedParameterProcedure extends Procedure { + @ProcedureHint( + argument = Array( + new ArgumentHint(name = "param1", `type` = new DataTypeHint("INTEGER"), isOptional = false), + new ArgumentHint(name = "param2", `type` = new DataTypeHint("INTEGER"), isOptional = true) + ) + ) + def call(context: ProcedureContext, a: Integer, b: Integer): Array[Integer] = { + Array(a + (if (b == null) 0 else b)) + } +} +``` +{{< /tab >}} +{{< /tabs >}} + +3. 在存储过程的 class 上使用 `@ArgumentHint` 注解。 + +{{< tabs "64db1ce1-1251-4cc4-a7d8-13b5664f9019" >}} +{{< tab "Java" >}} +```java +import org.apache.flink.table.annotation.DataTypeHint; +import org.apache.flink.table.annotation.ProcedureHint; +import org.apache.flink.table.procedure.ProcedureContext; +import org.apache.flink.table.procedures.Procedure; +import org.apache.flink.types.Row; + +@ProcedureHint( + argument = {@ArgumentHint(name = "param1", type = @DataTypeHint("INTEGER"), isOptional = false), + @ArgumentHint(name = "param2", type = @DataTypeHint("INTEGER"), isOptional = true)} +) +public static class NamedParameterProcedure extends Procedure { + + public @DataTypeHint("INT") Integer[] call(ProcedureContext context, Integer a, Integer b) { + return new Integer[] {a + (b == null ? 0 : b)}; + } +} +``` +{{< /tab >}} +{{< tab "Scala" >}} +```scala + +import org.apache.flink.table.annotation.DataTypeHint +import org.apache.flink.table.annotation.ProcedureHint +import org.apache.flink.table.procedure.ProcedureContext +import org.apache.flink.table.procedures.Procedure +import org.apache.flink.types.Row +import scala.annotation.varargs + +@ProcedureHint( + argument = Array( + new ArgumentHint(name = "param1", `type` = new DataTypeHint("INTEGER"), isOptional = false), + new ArgumentHint(name = "param2", `type` = new DataTypeHint("INTEGER"), isOptional = true) + ) +) +class NamedParameterProcedure extends Procedure { + def call(context: ProcedureContext, a: Integer, b: Integer): Array[Integer] = { + Array(a + (if (b == null) 0 else b)) + } +} +``` +{{< /tab >}} +{{< /tabs >}} + +{{< hint info >}} +* `@ArgumentHint` 内部包含了 `@DataTypeHint` 注解,因此在 `@ProcedureHint` 中不能同时声明 `input` 和 `argument`, 当作用于函数的参数时 `@ArgumentHint` 也不能和 `@DataTypeHint` 同时使用,推荐使用 `@ArgumentHint`。 +* 命名参数只有在对应的存储过程类不包含重载函数和可变参函数才会生效, 否则使用命名参数会导致报错。 + {{< /hint >}} ### 在 Catalog 中返回存储过程 在实现了一个存储过程后,Catalog 可以通过方法 `Catalog.getProcedure(ObjectPath procedurePath)` 来返回该存储过程,下面的例子展示了如何在 Catalog 中返回存储过程。 diff --git a/docs/content/docs/dev/table/functions/udfs.md b/docs/content/docs/dev/table/functions/udfs.md index b0c095f26b845..1b8243879410d 100644 --- a/docs/content/docs/dev/table/functions/udfs.md +++ b/docs/content/docs/dev/table/functions/udfs.md @@ -77,6 +77,9 @@ env.from("MyTable").select(call("SubstringFunction", $("myField"), 5, 12)); // call registered function in SQL env.sqlQuery("SELECT SubstringFunction(myField, 5, 12) FROM MyTable"); +// call registered function in SQL using named parameters +env.sqlQuery("SELECT SubstringFunction(param1 => myField, param2 => 5, param3 => 12) FROM MyTable"); + ``` {{< /tab >}} {{< tab "Scala" >}} @@ -610,6 +613,140 @@ public static class LiteralFunction extends ScalarFunction { For more examples of custom type inference, see also the `flink-examples-table` module with {{< gh_link file="/flink-examples/flink-examples-table/src/main/java/org/apache/flink/table/examples/java/functions/AdvancedFunctionsExample.java" name="advanced function implementation" >}}. +### Named Parameters + +When calling a function, you can use parameter names to specify the values of the parameters. Named parameters allow passing both the parameter name and value to a function, avoiding confusion caused by incorrect parameter order and improving code readability and maintainability. In addition, named parameters can also omit optional parameters, which are filled with `null` by default. +We can use the `@ArgumentHint` annotation to specify the name, type, and whether a parameter is required or not. + +**`@ArgumentHint`** + +The following 3 examples demonstrate how to use `@ArgumentHint` in different scopes. More information can be found in the documentation of the annotation class. + +1. Using `@ArgumentHint` annotation on the parameters of the `eval` method of the function. + +{{< tabs "20405d05-739c-4038-a885-3bde5f7998e8" >}} +{{< tab "Java" >}} +```java +import com.sun.tracing.dtrace.ArgsAttributes; +import org.apache.flink.table.annotation.ArgumentHint; +import org.apache.flink.table.functions.ScalarFunction; + +public static class NamedParameterClass extends ScalarFunction { + + // Use the @ArgumentHint annotation to specify the name, type, and whether a parameter is required. + public String eval(@ArgumentHint(name = "param1", isOptional = false, type = @DataTypeHint("STRING")) String s1, + @ArgumentHint(name = "param2", isOptional = true, type = @DataTypeHint("INT")) Integer s2) { + return s1 + ", " + s2; + } +} + +``` +{{< /tab >}} +{{< tab "Scala" >}} +```scala +import org.apache.flink.table.annotation.ArgumentHint; +import org.apache.flink.table.functions.ScalarFunction; + +class NamedParameterClass extends ScalarFunction { + + // Use the @ArgumentHint annotation to specify the name, type, and whether a parameter is required. + def eval(@ArgumentHint(name = "param1", isOptional = false, `type` = @DataTypeHint("STRING")) s1: String, + @ArgumentHint(name = "param2", isOptional = true, `type` = @DataTypeHint("INTEGER")) s2: Integer) = { + s1 + ", " + s2 + } +} +``` +{{< /tab >}} +{{< /tabs >}} + +2. Using `@ArgumentHint` annotation on the `eval` method of the function. + +{{< tabs "dbecd8a8-6285-4bc8-94e0-e79f6ca7f7c3" >}} +{{< tab "Java" >}} +```java +import org.apache.flink.table.annotation.ArgumentHint; +import org.apache.flink.table.functions.ScalarFunction; + +public static class NamedParameterClass extends ScalarFunction { + + // Use the @ArgumentHint annotation to specify the name, type, and whether a parameter is required. + @FunctionHint( + argument = {@ArgumentHint(name = "param1", isOptional = false, type = @DataTypeHint("STRING")), + @ArgumentHint(name = "param2", isOptional = true, type = @DataTypeHint("INTEGER"))} + ) + public String eval(String s1, Integer s2) { + return s1 + ", " + s2; + } +} +``` +{{< /tab >}} +{{< tab "Scala" >}} +```scala +import org.apache.flink.table.annotation.ArgumentHint; +import org.apache.flink.table.functions.ScalarFunction; + +class NamedParameterClass extends ScalarFunction { + + // Use the @ArgumentHint annotation to specify the name, type, and whether a parameter is required. + @FunctionHint( + argument = Array(new ArgumentHint(name = "param1", isOptional = false, `type` = new DataTypeHint("STRING")), + new ArgumentHint(name = "param2", isOptional = true, `type` = new DataTypeHint("INTEGER"))) + ) + def eval(s1: String, s2: Int): String = { + s1 + ", " + s2 + } +} +``` +{{< /tab >}} +{{< /tabs >}} + +3. Using `@ArgumentHint` annotation on the class of the function. + +{{< tabs "924dd007-3827-44ce-83c6-017dea78b9c4" >}} +{{< tab "Java" >}} +```java +import org.apache.flink.table.annotation.ArgumentHint; +import org.apache.flink.table.functions.ScalarFunction; + +// Use the @ArgumentHint annotation to specify the name, type, and whether a parameter is required. +@FunctionHint( + argument = {@ArgumentHint(name = "param1", isOptional = false, type = @DataTypeHint("STRING")), + @ArgumentHint(name = "param2", isOptional = true, type = @DataTypeHint("INTEGER"))} +) +public static class NamedParameterClass extends ScalarFunction { + + public String eval(String s1, Integer s2) { + return s1 + ", " + s2; + } +} +``` +{{< /tab >}} +{{< tab "Scala" >}} +```scala +import org.apache.flink.table.annotation.ArgumentHint; +import org.apache.flink.table.functions.ScalarFunction; + +// Use the @ArgumentHint annotation to specify the name, type, and whether a parameter is required. +@FunctionHint( + argument = Array(new ArgumentHint(name = "param1", isOptional = false, `type` = new DataTypeHint("STRING")), + new ArgumentHint(name = "param2", isOptional = true, `type` = new DataTypeHint("INTEGER"))) +) +class NamedParameterClass extends ScalarFunction { + + def eval(s1: String, s2: Int): String = { + s1 + ", " + s2 + } +} +``` +{{< /tab >}} +{{< /tabs >}} + + +{{< hint info >}} +* `@ArgumentHint` annotation already contains `@DataTypeHint` annotation, so it cannot be used together with `@DataTypeHint` in `@FunctionHint`. When applied to function parameters, `@ArgumentHint` cannot be used with `@DataTypeHint` at the same time, and it is recommended to use `@ArgumentHint`. +* Named parameters only take effect when the corresponding class does not contain overloaded functions and variable parameter functions, otherwise using named parameters will cause an error. +{{< /hint >}} + ### Determinism Every user-defined function class can declare whether it produces deterministic results or not by overriding diff --git a/docs/content/docs/dev/table/procedures.md b/docs/content/docs/dev/table/procedures.md index 0122a0de1918c..fbdbd469121f1 100644 --- a/docs/content/docs/dev/table/procedures.md +++ b/docs/content/docs/dev/table/procedures.md @@ -339,6 +339,150 @@ class OverloadedProcedure extends Procedure { {{< /tab >}} {{< /tabs >}} +### Named Parameters + +When calling a procedure, you can use parameter names to specify parameter values. Named parameters allow you to pass both the parameter name and value to the procedure at the same time, avoiding confusion caused by the wrong parameter order, and improving the readability and maintainability of the code. In addition, named parameters can also omit non-required parameters, which are filled with `null` by default. We can use the `@ArgumentHint` annotation to specify the name, type, and whether the parameter is required. + +The following three examples show how to use `@ArgumentHint` in different scopes. For more information, please refer to the documentation of the annotation class. + +1. Using `@ArgumentHint` annotation on the parameters of the `call` method of the procedure. + +{{< tabs "5d205654-30da-11ee-be56-0242ac120003" >}} +{{< tab "Java" >}} +```java +import org.apache.flink.table.annotation.DataTypeHint; +import org.apache.flink.table.annotation.ProcedureHint; +import org.apache.flink.table.procedure.ProcedureContext; +import org.apache.flink.table.procedures.Procedure; +import org.apache.flink.types.Row; + +public static class NamedParameterProcedure extends Procedure { + + public @DataTypeHint("INT") Integer[] call(ProcedureContext context, @ArgumentHint(name = "a", isOption = true) Integer a, @ArgumentHint(name = "b") Integer b) { + return new Integer[] {a + (b == null ? 0 : b)}; + } +} +``` +{{< /tab >}} +{{< tab "Scala" >}} +```scala + +import org.apache.flink.table.annotation.DataTypeHint +import org.apache.flink.table.annotation.ProcedureHint +import org.apache.flink.table.procedure.ProcedureContext +import org.apache.flink.table.procedures.Procedure +import org.apache.flink.types.Row +import scala.annotation.varargs + +class NamedParameterProcedure extends Procedure { + + def call(context: ProcedureContext, @ArgumentHint(name = "param1", isOptional = true) a: Integer, @ArgumentHint(name = "param2") b: Integer): Array[Integer] = { + Array(a + (if (b == null) 0 else b)) + } +} +``` +{{< /tab >}} +{{< /tabs >}} + +2. Using `@ArgumentHint` annotation on the `call` method of the procedure. +{{< tabs "5d205654-30da-11ee-be56-0242ac120004" >}} +{{< tab "Java" >}} +```java +import org.apache.flink.table.annotation.DataTypeHint; +import org.apache.flink.table.annotation.ProcedureHint; +import org.apache.flink.table.procedure.ProcedureContext; +import org.apache.flink.table.procedures.Procedure; +import org.apache.flink.types.Row; + +public static class NamedParameterProcedure extends Procedure { + + @ProcedureHint( + argument = {@ArgumentHint(name = "param1", type = @DataTypeHint("INTEGER"), isOptional = false), + @ArgumentHint(name = "param2", type = @DataTypeHint("INTEGER"), isOptional = true)} + ) + public @DataTypeHint("INT") Integer[] call(ProcedureContext context, Integer a, Integer b) { + return new Integer[] {a + (b == null ? 0 : b)}; + } +} +``` +{{< /tab >}} +{{< tab "Scala" >}} +```scala + +import org.apache.flink.table.annotation.DataTypeHint +import org.apache.flink.table.annotation.ProcedureHint +import org.apache.flink.table.procedure.ProcedureContext +import org.apache.flink.table.procedures.Procedure +import org.apache.flink.types.Row +import scala.annotation.varargs + +class NamedParameterProcedure extends Procedure { + @ProcedureHint( + argument = Array( + new ArgumentHint(name = "param1", `type` = new DataTypeHint("INTEGER"), isOptional = false), + new ArgumentHint(name = "param2", `type` = new DataTypeHint("INTEGER"), isOptional = true) + ) + ) + def call(context: ProcedureContext, a: Integer, b: Integer): Array[Integer] = { + Array(a + (if (b == null) 0 else b)) + } +} +``` +{{< /tab >}} +{{< /tabs >}} + +3. Using `@ArgumentHint` annotation on the class of the procedure. + +{{< tabs "5d205654-30da-11ee-be56-0242ac120005" >}} +{{< tab "Java" >}} +```java +import org.apache.flink.table.annotation.DataTypeHint; +import org.apache.flink.table.annotation.ProcedureHint; +import org.apache.flink.table.procedure.ProcedureContext; +import org.apache.flink.table.procedures.Procedure; +import org.apache.flink.types.Row; + +@ProcedureHint( + argument = {@ArgumentHint(name = "param1", type = @DataTypeHint("INTEGER"), isOptional = false), + @ArgumentHint(name = "param2", type = @DataTypeHint("INTEGER"), isOptional = true)} +) +public static class NamedParameterProcedure extends Procedure { + + public @DataTypeHint("INT") Integer[] call(ProcedureContext context, Integer a, Integer b) { + return new Integer[] {a + (b == null ? 0 : b)}; + } +} +``` +{{< /tab >}} +{{< tab "Scala" >}} +```scala + +import org.apache.flink.table.annotation.DataTypeHint +import org.apache.flink.table.annotation.ProcedureHint +import org.apache.flink.table.procedure.ProcedureContext +import org.apache.flink.table.procedures.Procedure +import org.apache.flink.types.Row +import scala.annotation.varargs + +@ProcedureHint( + argument = Array( + new ArgumentHint(name = "param1", `type` = new DataTypeHint("INTEGER"), isOptional = false), + new ArgumentHint(name = "param2", `type` = new DataTypeHint("INTEGER"), isOptional = true) + ) +) +class NamedParameterProcedure extends Procedure { + def call(context: ProcedureContext, a: Integer, b: Integer): Array[Integer] = { + Array(a + (if (b == null) 0 else b)) + } +} +``` +{{< /tab >}} +{{< /tabs >}} + +{{< hint info >}} +* `@ArgumentHint` annotation already contains `@DataTypeHint` annotation, so it cannot be used together with `@DataTypeHint` in `@ProcedureHint`. When applied to function parameters, `@ArgumentHint` cannot be used with `@DataTypeHint` at the same time, and it is recommended to use `@ArgumentHint`. +* Named parameters only take effect when the corresponding procedure class does not contain overloaded functions and variable parameter functions, otherwise using named parameters will cause an error. +{{< /hint >}} ### Return Procedure in Catalog After implementing a procedure, the catalog can then return the procedure in method `Catalog.getProcedure(ObjectPath procedurePath)`. The following example shows how to return it in a catalog.