首批通过分布式安全可靠测评,为关键业务系统打造
OceanBase 数据库 Oracle 模式下的 CAST_FROM_NUMBER 和 CAST_TO_NUMBER 函数不兼容原生 Oracle 结果
更新时间:2026-05-19 08:21
OceanBase 数据库 Oracle 模式兼容原生 Oracle 数据库中的 UTL_RAW 系统包提供用于操作 RAW 数据类型的 SQL 函数。因为普通的 SQL 函数不在 RAW 数据上操作,而 PL 不允许在 RAW 和 CHAR 数据类型之间重载,所以 UTL_RAW 系统包是必不可少的。从 OceanBase 数据库 V3.2.4 BP8 开始, OceanBase 数据库陆续支持了如下数据类型和 RAW 数据之间的转换。
| 函数名 | 函数介绍 |
|---|---|
| CAST_FROM_BINARY_DOUBLE | 以 RAW 的二进制形式返回 BINARY_DOUBLE 值。 |
| CAST_FROM_BINARY_FLOAT | 以 RAW 的二进制形式返回 BINARY_FLOAT 值。 |
| CAST_FROM_BINARY_INTEGER | 以 RAW 的二进制形式返回 BINARY_INTEGER 值。 |
| CAST_FROM_NUMBER | 以 RAW 的二进制形式返回 NUMBER 值。 |
| CAST_TO_BINARY_DOUBLE | 将以 RAW 二进制形式表示的 BINARY_DOUBLE 值转换为 BINARY_DOUBLE。 |
| CAST_TO_BINARY_FLOAT | 将以 RAW 二进制形式表示的 BINARY_FLOAT 值转换为 BINARY_FLOAT。 |
| CAST_TO_BINARY_INTEGER | 将以 RAW 二进制形式表示的 BINARY_INTEGER 值转换为 BINARY_INTEGER。 |
| CAST_TO_NUMBER | 将以 RAW 二进制形式表示的 NUMBER 值转换为 NUMBER。 |
| CAST_TO_RAW | 将 VARCHAR2 值转换为 RAW 值。 |
| CAST_TO_VARCHAR2 | 将 RAW 值转换为 VARCHAR2 值。 |
需要注意的是,CAST_FROM_NUMBER 和 CAST_TO_NUMBER 两个函数是根据 NUMBER 的存储信息来转成 RAW 的,因为 OceanBase 和 Oracle 的 NUMBER 实现不相同,所以转成的 RAW 值和 Oracle 也不相同,所以会出现从 Oracle 迁移过来的包含 CAST_FROM_NUMBER 和 CAST_TO_NUMBER 处理的值,在 OceanBase 数据库 Oracle 模式下,不兼容的问题。这里 OceanBase 数据库 Oracle 模式下,原生 Oracle 数据库在各自自身使用 CAST_FROM_NUMBER 和 CAST_TO_NUMBER 转成的 RAW 可以相互转换。下面通过一个具体案例,解释说明 OceanBase 数据库 Oracle 模式下不兼容原生 Oracle 数据库的 CAST_FROM_NUMBER/CAST_TO_NUMBER 结果。
详细说明
如下的例子中,在加密阶段,DBMS_CRYPTO.ENCRYPT 调用 UTL_RAW.cast_from_number(key_number), 将 NUMBER 类型的值转换成 RAW。
-- 加密函数(返回十六进制字符串)
CREATE OR REPLACE FUNCTION fn_xyz_col_upload (number_in IN VARCHAR2)
RETURN VARCHAR2 IS
number_in_raw RAW(500) := UTL_I18N.STRING_TO_RAW(number_in, 'AL32UTF8');
key_number NUMBER(32) := 202010018886669037;
key_raw RAW(500) := UTL_RAW.cast_from_number(key_number);
encrypted_raw RAW(500);
BEGIN
encrypted_raw := DBMS_CRYPTO.ENCRYPT(
src => number_in_raw,
typ => DBMS_CRYPTO.DES_CBC_PKCS5,
KEY => key_raw
);
RETURN RAWTOHEX(encrypted_raw); -- 返回十六进制字符串
END;
/
调用函数 fn_xyz_col_upload 将值 1xxxxxxxxx9 转换成 RAW 值。 OceanBase 数据库 Oracle 模式下和原生 Oracle 数据库返回的值不一样。 测试语句如下。
SELECT fn_xyz_col_upload('1xxxxxxxxx9') encrypted_result FROM dual;
示例如下。
-- 原生 Oracle 数据库
SQL> SELECT fn_xyz_col_upload('1xxxxxxxxx9') encrypted_result FROM dual;
6153****************3D5C71B*****
-- OceanBase 数据库 Oracle 模式
obclient [TEST]> SELECT fn_xyz_col_upload2('1xxxxxxxxx9') encrypted_result FROM dual;
+----------------------------------+
| ENCRYPTED_RESULT |
+----------------------------------+
| E**************************3**** |
+----------------------------------+
1 row in set (0.092 sec)
因此,在处理需要兼容原生 Oracle 数据库 UTL_RAW.cast_from_number 的值的时候,当前需要将原生 Oracle 数据库对应的值写死在 code 中,强制使用原生 Oracle 转换后的值。
参考用例如下。
-- 加密函数(硬编码特定结果)
CREATE OR REPLACE FUNCTION fn_xyz_col_upload (number_in IN VARCHAR2)
RETURN VARCHAR2 IS
BEGIN
-- 仅为特定输入返回固定结果
IF number_in = '1xxxxxxxxx9' THEN
RETURN '6153****************3D5C71B*****';
ELSE
-- 其他输入的正常加密逻辑
RETURN RAWTOHEX(DBMS_CRYPTO.ENCRYPT(
src => UTL_I18N.STRING_TO_RAW(number_in, 'AL32UTF8'),
typ => DBMS_CRYPTO.ENCRYPT_DES + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5,
key => UTL_RAW.cast_from_number(202010018886669037)
));
END IF;
END;
/
影响租户
影响 OceanBase 数据库中的 Oracle 租户,对于 SYS 租户和 MySQL 租户无影响。
适用版本
OceanBase 数据库 V3.x、V4.x 版本。