首批通过分布式安全可靠测评,为关键业务系统打造
update 报错 4377 场景之一
更新时间:2024-01-22 01:56
问题描述
OceanBase 数据库执行 UPDATE 更新语句引发 4377 报错,日志信息如下。
ERROR [STORAGE] check_old_row_legitimacy (ob_partition_storage.cpp:2204) [105480][0][xxxxx-xxxxx-xxxxx-xxxxx] [lt=3] [dc=0] Fatal Error!!! Catch a defensive error!(ret=-4377
使用 addr2line 工具打印调用栈信息。
[root@xxxxx ~]# addr2line -pCfe /home/admin/oceanbase/bin/observer 0xf4ebe0b 0x53069ef 0x55d98c6 0x55d94df 0x55d9168 0xa43e846 0xa2b4d53 0xa2a8d3e 0x517d463 0x5174ddd 0x5171cdd 0x516ea75 0x516e836 0x516ef30 0xe0b1624 0xe0b0b4a 0xe0b00a0 0xd752de2 0xd752f5f 0xe53e41b 0xe53eeb5 0xe540452 0xe53fc0b 0xe696136 0xd752de2 0x50ffe4a 0x51013b9 0x50fe970 0xb6950c0 0xb6d5cbd 0x50eb847 0x50e88ef 0x50e6a6e 0xb9cf451 0x50e5c8f 0xb9ccde1 0x50e18f6 0xb9cd3e7 0xf3cb5f3 0xf3cb44f 0xf66670f
输出结果如下。
oceanbase::common::lbt() at ??:?
oceanbase::common::ObLogger::check_error_log(oceanbase::common::ObPLogItem&) at ??:?
oceanbase::common::ObLogger::log_message_kv(char const*, int, char const*, int, char const*, unsigned long, char const*, char const*, char const*, char const*, char const*, char const*, char const*)::{lambda(oceanbase::common::ObPLogItem*)#1}::operator()(oceanbase::common::ObPLogItem*) const at 0_cxx.cxx:?
void oceanbase::common::ObLogger::do_async_log_message<oceanbase::common::ObLogger::log_message_kv(char const*, int, char const*, int, char const*, unsigned long, char const*, char const*, char const*, char const*, char const*, char const*, char const*)::{lambda(oceanbase::common::ObPLogItem*)#1}>(char const*, int, char const*, int, char const*, unsigned long, oceanbase::common::ObLogger::log_message_kv(char const*, int, char const*, int, char const*, unsigned long, char const*, char const*, char const*, char const*, char const*, char const*, char const*)::{lambda(oceanbase::common::ObPLogItem*)#1}&) at 0_cxx.cxx:?
oceanbase::common::ObLogger::log_message_kv(char const*, int, char const*, int, char const*, unsigned long, char const*, char const*, char const*, char const*, char const*, char const*, char const*) at 0_cxx.cxx:?
void oceanbase::common::OB_PRINT<int, oceanbase::common::ObIArray<unsigned long>, oceanbase::common::ObLogPrintPointerCnt<oceanbase::common::ObNewRow*>, oceanbase::common::ObNewRow, oceanbase::storage::ObDMLBaseParam, oceanbase::storage::ObRowDml>(char const*, int, char const*, int, char const*, unsigned long, char const*, char const*, int const&, char const*, oceanbase::common::ObIArray<unsigned long> const&, char const*, oceanbase::common::ObLogPrintPointerCnt<oceanbase::common::ObNewRow*> const&, char const*, oceanbase::common::ObNewRow const&, char const*, oceanbase::storage::ObDMLBaseParam const&, char const*, oceanbase::storage::ObRowDml const&) at ??:?
oceanbase::storage::ObPartitionStorage::check_old_row_legitimacy(oceanbase::storage::ObPartitionStorage::ObDMLRunningCtx&, oceanbase::common::ObNewRow const&)::$_4164::operator()(char const*) const at 2_cxx.cxx:?
oceanbase::storage::ObPartitionStorage::check_old_row_legitimacy(oceanbase::storage::ObPartitionStorage::ObDMLRunningCtx&, oceanbase::common::ObNewRow const&) at ??:?
oceanbase::storage::ObPartitionStorage::process_old_row(oceanbase::storage::ObPartitionStorage::ObDMLRunningCtx&, bool, oceanbase::common::ObIArray<oceanbase::storage::ObPartitionStorage::ChangeType> const&, oceanbase::storage::ObStoreRow const&) at ??:?
oceanbase::storage::ObPartitionStorage::update_row(oceanbase::storage::ObPartitionStorage::ObDMLRunningCtx&, oceanbase::common::ObIArray<oceanbase::storage::ObPartitionStorage::ChangeType> const&, oceanbase::common::ObIArray<long> const&, bool, oceanbase::storage::ObPartitionStorage::RowReshape*&, oceanbase::storage::ObPartitionStorage::RowReshape*&, oceanbase::storage::ObStoreRow&, oceanbase::storage::ObStoreRow&, oceanbase::common::ObRowStore*, bool&) at ??:?
oceanbase::storage::ObPartitionStorage::update_rows(oceanbase::storage::ObStoreCtx const&, oceanbase::storage::ObDMLBaseParam const&, oceanbase::common::ObIArray<unsigned long> const&, oceanbase::common::ObIArray<unsigned long> const&, oceanbase::common::ObNewRowIterator*, long&) at ??:?
oceanbase::storage::ObPGStorage::update_rows(oceanbase::storage::ObStoreCtx const&, oceanbase::storage::ObDMLBaseParam const&, oceanbase::common::ObIArray<unsigned long> const&, oceanbase::common::ObIArray<unsigned long> const&, oceanbase::common::ObNewRowIterator*, long&) at ??:?
oceanbase::storage::ObPartitionGroup::update_rows(oceanbase::storage::ObStoreCtx const&, oceanbase::storage::ObDMLBaseParam const&, oceanbase::common::ObIArray<unsigned long> const&, oceanbase::common::ObIArray<unsigned long> const&, oceanbase::common::ObNewRowIterator*, long&) at ??:?
oceanbase::storage::ObPartitionService::update_rows(oceanbase::transaction::ObTransDesc const&, oceanbase::storage::ObDMLBaseParam const&, oceanbase::common::ObPartitionKey const&, oceanbase::common::ObIArray<unsigned long> const&, oceanbase::common::ObIArray<unsigned long> const&, oceanbase::common::ObNewRowIterator*, long&) at ??:?
oceanbase::sql::ObTableUpdate::update_rows(oceanbase::sql::ObExecContext&, long&) const at ??:?
oceanbase::sql::ObTableUpdate::do_table_update(oceanbase::sql::ObExecContext&) const at ??:?
oceanbase::sql::ObTableUpdate::inner_open(oceanbase::sql::ObExecContext&) const at ??:?
oceanbase::sql::ObPhyOperator::open(oceanbase::sql::ObExecContext&) const at ??:?
oceanbase::sql::ObPhyOperator::open(oceanbase::sql::ObExecContext&) const at ??:?
oceanbase::sql::ObMiniTaskExecutor::sync_fetch_local_result(oceanbase::sql::ObExecContext&, oceanbase::sql::ObPhyOperator const&, oceanbase::common::ObScanner&) at ??:?
oceanbase::sql::ObMiniTaskExecutor::mini_task_local_execute(oceanbase::sql::ObExecContext&, oceanbase::sql::ObMiniTask&, oceanbase::sql::ObMiniTaskResult&) at ??:?
oceanbase::sql::ObDMLMiniTaskExecutor::mini_task_execute(oceanbase::sql::ObExecContext&, oceanbase::sql::ObMiniJob const&, oceanbase::sql::ObTaskInfo&, oceanbase::sql::ObMiniTaskResult&) at ??:?
oceanbase::sql::ObDMLMiniTaskExecutor::execute(oceanbase::sql::ObExecContext&, oceanbase::sql::ObMiniJob const&, oceanbase::common::ObIArray<oceanbase::sql::ObTaskInfo*>&, bool, oceanbase::sql::ObMiniTaskResult&) at ??:?
oceanbase::sql::ObMultiPartUpdate::inner_open(oceanbase::sql::ObExecContext&) const at ??:?
oceanbase::sql::ObPhyOperator::open(oceanbase::sql::ObExecContext&) const at ??:?
oceanbase::sql::ObExecuteResult::open(oceanbase::sql::ObExecContext&) at ??:?
oceanbase::sql::ObResultSet::open() at ??:?
oceanbase::sql::ObResultSet::sync_open() at ??:?
oceanbase::observer::ObAsyncPlanDriver::response_result(oceanbase::observer::ObMySQLResultSet&) at ??:?
oceanbase::observer::ObMPQuery::process_with_tmp_context(oceanbase::sql::ObSQLSessionInfo&, bool, bool, bool&, bool&) at ??:?
oceanbase::observer::ObMPQuery::process_single_stmt(oceanbase::sql::ObMultiStmtItem const&, oceanbase::sql::ObSQLSessionInfo&, bool, bool, bool&, bool&) at ??:?
oceanbase::observer::ObMPQuery::process() at ??:?
oceanbase::rpc::frame::ObSqlProcessor::run() at ??:?
oceanbase::omt::ObWorkerProcessor::process_one(oceanbase::rpc::ObRequest&) at ??:?
oceanbase::omt::ObWorkerProcessor::process(oceanbase::rpc::ObRequest&) at ??:?
oceanbase::omt::ObThWorker::process_request(oceanbase::rpc::ObRequest&) at ??:?
oceanbase::omt::ObThWorker::worker(long&, long&, int&) at ??:?
non-virtual thunk to oceanbase::omt::ObThWorker::run(long) at ??:?
std::_Function_handler<void (), oceanbase::lib::UserThread::start()::$_14::operator()(oblib::Thread*) const::{lambda()#1}>::_M_invoke(std::_Any_data const&) at 0_cxx.cxx:?
eeentry(boost::context::detail::transfer_t) at ??:?
finish at object_set.cpp:?
示例如下。
创建测试表 SAMPLE。
obclient > CREATE TABLE "SAMPLE" ( "SAMPLE_ID" NUMBER(*,0) PRIMARY KEY, "SAMPLE_BARCODE" VARCHAR2(60), "VOLUME" NUMBER(*,2), "TOTAL_QUANTITY" NUMBER(*,2), "REPORT_PDF" VARCHAR2(200)); Query OK, 0 rows affected (0.072 sec)创建索引。
obclient > CREATE INDEX "SAMPLE_BARCODE_INDEX" on "SAMPLE" ("SAMPLE_BARCODE"); Query OK, 0 rows affected (0.032 sec)创建测试表 STOCK_RETURN_YPLIST。
obclient > CREATE TABLE "STOCK_RETURN_YPLIST" ( "STOCK_RETURN_YPLIST_ID" NUMBER(*,0) PRIMARY KEY, "SAMPLE_BARCODE" VARCHAR2(50), "ACTUAL_TOTAL" NUMBER(*,2), "ACTUAL_VOLUME" NUMBER(*,2)); Query OK, 0 rows affected (0.032 sec)创建自定义函数。
obclient > CREATE OR REPLACE FUNCTION Subtract(num1 IN NUMBER, num2 IN NUMBER) RETURN NUMBER AS num3 number; begin num3 := num1 - num2; RETURN num3; end; / Query OK, 0 rows affected (0.030 sec)插入测试数据。
obclient > insert into sample (SAMPLE_ID, volume, total_quantity, sample_barcode, REPORT_PDF) values(1, 100, 200, 10, 'a.pdf'); Query OK, 1 row affected (0.011 sec)insert into stock_return_yplist (STOCK_RETURN_YPLIST_ID, actual_volume, actual_total, sample_barcode) values(2, 30, 40, 10); Query OK, 1 row affected (0.003 sec)执行更新语句。
obclient > UPDATE
sample s
SET
(s.volume, s.total_quantity) = (
SELECT
Subtract(s.volume, y.actual_volume) AS volume,
Subtract(s.total_quantity, y.actual_total) AS total_quantity
FROM
stock_return_yplist y
WHERE
y.sample_barcode = s.sample_barcode and y. stock_return_sheet_id = '31507' AND (
s.re_test_report_date is null or s. re_test_report_date = ''
)
)
WHERE
EXISTS (
SELECT
1
FROM
stock_return_yplist y
WHERE
y.stock_return_sheet_id = '31507' AND s.sample_barcode = y.sample_barcode AND (
s.re_test_report_date is null or s.re_test_report_date = ''
)
);
ORA-00600:internal error code, arguments: -4377, fatal internal error in [check_old_row_legitimacy]
适用版本
OceanBase 数据库 V3.2.x 版本。
问题原因
update set 使用子查询对向量进行更新时,subplan filter 输出结果列投影处理发生偏移错误,导致一部分列错误覆盖,触发类型检查报错。
解决方法
升级至问题已修复版本,目前已修复的版本包括 OceanBase 数据库企业版 V3.2.3 BP5(oceanbase-3.2.3.2-105000062022090916)及之后版本。
短期解决方法改写 SQL,更新行。