From 14530b4deddee2d3743ed0d9e33557021555f539 Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Sat, 22 Feb 2025 09:28:21 +0300 Subject: [PATCH 1/2] Ignore NULLs (if desired) while scanning keys during index navigation --- src/jrd/recsrc/IndexTableScan.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/jrd/recsrc/IndexTableScan.cpp b/src/jrd/recsrc/IndexTableScan.cpp index 7319e4dd832..616be4d4430 100644 --- a/src/jrd/recsrc/IndexTableScan.cpp +++ b/src/jrd/recsrc/IndexTableScan.cpp @@ -198,6 +198,7 @@ bool IndexTableScan::internalGetRecord(thread_db* tdbb) const } index_desc* const idx = (index_desc*) ((SCHAR*) impure + m_offset); + const bool descending = (idx->idx_flags & idx_descending); // find the last fetched position from the index const USHORT pageSpaceID = m_relation->getPages(tdbb)->rel_pg_space_id; @@ -205,6 +206,8 @@ bool IndexTableScan::internalGetRecord(thread_db* tdbb) const const IndexRetrieval* const retrieval = m_index->retrieval; const USHORT flags = retrieval->irb_generic & (irb_descending | irb_partial | irb_starting); + const bool ignoreNulls = + (retrieval->irb_generic & irb_ignore_null_value_key) && (idx->idx_count == 1); do { @@ -252,6 +255,14 @@ bool IndexTableScan::internalGetRecord(thread_db* tdbb) const continue; } + // If we're walking in a descending index and we need to ignore NULLs + // then stop at the first NULL we see (only for single segment!) + if (descending && ignoreNulls && node.prefix == 0 && + node.length >= 1 && node.data[0] == 255) + { + break; + } + // Build the current key value from the prefix and current node data. memcpy(key.key_data + node.prefix, node.data, node.length); key.key_length = node.length + node.prefix; @@ -297,12 +308,16 @@ bool IndexTableScan::internalGetRecord(thread_db* tdbb) const break; } - // skip this record if: - // 1) there is an inversion tree for this index and this record + const bool skipNullKey = (ignoreNulls && !descending && !key.key_length); + + // Skip this record if: + // 1) NULL key is found and we were asked to ignore them, or + // 2) there is an inversion tree for this index and this record // is not in the bitmap for the inversion, or - // 2) the record has already been visited + // 3) the record has already been visited - if ((!(impure->irsb_flags & irsb_mustread) && + if (skipNullKey || + (!(impure->irsb_flags & irsb_mustread) && (!impure->irsb_nav_bitmap || !RecordBitmap::test(*impure->irsb_nav_bitmap, number.getValue()))) || RecordBitmap::test(impure->irsb_nav_records_visited, number.getValue())) From 9a0cf7b1868a64e0905b6e1c4aa6b386e5776fbe Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Mon, 24 Feb 2025 12:18:04 +0300 Subject: [PATCH 2/2] Misc --- src/jrd/btr.cpp | 19 +++++++------------ src/jrd/recsrc/IndexTableScan.cpp | 4 ++-- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index e9978fd4169..7d7bb681c1c 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -1241,8 +1241,8 @@ void BTR_evaluate(thread_db* tdbb, const IndexRetrieval* retrieval, RecordBitmap { // If we're walking in a descending index and we need to ignore NULLs // then stop at the first NULL we see (only for single segment!) - if (descending && ignoreNulls && node.prefix == 0 && - node.length >= 1 && node.data[0] == 255) + if (descending && ignoreNulls && + node.prefix == 0 && node.length >= 1 && node.data[0] == 255) { break; } @@ -6906,18 +6906,13 @@ static bool scan(thread_db* tdbb, UCHAR* pointer, RecordBitmap** bitmap, RecordB return true; } - // Ignore NULL-values, this is currently only available for single segment indexes. + // Ignore NULL-values, this is currently only available for single segment indexes if (ignoreNulls) { - ignore = false; - if (descending) - { - if ((node.prefix == 0) && (node.length >= 1) && (node.data[0] == 255)) - return false; - } - else { - ignore = (node.prefix + node.length == 0); // Ascending (prefix + length == 0) - } + if (descending && node.prefix == 0 && node.length >= 1 && node.data[0] == 255) + return false; + + ignore = descending ? false : (node.prefix + node.length == 0); } if (skipLowerKey) diff --git a/src/jrd/recsrc/IndexTableScan.cpp b/src/jrd/recsrc/IndexTableScan.cpp index 616be4d4430..ba672e41054 100644 --- a/src/jrd/recsrc/IndexTableScan.cpp +++ b/src/jrd/recsrc/IndexTableScan.cpp @@ -257,8 +257,8 @@ bool IndexTableScan::internalGetRecord(thread_db* tdbb) const // If we're walking in a descending index and we need to ignore NULLs // then stop at the first NULL we see (only for single segment!) - if (descending && ignoreNulls && node.prefix == 0 && - node.length >= 1 && node.data[0] == 255) + if (descending && ignoreNulls && + node.prefix == 0 && node.length >= 1 && node.data[0] == 255) { break; }