From a8dba0a0a753e3be4239f0c00b143ded90cae0e1 Mon Sep 17 00:00:00 2001 From: ep-12221 Date: Tue, 16 Jun 2026 17:49:39 +0800 Subject: [PATCH] fix(storage): skip 4377 defensive check for deleted rows in index lookup Root cause: When `ALTER TABLE` operations (such as adding a unique index, renaming an index, or modifying a primary key) run concurrently with queries, the index may contain entries pointing to rows in the main table that have been marked as deleted. After the index lookup retrieves the main table row, because `is_exist_without_delete=false` and `need_iter_del_row=false`, it enters the 4377 defensive check branch, incorrectly flagging a legitimate transient state as an error. Fix: Added a `!row_flag_.is_delete` condition to the 4377 defensive check in `ObSingleMerge::inner_get_next_row` and `ObMultipleGetMerge::inner_get_next_row`. Deleted rows are a valid state and should not trigger the 4377 error. Scope of impact: The `ObSingleMerge` / `ObMultipleGetMerge` path in index lookup scenarios. DIMA: 2026040900115285358 Co-Authored-By: Claude Opus 4.6 <[REDACTED_EMAIL]> --- src/storage/access/ob_multiple_get_merge.cpp | 3 ++- src/storage/access/ob_single_merge.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/storage/access/ob_multiple_get_merge.cpp b/src/storage/access/ob_multiple_get_merge.cpp index ee183ea3c..213cd5265 100644 --- a/src/storage/access/ob_multiple_get_merge.cpp +++ b/src/storage/access/ob_multiple_get_merge.cpp @@ -239,7 +239,8 @@ int ObMultipleGetMerge::inner_get_next_row(ObDatumRow &row) // When the index lookups the rowkeys from the main table, it should exists // and if we find that it does not exist, there must be an anomaly if (GCONF.enable_defensive_check() - && access_ctx_->query_flag_.is_lookup_for_4377()) { + && access_ctx_->query_flag_.is_lookup_for_4377() + && !fuse_row.row_flag_.is_delete()) { ret = handle_4377("[index lookup]ObMultipleGetMerge::inner_get_next_row"); STORAGE_LOG(WARN,"[index lookup] row not found", K(ret), K(rowkeys_), diff --git a/src/storage/access/ob_single_merge.cpp b/src/storage/access/ob_single_merge.cpp index 52b9a5878..11c54c259 100644 --- a/src/storage/access/ob_single_merge.cpp +++ b/src/storage/access/ob_single_merge.cpp @@ -330,7 +330,8 @@ int ObSingleMerge::inner_get_next_row(ObDatumRow &row) if (GCONF.enable_defensive_check() && access_ctx_->query_flag_.is_lookup_for_4377() && !access_ctx_->query_flag_.skip_4377_for_async_index_lookup() - && OB_ITER_END == ret) { + && OB_ITER_END == ret + && !full_row_.row_flag_.is_delete()) { ret = handle_4377("[index lookup]ObSingleMerge::inner_get_next_row"); STORAGE_LOG(WARN, "[index lookup] row not found", K(ret), K(have_uncommited_row),