This is an automated email from the ASF dual-hosted git repository.

HTHou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iotdb-docs.git


The following commit(s) were added to refs/heads/main by this push:
     new 25224758 docs: document IoTDBLocal for table UDFs (#1212)
25224758 is described below

commit 25224758eae21804df3f682592fe8130ca8bc2b9
Author: leto-bbq <[email protected]>
AuthorDate: Fri Sep 11 17:43:15 2026 +0800

    docs: document IoTDBLocal for table UDFs (#1212)
---
 src/.vuepress/sidebar/V2.0.x/en-Table.ts           |   2 +-
 src/.vuepress/sidebar/V2.0.x/zh-Table.ts           |   2 +-
 ...function.md => User-defined-function_apache.md} | 182 ++++++++++++++++++++-
 ...function.md => User-defined-function_apache.md} | 182 ++++++++++++++++++++-
 ...function.md => User-defined-function_apache.md} | 182 ++++++++++++++++++++-
 ...function.md => User-defined-function_apache.md} | 182 ++++++++++++++++++++-
 6 files changed, 726 insertions(+), 6 deletions(-)

diff --git a/src/.vuepress/sidebar/V2.0.x/en-Table.ts 
b/src/.vuepress/sidebar/V2.0.x/en-Table.ts
index b81f598b..d2b6e295 100644
--- a/src/.vuepress/sidebar/V2.0.x/en-Table.ts
+++ b/src/.vuepress/sidebar/V2.0.x/en-Table.ts
@@ -115,7 +115,7 @@ export const enSidebar = {
           ],
           badge: ['hot'],
         },
-        { text: 'UDF', link: 'User-defined-function' },
+        { text: 'UDF', link: 'User-defined-function_apache' },
         {
           text: 'Security Management',
           collapsible: true,
diff --git a/src/.vuepress/sidebar/V2.0.x/zh-Table.ts 
b/src/.vuepress/sidebar/V2.0.x/zh-Table.ts
index 58eefe56..72080c11 100644
--- a/src/.vuepress/sidebar/V2.0.x/zh-Table.ts
+++ b/src/.vuepress/sidebar/V2.0.x/zh-Table.ts
@@ -115,7 +115,7 @@ export const zhSidebar = {
           ],
           badge: ['hot'],
         },
-        { text: 'UDF', link: 'User-defined-function' },
+        { text: 'UDF', link: 'User-defined-function_apache' },
         {
           text: '安全管理',
           collapsible: true,
diff --git a/src/UserGuide/Master/Table/User-Manual/User-defined-function.md 
b/src/UserGuide/Master/Table/User-Manual/User-defined-function_apache.md
similarity index 77%
rename from src/UserGuide/Master/Table/User-Manual/User-defined-function.md
rename to src/UserGuide/Master/Table/User-Manual/User-defined-function_apache.md
index 4213a7f9..e3fc7383 100644
--- a/src/UserGuide/Master/Table/User-Manual/User-defined-function.md
+++ b/src/UserGuide/Master/Table/User-Manual/User-defined-function_apache.md
@@ -448,6 +448,186 @@ The result set of a table function consists of two parts:
    * If no pass-through but PARTITION BY is specified: Only partition columns 
are included.
    * If neither is specified: No additional columns are added.
 
-### 3.5 Complete Maven Project Example
+### 3.5 Accessing IoTDB from UDFs
+
+Starting from **V2.0.11**, table-model UDFs can use `IoTDBLocal` to execute 
SQL queries and write logs during data processing. `IoTDBLocal` is supplied by 
the framework. Queries reuse the permissions of the current connection user and 
return streaming result sets. This capability is included in `udf-api`; no 
additional dependency is required.
+
+Existing methods without an `IoTDBLocal` parameter remain available. Implement 
the overloads with an `IoTDBLocal` parameter only when the UDF needs to query 
IoTDB or write logs.
+
+#### 3.5.1 API Reference
+
+`IoTDBLocal` is in the `org.apache.iotdb.udf.api` package and provides the 
following capabilities:
+
+| API | Description |
+|---|---|
+| `UDFResultSet query(String sql) throws UDFException` | Executes SQL and 
returns the query result as a streaming result set. The query uses the current 
connection user's permissions. |
+| `info(...)` | Writes an INFO-level log message. Message arguments and 
exception objects are supported. |
+| `warn(...)` | Writes a WARN-level log message. Message arguments and 
exception objects are supported. |
+| `error(...)` | Writes an ERROR-level log message. Message arguments and 
exception objects are supported. |
+
+The `UDFResultSet` returned by `query` implements `AutoCloseable` and provides 
the following methods for reading rows:
+
+| API | Description |
+|---|---|
+| `boolean hasNext() throws UDFException` | Checks whether another row is 
available. |
+| `Record next() throws UDFException` | Returns the next row. Throws 
`NoSuchElementException` when no more rows are available. |
+| `void close() throws IoTDBLocalException` | Closes the result set and 
releases resources. |
+
+Use try-with-resources to close result sets promptly. Even if a result set is 
not closed manually, the framework releases any result sets that remain open 
after the current UDF execution finishes.
+
+The following table-model UDF methods can receive `IoTDBLocal`:
+
+| UDF type | Supported methods |
+|---|---|
+| Scalar function (UDSF) | `beforeStart`, `evaluate`, `beforeDestroy` |
+| Aggregate function (UDAF) | `beforeStart`, `addInput`, `combineState`, 
`outputFinal`, `beforeDestroy` |
+| Table function (UDTF) | `beforeStart`, `process`, `finish`, and 
`beforeDestroy` of `TableFunctionDataProcessor`; `beforeStart`, `process`, and 
`beforeDestroy` of `TableFunctionLeafProcessor` |
+
+For example, a scalar function can implement the following overloads as needed:
+
+```Java
+default void beforeStart(FunctionArguments arguments, IoTDBLocal local)
+    throws UDFException;
+
+default Object evaluate(Record input, IoTDBLocal local)
+    throws UDFException;
+
+default void beforeDestroy(IoTDBLocal local);
+```
+
+#### 3.5.2 Example
+
+The following example queries device names and temperature limits in 
`beforeStart` and caches the results in memory. If the UDF only needs device 
names, keep the first query. If it needs to combine multiple data sources, call 
`query` multiple times as shown here. For reference data that does not change 
during one UDF execution, query it during initialization instead of executing 
the same SQL for every row in `evaluate`.
+
+1. Create the sample tables and insert data.
+
+```SQL
+CREATE TABLE readings (
+  device_id STRING TAG,
+  temperature DOUBLE FIELD
+);
+
+CREATE TABLE device_info (
+  device_id STRING TAG,
+  device_name STRING FIELD
+);
+
+CREATE TABLE device_limits (
+  device_id STRING TAG,
+  max_temp DOUBLE FIELD
+);
+
+INSERT INTO device_info(time, device_id, device_name)
+VALUES (1, 'd1', 'Workshop 1 temperature sensor'),
+       (1, 'd2', 'Workshop 2 temperature sensor');
+
+INSERT INTO device_limits(time, device_id, max_temp)
+VALUES (1, 'd1', 30.0),
+       (1, 'd2', 35.0);
+
+INSERT INTO readings(time, device_id, temperature)
+VALUES (1000, 'd1', 25.5),
+       (1001, 'd2', 32.0),
+       (1002, 'd3', 20.0);
+```
+
+2. Implement the scalar function.
+
+```Java
+public class DeviceSummaryFunction implements ScalarFunction {
+
+  private Map<String, String> idToName = Map.of();
+  private Map<String, Double> idToMaxTemp = Map.of();
+
+  @Override
+  public ScalarFunctionAnalysis analyze(FunctionArguments arguments)
+      throws UDFArgumentNotValidException {
+    return new ScalarFunctionAnalysis.Builder()
+        .outputDataType(Type.STRING)
+        .build();
+  }
+
+  @Override
+  public void beforeStart(FunctionArguments arguments, IoTDBLocal local)
+      throws UDFException {
+    local.info("DeviceSummaryFunction: loading reference data");
+
+    // Keep only this block when a single query is needed.
+    Map<String, String> names = new HashMap<>();
+    try (UDFResultSet resultSet =
+        local.query("SELECT device_id, device_name FROM device_info")) {
+      while (resultSet.hasNext()) {
+        Record row = resultSet.next();
+        names.put(row.getString(0), row.getString(1));
+      }
+    }
+
+    // Execute additional queries when multiple data sources are needed.
+    Map<String, Double> limits = new HashMap<>();
+    try (UDFResultSet resultSet =
+        local.query("SELECT device_id, max_temp FROM device_limits")) {
+      while (resultSet.hasNext()) {
+        Record row = resultSet.next();
+        limits.put(row.getString(0), row.getDouble(1));
+      }
+    }
+
+    idToName = names;
+    idToMaxTemp = limits;
+    local.info(
+        "DeviceSummaryFunction: loaded {} names and {} limits",
+        idToName.size(),
+        idToMaxTemp.size());
+  }
+
+  @Override
+  public Object evaluate(Record input) throws UDFException {
+    return summarize(input);
+  }
+
+  @Override
+  public Object evaluate(Record input, IoTDBLocal local)
+      throws UDFException {
+    return summarize(input);
+  }
+
+  private Binary summarize(Record input) {
+    String deviceId = input.getString(0);
+    String name = idToName.getOrDefault(deviceId, "Unknown device");
+    Double maxTemp = idToMaxTemp.get(deviceId);
+
+    String result =
+        String.format(
+            "%s (limit: %s)",
+            name,
+            maxTemp == null ? "unknown" : maxTemp);
+    return new Binary(result, TSFileConfig.STRING_CHARSET);
+  }
+}
+```
+
+3. Register and use the function.
+
+```SQL
+CREATE FUNCTION device_summary
+AS 'org.apache.iotdb.udf.demo.DeviceSummaryFunction';
+
+SELECT time,
+       device_id,
+       temperature,
+       device_summary(device_id) AS summary
+FROM readings;
+```
+
+The query returns results similar to the following:
+
+```SQL
+d1  25.5  Workshop 1 temperature sensor (limit: 30.0)
+d2  32.0  Workshop 2 temperature sensor (limit: 35.0)
+d3  20.0  Unknown device (limit: unknown)
+```
+
+
+### 3.6 Complete Maven Project Example
 
 For Maven-based implementations, refer to the sample project: 
[udf-example](https://github.com/apache/iotdb/tree/master/example/udf).
diff --git a/src/UserGuide/latest-Table/User-Manual/User-defined-function.md 
b/src/UserGuide/latest-Table/User-Manual/User-defined-function_apache.md
similarity index 77%
rename from src/UserGuide/latest-Table/User-Manual/User-defined-function.md
rename to src/UserGuide/latest-Table/User-Manual/User-defined-function_apache.md
index 770151fd..e88a688d 100644
--- a/src/UserGuide/latest-Table/User-Manual/User-defined-function.md
+++ b/src/UserGuide/latest-Table/User-Manual/User-defined-function_apache.md
@@ -448,6 +448,186 @@ The result set of a table function consists of two parts:
    * If no pass-through but PARTITION BY is specified: Only partition columns 
are included.
    * If neither is specified: No additional columns are added.
 
-### 3.5 Complete Maven Project Example
+### 3.5 Accessing IoTDB from UDFs
+
+Starting from **V2.0.11**, table-model UDFs can use `IoTDBLocal` to execute 
SQL queries and write logs during data processing. `IoTDBLocal` is supplied by 
the framework. Queries reuse the permissions of the current connection user and 
return streaming result sets. This capability is included in `udf-api`; no 
additional dependency is required.
+
+Existing methods without an `IoTDBLocal` parameter remain available. Implement 
the overloads with an `IoTDBLocal` parameter only when the UDF needs to query 
IoTDB or write logs.
+
+#### 3.5.1 API Reference
+
+`IoTDBLocal` is in the `org.apache.iotdb.udf.api` package and provides the 
following capabilities:
+
+| API | Description |
+|---|---|
+| `UDFResultSet query(String sql) throws UDFException` | Executes SQL and 
returns the query result as a streaming result set. The query uses the current 
connection user's permissions. |
+| `info(...)` | Writes an INFO-level log message. Message arguments and 
exception objects are supported. |
+| `warn(...)` | Writes a WARN-level log message. Message arguments and 
exception objects are supported. |
+| `error(...)` | Writes an ERROR-level log message. Message arguments and 
exception objects are supported. |
+
+The `UDFResultSet` returned by `query` implements `AutoCloseable` and provides 
the following methods for reading rows:
+
+| API | Description |
+|---|---|
+| `boolean hasNext() throws UDFException` | Checks whether another row is 
available. |
+| `Record next() throws UDFException` | Returns the next row. Throws 
`NoSuchElementException` when no more rows are available. |
+| `void close() throws IoTDBLocalException` | Closes the result set and 
releases resources. |
+
+Use try-with-resources to close result sets promptly. Even if a result set is 
not closed manually, the framework releases any result sets that remain open 
after the current UDF execution finishes.
+
+The following table-model UDF methods can receive `IoTDBLocal`:
+
+| UDF type | Supported methods |
+|---|---|
+| Scalar function (UDSF) | `beforeStart`, `evaluate`, `beforeDestroy` |
+| Aggregate function (UDAF) | `beforeStart`, `addInput`, `combineState`, 
`outputFinal`, `beforeDestroy` |
+| Table function (UDTF) | `beforeStart`, `process`, `finish`, and 
`beforeDestroy` of `TableFunctionDataProcessor`; `beforeStart`, `process`, and 
`beforeDestroy` of `TableFunctionLeafProcessor` |
+
+For example, a scalar function can implement the following overloads as needed:
+
+```Java
+default void beforeStart(FunctionArguments arguments, IoTDBLocal local)
+    throws UDFException;
+
+default Object evaluate(Record input, IoTDBLocal local)
+    throws UDFException;
+
+default void beforeDestroy(IoTDBLocal local);
+```
+
+#### 3.5.2 Example
+
+The following example queries device names and temperature limits in 
`beforeStart` and caches the results in memory. If the UDF only needs device 
names, keep the first query. If it needs to combine multiple data sources, call 
`query` multiple times as shown here. For reference data that does not change 
during one UDF execution, query it during initialization instead of executing 
the same SQL for every row in `evaluate`.
+
+1. Create the sample tables and insert data.
+
+```SQL
+CREATE TABLE readings (
+  device_id STRING TAG,
+  temperature DOUBLE FIELD
+);
+
+CREATE TABLE device_info (
+  device_id STRING TAG,
+  device_name STRING FIELD
+);
+
+CREATE TABLE device_limits (
+  device_id STRING TAG,
+  max_temp DOUBLE FIELD
+);
+
+INSERT INTO device_info(time, device_id, device_name)
+VALUES (1, 'd1', 'Workshop 1 temperature sensor'),
+       (1, 'd2', 'Workshop 2 temperature sensor');
+
+INSERT INTO device_limits(time, device_id, max_temp)
+VALUES (1, 'd1', 30.0),
+       (1, 'd2', 35.0);
+
+INSERT INTO readings(time, device_id, temperature)
+VALUES (1000, 'd1', 25.5),
+       (1001, 'd2', 32.0),
+       (1002, 'd3', 20.0);
+```
+
+2. Implement the scalar function.
+
+```Java
+public class DeviceSummaryFunction implements ScalarFunction {
+
+  private Map<String, String> idToName = Map.of();
+  private Map<String, Double> idToMaxTemp = Map.of();
+
+  @Override
+  public ScalarFunctionAnalysis analyze(FunctionArguments arguments)
+      throws UDFArgumentNotValidException {
+    return new ScalarFunctionAnalysis.Builder()
+        .outputDataType(Type.STRING)
+        .build();
+  }
+
+  @Override
+  public void beforeStart(FunctionArguments arguments, IoTDBLocal local)
+      throws UDFException {
+    local.info("DeviceSummaryFunction: loading reference data");
+
+    // Keep only this block when a single query is needed.
+    Map<String, String> names = new HashMap<>();
+    try (UDFResultSet resultSet =
+        local.query("SELECT device_id, device_name FROM device_info")) {
+      while (resultSet.hasNext()) {
+        Record row = resultSet.next();
+        names.put(row.getString(0), row.getString(1));
+      }
+    }
+
+    // Execute additional queries when multiple data sources are needed.
+    Map<String, Double> limits = new HashMap<>();
+    try (UDFResultSet resultSet =
+        local.query("SELECT device_id, max_temp FROM device_limits")) {
+      while (resultSet.hasNext()) {
+        Record row = resultSet.next();
+        limits.put(row.getString(0), row.getDouble(1));
+      }
+    }
+
+    idToName = names;
+    idToMaxTemp = limits;
+    local.info(
+        "DeviceSummaryFunction: loaded {} names and {} limits",
+        idToName.size(),
+        idToMaxTemp.size());
+  }
+
+  @Override
+  public Object evaluate(Record input) throws UDFException {
+    return summarize(input);
+  }
+
+  @Override
+  public Object evaluate(Record input, IoTDBLocal local)
+      throws UDFException {
+    return summarize(input);
+  }
+
+  private Binary summarize(Record input) {
+    String deviceId = input.getString(0);
+    String name = idToName.getOrDefault(deviceId, "Unknown device");
+    Double maxTemp = idToMaxTemp.get(deviceId);
+
+    String result =
+        String.format(
+            "%s (limit: %s)",
+            name,
+            maxTemp == null ? "unknown" : maxTemp);
+    return new Binary(result, TSFileConfig.STRING_CHARSET);
+  }
+}
+```
+
+3. Register and use the function.
+
+```SQL
+CREATE FUNCTION device_summary
+AS 'org.apache.iotdb.udf.demo.DeviceSummaryFunction';
+
+SELECT time,
+       device_id,
+       temperature,
+       device_summary(device_id) AS summary
+FROM readings;
+```
+
+The query returns results similar to the following:
+
+```SQL
+d1  25.5  Workshop 1 temperature sensor (limit: 30.0)
+d2  32.0  Workshop 2 temperature sensor (limit: 35.0)
+d3  20.0  Unknown device (limit: unknown)
+```
+
+
+### 3.6 Complete Maven Project Example
 
 For Maven-based implementations, refer to the sample project: 
[udf-example](https://github.com/apache/iotdb/tree/master/example/udf).
diff --git a/src/zh/UserGuide/Master/Table/User-Manual/User-defined-function.md 
b/src/zh/UserGuide/Master/Table/User-Manual/User-defined-function_apache.md
similarity index 77%
rename from src/zh/UserGuide/Master/Table/User-Manual/User-defined-function.md
rename to 
src/zh/UserGuide/Master/Table/User-Manual/User-defined-function_apache.md
index 288071f3..42fd233b 100644
--- a/src/zh/UserGuide/Master/Table/User-Manual/User-defined-function.md
+++ b/src/zh/UserGuide/Master/Table/User-Manual/User-defined-function_apache.md
@@ -432,6 +432,186 @@ IoTDB 中的表函数为多态表值函数,支持参数类型如下所示:
 
 
 
-### 3.5 完整Maven项目示例
+### 3.5 在 UDF 中访问 IoTDB
+
+自 **V2.0.11** 起,表模型 UDF 可以通过 `IoTDBLocal` 在数据处理过程中执行 SQL 查询和记录日志。`IoTDBLocal` 
由框架传入,查询会复用当前连接用户的权限,并以流式结果集返回数据。该功能包含在 `udf-api` 中,无需引入其他依赖。
+
+原有不带 `IoTDBLocal` 参数的接口仍然可用。仅当 UDF 需要查询 IoTDB 或记录日志时,才需要实现带 `IoTDBLocal` 
参数的重载方法。
+
+#### 3.5.1 接口说明
+
+`IoTDBLocal` 位于 `org.apache.iotdb.udf.api` 包中,提供以下能力:
+
+|接口|说明|
+|---|---|
+|`UDFResultSet query(String sql) throws UDFException`|执行一条 
SQL,并以流式结果集返回查询结果。查询使用当前连接用户的权限。|
+|`info(...)`|记录 INFO 级别日志,支持消息、格式化参数或异常对象。|
+|`warn(...)`|记录 WARN 级别日志,支持消息、格式化参数或异常对象。|
+|`error(...)`|记录 ERROR 级别日志,支持消息、格式化参数或异常对象。|
+
+`query` 返回的 `UDFResultSet` 实现了 `AutoCloseable`,通过以下方法逐行读取结果:
+
+|接口|说明|
+|---|---|
+|`boolean hasNext() throws UDFException`|判断结果集中是否还有下一行。|
+|`Record next() throws UDFException`|获取下一行;没有更多数据时抛出 `NoSuchElementException`。|
+|`void close() throws IoTDBLocalException`|关闭结果集并释放资源。|
+
+建议使用 `try-with-resources` 及时关闭结果集。即使没有手动关闭,框架也会在本次 UDF 执行结束后释放仍未关闭的结果集。
+
+不同类型的表模型 UDF 可以在以下方法中获取 `IoTDBLocal`:
+
+|UDF 类型|支持的方法|
+|---|---|
+|标量函数(UDSF)|`beforeStart`、`evaluate`、`beforeDestroy`|
+|聚合函数(UDAF)|`beforeStart`、`addInput`、`combineState`、`outputFinal`、`beforeDestroy`|
+|表函数(UDTF)|`TableFunctionDataProcessor` 的 
`beforeStart`、`process`、`finish`、`beforeDestroy`;<br>`TableFunctionLeafProcessor`
 的 `beforeStart`、`process`、`beforeDestroy`|
+
+例如,标量函数可以按需实现以下重载方法:
+
+```Java
+default void beforeStart(FunctionArguments arguments, IoTDBLocal local)
+    throws UDFException;
+
+default Object evaluate(Record input, IoTDBLocal local)
+    throws UDFException;
+
+default void beforeDestroy(IoTDBLocal local);
+```
+
+#### 3.5.2 使用示例
+
+以下示例在 `beforeStart` 中查询设备名称和温度上限,并将结果缓存在内存中。如果 UDF 
只需要设备名称,保留第一条查询即可;如果需要组合多个数据源,则可以像本例一样多次调用 `query`。对于不会在一次 UDF 
执行期间变化的参考数据,建议在初始化阶段集中查询,避免在 `evaluate` 中对每一行重复执行 SQL。
+
+1. 创建示例表并写入数据。
+
+```SQL
+CREATE TABLE readings (
+  device_id STRING TAG,
+  temperature DOUBLE FIELD
+);
+
+CREATE TABLE device_info (
+  device_id STRING TAG,
+  device_name STRING FIELD
+);
+
+CREATE TABLE device_limits (
+  device_id STRING TAG,
+  max_temp DOUBLE FIELD
+);
+
+INSERT INTO device_info(time, device_id, device_name)
+VALUES (1, 'd1', '一号车间温度传感器'),
+       (1, 'd2', '二号车间温度传感器');
+
+INSERT INTO device_limits(time, device_id, max_temp)
+VALUES (1, 'd1', 30.0),
+       (1, 'd2', 35.0);
+
+INSERT INTO readings(time, device_id, temperature)
+VALUES (1000, 'd1', 25.5),
+       (1001, 'd2', 32.0),
+       (1002, 'd3', 20.0);
+```
+
+2. 实现标量函数。
+
+```Java
+public class DeviceSummaryFunction implements ScalarFunction {
+
+  private Map<String, String> idToName = Map.of();
+  private Map<String, Double> idToMaxTemp = Map.of();
+
+  @Override
+  public ScalarFunctionAnalysis analyze(FunctionArguments arguments)
+      throws UDFArgumentNotValidException {
+    return new ScalarFunctionAnalysis.Builder()
+        .outputDataType(Type.STRING)
+        .build();
+  }
+
+  @Override
+  public void beforeStart(FunctionArguments arguments, IoTDBLocal local)
+      throws UDFException {
+    local.info("DeviceSummaryFunction: loading reference data");
+
+    // 单条查询场景只需保留这一段。
+    Map<String, String> names = new HashMap<>();
+    try (UDFResultSet resultSet =
+        local.query("SELECT device_id, device_name FROM device_info")) {
+      while (resultSet.hasNext()) {
+        Record row = resultSet.next();
+        names.put(row.getString(0), row.getString(1));
+      }
+    }
+
+    // 需要组合多个数据源时,可以继续执行其他查询。
+    Map<String, Double> limits = new HashMap<>();
+    try (UDFResultSet resultSet =
+        local.query("SELECT device_id, max_temp FROM device_limits")) {
+      while (resultSet.hasNext()) {
+        Record row = resultSet.next();
+        limits.put(row.getString(0), row.getDouble(1));
+      }
+    }
+
+    idToName = names;
+    idToMaxTemp = limits;
+    local.info(
+        "DeviceSummaryFunction: loaded {} names and {} limits",
+        idToName.size(),
+        idToMaxTemp.size());
+  }
+
+  @Override
+  public Object evaluate(Record input) throws UDFException {
+    return summarize(input);
+  }
+
+  @Override
+  public Object evaluate(Record input, IoTDBLocal local)
+      throws UDFException {
+    return summarize(input);
+  }
+
+  private Binary summarize(Record input) {
+    String deviceId = input.getString(0);
+    String name = idToName.getOrDefault(deviceId, "未知设备");
+    Double maxTemp = idToMaxTemp.get(deviceId);
+
+    String result =
+        String.format(
+            "%s(上限:%s)",
+            name,
+            maxTemp == null ? "未知" : maxTemp);
+    return new Binary(result, TSFileConfig.STRING_CHARSET);
+  }
+}
+```
+
+3. 注册并使用该函数。
+
+```SQL
+CREATE FUNCTION device_summary
+AS 'org.apache.iotdb.udf.demo.DeviceSummaryFunction';
+
+SELECT time,
+       device_id,
+       temperature,
+       device_summary(device_id) AS summary
+FROM readings;
+```
+
+上述查询将会返回类似如下结果:
+
+```SQL
+d1  25.5  一号车间温度传感器(上限:30.0)
+d2  32.0  二号车间温度传感器(上限:35.0)
+d3  20.0  未知设备(上限:未知)
+```
+
+
+### 3.6 完整Maven项目示例
 
 如果使用 
[Maven](http://search.maven.org/),可以参考示例项目[udf-example](https://github.com/apache/iotdb/tree/master/example/udf)。
diff --git a/src/zh/UserGuide/latest-Table/User-Manual/User-defined-function.md 
b/src/zh/UserGuide/latest-Table/User-Manual/User-defined-function_apache.md
similarity index 77%
rename from src/zh/UserGuide/latest-Table/User-Manual/User-defined-function.md
rename to 
src/zh/UserGuide/latest-Table/User-Manual/User-defined-function_apache.md
index 288071f3..42fd233b 100644
--- a/src/zh/UserGuide/latest-Table/User-Manual/User-defined-function.md
+++ b/src/zh/UserGuide/latest-Table/User-Manual/User-defined-function_apache.md
@@ -432,6 +432,186 @@ IoTDB 中的表函数为多态表值函数,支持参数类型如下所示:
 
 
 
-### 3.5 完整Maven项目示例
+### 3.5 在 UDF 中访问 IoTDB
+
+自 **V2.0.11** 起,表模型 UDF 可以通过 `IoTDBLocal` 在数据处理过程中执行 SQL 查询和记录日志。`IoTDBLocal` 
由框架传入,查询会复用当前连接用户的权限,并以流式结果集返回数据。该功能包含在 `udf-api` 中,无需引入其他依赖。
+
+原有不带 `IoTDBLocal` 参数的接口仍然可用。仅当 UDF 需要查询 IoTDB 或记录日志时,才需要实现带 `IoTDBLocal` 
参数的重载方法。
+
+#### 3.5.1 接口说明
+
+`IoTDBLocal` 位于 `org.apache.iotdb.udf.api` 包中,提供以下能力:
+
+|接口|说明|
+|---|---|
+|`UDFResultSet query(String sql) throws UDFException`|执行一条 
SQL,并以流式结果集返回查询结果。查询使用当前连接用户的权限。|
+|`info(...)`|记录 INFO 级别日志,支持消息、格式化参数或异常对象。|
+|`warn(...)`|记录 WARN 级别日志,支持消息、格式化参数或异常对象。|
+|`error(...)`|记录 ERROR 级别日志,支持消息、格式化参数或异常对象。|
+
+`query` 返回的 `UDFResultSet` 实现了 `AutoCloseable`,通过以下方法逐行读取结果:
+
+|接口|说明|
+|---|---|
+|`boolean hasNext() throws UDFException`|判断结果集中是否还有下一行。|
+|`Record next() throws UDFException`|获取下一行;没有更多数据时抛出 `NoSuchElementException`。|
+|`void close() throws IoTDBLocalException`|关闭结果集并释放资源。|
+
+建议使用 `try-with-resources` 及时关闭结果集。即使没有手动关闭,框架也会在本次 UDF 执行结束后释放仍未关闭的结果集。
+
+不同类型的表模型 UDF 可以在以下方法中获取 `IoTDBLocal`:
+
+|UDF 类型|支持的方法|
+|---|---|
+|标量函数(UDSF)|`beforeStart`、`evaluate`、`beforeDestroy`|
+|聚合函数(UDAF)|`beforeStart`、`addInput`、`combineState`、`outputFinal`、`beforeDestroy`|
+|表函数(UDTF)|`TableFunctionDataProcessor` 的 
`beforeStart`、`process`、`finish`、`beforeDestroy`;<br>`TableFunctionLeafProcessor`
 的 `beforeStart`、`process`、`beforeDestroy`|
+
+例如,标量函数可以按需实现以下重载方法:
+
+```Java
+default void beforeStart(FunctionArguments arguments, IoTDBLocal local)
+    throws UDFException;
+
+default Object evaluate(Record input, IoTDBLocal local)
+    throws UDFException;
+
+default void beforeDestroy(IoTDBLocal local);
+```
+
+#### 3.5.2 使用示例
+
+以下示例在 `beforeStart` 中查询设备名称和温度上限,并将结果缓存在内存中。如果 UDF 
只需要设备名称,保留第一条查询即可;如果需要组合多个数据源,则可以像本例一样多次调用 `query`。对于不会在一次 UDF 
执行期间变化的参考数据,建议在初始化阶段集中查询,避免在 `evaluate` 中对每一行重复执行 SQL。
+
+1. 创建示例表并写入数据。
+
+```SQL
+CREATE TABLE readings (
+  device_id STRING TAG,
+  temperature DOUBLE FIELD
+);
+
+CREATE TABLE device_info (
+  device_id STRING TAG,
+  device_name STRING FIELD
+);
+
+CREATE TABLE device_limits (
+  device_id STRING TAG,
+  max_temp DOUBLE FIELD
+);
+
+INSERT INTO device_info(time, device_id, device_name)
+VALUES (1, 'd1', '一号车间温度传感器'),
+       (1, 'd2', '二号车间温度传感器');
+
+INSERT INTO device_limits(time, device_id, max_temp)
+VALUES (1, 'd1', 30.0),
+       (1, 'd2', 35.0);
+
+INSERT INTO readings(time, device_id, temperature)
+VALUES (1000, 'd1', 25.5),
+       (1001, 'd2', 32.0),
+       (1002, 'd3', 20.0);
+```
+
+2. 实现标量函数。
+
+```Java
+public class DeviceSummaryFunction implements ScalarFunction {
+
+  private Map<String, String> idToName = Map.of();
+  private Map<String, Double> idToMaxTemp = Map.of();
+
+  @Override
+  public ScalarFunctionAnalysis analyze(FunctionArguments arguments)
+      throws UDFArgumentNotValidException {
+    return new ScalarFunctionAnalysis.Builder()
+        .outputDataType(Type.STRING)
+        .build();
+  }
+
+  @Override
+  public void beforeStart(FunctionArguments arguments, IoTDBLocal local)
+      throws UDFException {
+    local.info("DeviceSummaryFunction: loading reference data");
+
+    // 单条查询场景只需保留这一段。
+    Map<String, String> names = new HashMap<>();
+    try (UDFResultSet resultSet =
+        local.query("SELECT device_id, device_name FROM device_info")) {
+      while (resultSet.hasNext()) {
+        Record row = resultSet.next();
+        names.put(row.getString(0), row.getString(1));
+      }
+    }
+
+    // 需要组合多个数据源时,可以继续执行其他查询。
+    Map<String, Double> limits = new HashMap<>();
+    try (UDFResultSet resultSet =
+        local.query("SELECT device_id, max_temp FROM device_limits")) {
+      while (resultSet.hasNext()) {
+        Record row = resultSet.next();
+        limits.put(row.getString(0), row.getDouble(1));
+      }
+    }
+
+    idToName = names;
+    idToMaxTemp = limits;
+    local.info(
+        "DeviceSummaryFunction: loaded {} names and {} limits",
+        idToName.size(),
+        idToMaxTemp.size());
+  }
+
+  @Override
+  public Object evaluate(Record input) throws UDFException {
+    return summarize(input);
+  }
+
+  @Override
+  public Object evaluate(Record input, IoTDBLocal local)
+      throws UDFException {
+    return summarize(input);
+  }
+
+  private Binary summarize(Record input) {
+    String deviceId = input.getString(0);
+    String name = idToName.getOrDefault(deviceId, "未知设备");
+    Double maxTemp = idToMaxTemp.get(deviceId);
+
+    String result =
+        String.format(
+            "%s(上限:%s)",
+            name,
+            maxTemp == null ? "未知" : maxTemp);
+    return new Binary(result, TSFileConfig.STRING_CHARSET);
+  }
+}
+```
+
+3. 注册并使用该函数。
+
+```SQL
+CREATE FUNCTION device_summary
+AS 'org.apache.iotdb.udf.demo.DeviceSummaryFunction';
+
+SELECT time,
+       device_id,
+       temperature,
+       device_summary(device_id) AS summary
+FROM readings;
+```
+
+上述查询将会返回类似如下结果:
+
+```SQL
+d1  25.5  一号车间温度传感器(上限:30.0)
+d2  32.0  二号车间温度传感器(上限:35.0)
+d3  20.0  未知设备(上限:未知)
+```
+
+
+### 3.6 完整Maven项目示例
 
 如果使用 
[Maven](http://search.maven.org/),可以参考示例项目[udf-example](https://github.com/apache/iotdb/tree/master/example/udf)。

Reply via email to