开源OceanBase4.5版本创建外部函数报错

【 使用环境 】 测试环境
【 OB or 其他组件 】
【 使用版本 】开源OceanBase4.5
【问题描述】根据这个文档来创建
https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000004478381
创建外部存储函数,执行日志如下
bclient(root@mq_t1)[test]> select version()
→ ;
±-----------------------------+
| version() |
±-----------------------------+
| 5.7.25-OceanBase_CE-v4.5.0.0 |
±-----------------------------+
1 row in set (0.001 sec)
开启Java的外部存储函数功能
client(root@sys)[oceanbase]> SHOW PARAMETERS LIKE ‘ob_enable_java_udf’;
±------±---------±-----------±---------±-------------------±----------±------±----------------------------±---------±-------±--------±------------------±--------------±----------+
| zone | svr_type | svr_ip | svr_port | name | data_type | value | info | section | scope | source | edit_level | default_value | isdefault |
±------±---------±-----------±---------±-------------------±----------±------±----------------------------±---------±-------±--------±------------------±--------------±----------+
| zone1 | observer | 10.60.0.85 | 2882 | ob_enable_java_udf | BOOL | False | Enable or disable java udf. | OBSERVER | TENANT | DEFAULT | DYNAMIC_EFFECTIVE | False | 1 |
±------±---------±-----------±---------±-------------------±----------±------±----------------------------±---------±-------±--------±------------------±--------------±----------+
1 row in set (0.008 sec)

obclient(root@sys)[oceanbase]> ALTER SYSTEM SET ob_enable_java_udf = TRUE SCOPE = BOTH;
Query OK, 0 rows affected (0.015 sec)

obclient(root@sys)[oceanbase]> SHOW PARAMETERS LIKE ‘ob_enable_java_udf’;
±------±---------±-----------±---------±-------------------±----------±------±----------------------------±---------±-------±--------±------------------±--------------±----------+
| zone | svr_type | svr_ip | svr_port | name | data_type | value | info | section | scope | source | edit_level | default_value | isdefault |
±------±---------±-----------±---------±-------------------±----------±------±----------------------------±---------±-------±--------±------------------±--------------±----------+
| zone1 | observer | 10.60.0.85 | 2882 | ob_enable_java_udf | BOOL | True | Enable or disable java udf. | OBSERVER | TENANT | DEFAULT | DYNAMIC_EFFECTIVE | False | 0 |
±------±---------±-----------±---------±-------------------±----------±------±----------------------------±---------±-------±--------±------------------±--------------±----------+
1 row in set (0.007 sec)
已经打包了对应的jar包
obclient(root@sys)[oceanbase]> CALL DBMS_JAVA.LOADJAVA(’/data/ob-lib/sm4_udf.jar’, ‘-resolve’, ‘-force’);
Query OK, 0 rows affected (0.041 sec)

obclient(root@sys)[oceanbase]> CREATE FUNCTION sm4_encrypt(plain_text VARCHAR(1024), key VARCHAR(64))
→ RETURNS VARCHAR(2048)
→ PROPERTIES (
→ type = ‘odpsjar’,
→ file = ‘sm4_udf.jar’,
→ symbol = ‘SM4UDF.evaluate_encrypt’
→ );
Query OK, 0 rows affected (0.049 sec)

obclient(root@sys)[oceanbase]> CREATE FUNCTION sm4_decrypt(cipher_text VARCHAR(2048), key VARCHAR(64))
→ RETURNS VARCHAR(1024)
→ PROPERTIES (
→ type = ‘odpsjar’,
→ file = ‘sm4_udf.jar’,
→ symbol = ‘SM4UDF.evaluate_decrypt’
→ );
Query OK, 0 rows affected (0.043 sec)

obclient(root@sys)[oceanbase]> SHOW FUNCTION STATUS;
±----------±------------±---------±-----------±---------------------------±---------------------------±--------------±--------±---------------------±---------------------±-------------------+
| Db | Name | Type | Definer | Modified | Created | Security_type | Comment | character_set_client | collation_connection | Database Collation |
±----------±------------±---------±-----------±---------------------------±---------------------------±--------------±--------±---------------------±---------------------±-------------------+
| oceanbase | sm4_decrypt | FUNCTION | ‘root’@’%’ | 2026-06-12 15:30:23.384284 | 2026-06-12 15:30:23.384284 | DEFINER | NULL | utf8mb4 | utf8mb4_general_ci | utf8mb4_general_ci |
| oceanbase | sm4_encrypt | FUNCTION | ‘root’@’%’ | 2026-06-12 15:30:19.009264 | 2026-06-12 15:30:19.009264 | DEFINER | NULL | utf8mb4 | utf8mb4_general_ci | utf8mb4_general_ci |
±----------±------------±---------±-----------±---------------------------±---------------------------±--------------±--------±---------------------±---------------------±-------------------+
2 rows in set (0.055 sec)

obclient(root@sys)[oceanbase]> SELECT sm4_encrypt(‘Hello OceanBase SM4!’, ‘1234567890123456’) AS encrypted;
ERROR 1235 (0A000): Function sm4_encrypt not supported
【复现路径】现在函数已经创建成功了,使用过程中就报错,不知道是什么问题

【备注】基于 LLM 和开源文档 RAG 的论坛小助手已开放测试,在发帖时输入 [@论坛小助手] 即可召唤小助手,欢迎试用!

1 个赞

根据您描述的问题,OceanBase在调用您创建的Java UDF(用户自定义函数)sm4_encrypt时报告了不支持该函数的错误。这可能是由于配置不当、环境问题或兼容性问题导致的。虽然当前版本的obdiag可能没有直接针对外部函数或UDF特定问题的诊断场景,但我们可以尝试通过日志采集来获取更多信息以帮助定位问题。

日志采集

对于您的情况,推荐先使用obdiag工具进行日志收集,特别是关于集群的基础信息和任何可能与执行SQL相关的错误信息。这有助于我们更好地理解环境中发生了什么。

  • 日志采集场景: 集群基础信息
  • 日志采集命令: obdiag gather scene run --scene=observer.base

另外,如果您能确定是某个具体操作或查询触发了这个错误,请提供更多的上下文细节,例如执行失败的确切SQL语句等,这样可以帮助更准确地定位问题所在。

接下来,请允许我提几个问题以便进一步了解您的具体情况:

  1. 您能否分享一下创建外部函数sm4_encrypt的具体步骤以及相关配置?包括使用的Java代码片段和OB端的配置。
  2. 错误消息是在哪种情况下出现的?比如是在直接调用该函数时,还是在执行包含该函数的复杂查询过程中?
  3. 创建其他类型的UDF或执行普通的SQL命令是否正常工作?是否有观察到类似的错误?
  4. OceanBase服务所在的服务器上已安装并正确配置了JDK吗?请确认JDK版本及路径设置。
  5. 当前是否有其他异常警告或错误被记录在OceanBase的日志文件中?特别是与Java UDF加载或执行相关的错误信息。

请按上述指导操作,并将采集到的日志文件压缩包发送给我们,以便于后续的故障排查。感谢您的配合!

附上敏捷诊断工具 obdiag 使用帮助链接

java 定义的sm4函数

root@sc001 ob-lib]# cat SM4UDF.java
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class SM4UDF {

static {
    Security.addProvider(new BouncyCastleProvider());
}

public String evaluate_encrypt(String plainText, String key) {
    if (plainText == null || key == null) return null;
    try {
        byte[] keyBytes = processKey(key);
        byte[] plainBytes = plainText.getBytes("UTF-8");

        int blockSize = 16;
        int pad = blockSize - (plainBytes.length % blockSize);
        byte[] paddedPlain = new byte[plainBytes.length + pad];
        System.arraycopy(plainBytes, 0, paddedPlain, 0, plainBytes.length);
        for (int i = 0; i < pad; i++) {
            paddedPlain[plainBytes.length + i] = (byte) pad;
        }

        Cipher cipher = Cipher.getInstance("SM4/ECB/PKCS7Padding", "BC");
        SecretKeySpec skey = new SecretKeySpec(keyBytes, "SM4");
        cipher.init(Cipher.ENCRYPT_MODE, skey);

        byte[] encrypted = cipher.doFinal(paddedPlain);
        return bytesToHex(encrypted);
    } catch (Exception e) {
        return "ERROR:" + e.getMessage();
    }
}

public String evaluate_decrypt(String cipherText, String key) {
    if (cipherText == null || key == null) return null;
    try {
        byte[] keyBytes = processKey(key);
        byte[] cipherBytes = hexToBytes(cipherText);

        Cipher cipher = Cipher.getInstance("SM4/ECB/PKCS7Padding", "BC");
        SecretKeySpec skey = new SecretKeySpec(keyBytes, "SM4");
        cipher.init(Cipher.DECRYPT_MODE, skey);

        byte[] decrypted = cipher.doFinal(cipherBytes);

        int pad = decrypted[decrypted.length - 1];
        byte[] plainBytes = new byte[decrypted.length - pad];
        System.arraycopy(decrypted, 0, plainBytes, 0, plainBytes.length);

        return new String(plainBytes, "UTF-8");
    } catch (Exception e) {
        return "ERROR:" + e.getMessage();
    }
}

private byte[] processKey(String key) throws Exception {
    byte[] keyBytes = key.getBytes("UTF-8");
    if (keyBytes.length > 16) {
        return java.util.Arrays.copyOf(keyBytes, 16);
    } else if (keyBytes.length < 16) {
        byte[] padded = new byte[16];
        System.arraycopy(keyBytes, 0, padded, 0, keyBytes.length);
        java.util.Arrays.fill(padded, keyBytes.length, 16, (byte) 0);
        return padded;
    }
    return keyBytes;
}

private String bytesToHex(byte[] bytes) {
    StringBuilder sb = new StringBuilder();
    for (byte b : bytes) {
        sb.append(String.format("%02X", b & 0xFF));
    }
    return sb.toString();
}

private byte[] hexToBytes(String hex) {
    int len = hex.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                            + Character.digit(hex.charAt(i + 1), 16));
    }
    return data;
}

}
[root@sc001 ob-lib]#

社区版不支持加密服务。

原因

  • SM4 加密依赖 BabaSSL(蚂蚁自研的 SSL 库,现已更名为 Tongsuo/铜锁),通过编译宏 OB_USE_BABASSL 控制。
  • 社区版使用的是 OpenSSL 1.1.1,该版本不包含 SM4 算法支持(OpenSSL 3.0 才开始原生支持 SM4)。
  • 因此函数在 SQL 解析/创建阶段能通过(语法合法),但在执行阶段直接返回 OB_NOT_SUPPORTED
1 个赞

大佬,有没有什么其它的办法可以支持?sm4 加密解密的

社区不支持的呀。可以试试企业版。
OceanBase官网商务咨询

https://www.oceanbase.com/contactus?fromPage=https%3A%2F%2Fwww.oceanbase.com%2Fsoftwarecenter-enterprise&dataSources=softwarecenter-enterprise_footercontact_d2022

5869699696969

698889963333

8090963321233