Hi Weihao,

I think this is a great feature. It reminds me of the influxdb3_local API
provided by the Python plugin interface in the Processing Engine introduced
in InfluxDB 3.0[1].

With IoTDBLocal, it becomes much more convenient when we write customized
UDFs for customers and need to perform secondary queries or lookups inside
the UDF. Without this kind of internal query interface, we would otherwise
have to use an external client and hard-code the username and password in
the UDF, which is very unsafe. Also, once the password changes, we would
have to recompile and redeploy the UDF.

So I think this capability is very valuable for real-world UDF development.


我觉得这个特性很棒。它和 InfluxDB 3.0 中 Processing Engine 的 Python plugin 接口提供的
influxdb3_local 很类似。

有了 IoTDBLocal 之后,当我们为客户编写定制 UDF,并且需要在 UDF 内部做二次查询或查询补充信息时,会方便很多。否则我们就需要在
UDF 中使用外部 client,并把用户名和密码硬编码进去,这是一种很不安全的做法。而且一旦密码发生变化,还需要重新编译和重新部署 UDF。

所以我认为这个能力对于实际的 UDF 开发场景非常有价值。


[1] https://docs.influxdata.com/influxdb3/core/plugins/


Best regards,

----------------------
Yuan Tian

On Thu, 2 Jul 2026 11:15:04 +0800 (CST), Weihao Li [email protected]
wrote:

Hi all,

I’d like to share a new capability introduced by PR #18035:
https://github.com/apache/iotdb/pull/18035

This PR adds IoTDBLocal, a framework-injected API for table-model UDFs
(scalar functions, aggregate functions, and table functions). With it, UDF
authors can execute read-only embedded SQL directly inside the server
during UDF lifecycle hooks — without pulling in an external IoTDB client or
opening a separate network connection. And it is compatible with previous
versions, the UDF of old version can still run normally. Following are
examples:

Example 1 — Preload an id to device-name mapping once using query interface
of IoTDBLocal, to be used in later process:
// The beforeStart method of a scalar UDF @Override public void
beforeStart(FunctionArguments arguments, IoTDBLocal local) throws
UDFException { local.info("DeviceNameFunction: loading device_info");
Map<String, String> map = new HashMap<>(); try (UDFResultSet rs =
local.query("SELECT device_id, device_name FROM device_info")) { while
(rs.hasNext()) { Record row = rs.next(); map.put(row.getString(0),
row.getString(1)); } } idToName = map; } 、、、 Example2 — Write server log
using info / warn / error interfaces of IoTDBLocal:

// The evaluate method of a scalar UDF
@Override
public Object evaluate(Record input, IoTDBLocal local) {
if (!firstRowLogged) {
firstRowLogged = true;
local.info(“MyUdf: start processing, first device_id={}”,
input.getString(0));
}
if (input.isNull(1)) {
local.error(“MyUdf: temperature is null, device_id={}”, input.getString(0));
return null;
}
double temp = input.getDouble(1);
if (temp > 30.0) {
local.warn(“MyUdf: high temperature detected, device_id={}, temp={}”,
input.getString(0), temp);
}
return buildResult(input);
}
Yours, Weihao Li

Reply via email to