首批通过分布式安全可靠测评,为关键业务系统打造
应用执行 insert 出现报错 00918
更新时间:2025-03-02 02:56
问题现象
用户遇到通过 JDBC 插入数据后查询结果与应用日志记录不一致疑似正确性问题,下面 select * from (select 2, 1 from dual); 预期结果是(2, 1)实际输出(2, 2)。

关键信息
遇到类似的 SQL 如
select * from (select 2, 1 from dual);预期结果是(2, 1)实际输出(2, 2)疑似正确性问题。alter system flush plan cache刷 plan cache 或者改成指定别名的形式规避此问题。select A.* from (select 1,1 from dual); -- 改成指定别名的形式 select A.* from (select 1 as c1,1 as c2 from dual);
问题原因
原因是 OceanBase 数据库解析星号时使用了子查询的 select item 别名做去重,导致解析后得到了两个相同 id 的列,结果只投影出了第一列。 例如 select * from (select 2, 2 from dual),由于 select 的两个都是 2,别名相同,解析后类似 select * from (select c1, c1 from t) 内层只投影出了 c1 这一列。正确结果应该是像 select * from (select 2 as c1, 2 as c2 from dual) 内层投影出 c1 和 c2 两个列。 现在遇到的问题是 insert into x select * from(select 2, 2 from dual)v 解析时,v 中 select 常量没有指定别名时,在解析过程中产生重复别名,导致外层解析时引用 select 输出关系错误, 当前面的计划生成后,后续 insert into x select * from(select 2,1 from dual) v 会复用前面的计划,导致 x 表中被错误的插入(2, 2)而不是(2, 1), 最终导致执行的结果出错,目前遇到这中形式的 SQL,只能强制这条 SQL 不走 plan cache。
Server version: OceanBase 4.2.1.7 (r1-0d6e365f0ea010ea4dc9049dfc555092652ab35d) (Built Dec 30 2024 20:28:29)
Copyright (c) 2000, 2018, OceanBase and/or its affiliates. All rights reserved.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
obclient [SYS]> select * from (select 2, 2 from dual);
+---+---+
| 2 | 2 |
+---+---+
| 2 | 2 |
+---+---+
1 row in set (0.005 sec)
obclient [SYS]> select * from (select 2, 1 from dual);
+---+---+
| 2 | 1 |
+---+---+
| 2 | 2 |
+---+---+
1 row in set (0.001 sec)
obclient [SYS]> alter system flush plan cache;
Query OK, 0 rows affected (0.018 sec)
obclient [SYS]> select * from (select 2, 1 from dual);
+---+---+
| 2 | 1 |
+---+---+
| 2 | 1 |
+---+---+
1 row in set (0.005 sec)
问题的风险及影响
内联视图投影项中存在重名列 insert into select 导致插入数量不一致疑似正确性问题。
影响租户
影响 OceanBase 数据库中的 Oracle 租户和 MySQL 租户,对于 SYS 租户无影响。
适用版本
OceanBase 数据库 V3.x、V4.x 版本。
解决方法
升级至问题已修复版本。目前已修复的版本包括 OceanBase 数据库企业版 V3.2.3 BP11 Hotfix2(oceanbase-3.2.3.3-111020032024101417)、V4.2.1 BP8(oceanbase-4.2.1.8-108000052024072217)。
规避方式
规避方式,示例如下。
select A.* from (select 1,1 from dual);
-- 改成指定别名的形式
select A.* from (select 1 as c1,1 as c2 from dual);