8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 16:43:03 +01:00

Added missing (forgotten during refactoring) pre-sort before index scans. Fixed crash when all IN values are NULLs. Exclude duplicated IN values from the index scan.

This commit is contained in:
Dmitry Yemanov 2023-09-05 23:14:16 +03:00
parent 0e3ddc3c45
commit bdce8b1341
6 changed files with 75 additions and 27 deletions

View File

@ -204,7 +204,7 @@ LookupValueList::LookupValueList(MemoryPool& pool, ValueListNode* values, ULONG
m_values.add(item);
}
TriState LookupValueList::find(thread_db* tdbb, Request* request, const ValueExprNode* value, const dsc* desc) const
const SortedValueList* LookupValueList::init(thread_db* tdbb, Request* request) const
{
const auto impure = request->getImpure<impure_value>(m_impureOffset);
auto sortedList = impure->vlu_misc.vlu_sortedList;
@ -231,6 +231,14 @@ TriState LookupValueList::find(thread_db* tdbb, Request* request, const ValueExp
impure->vlu_flags |= VLU_computed;
}
return sortedList;
}
TriState LookupValueList::find(thread_db* tdbb, Request* request, const ValueExprNode* value, const dsc* desc) const
{
const auto sortedList = init(tdbb, request);
fb_assert(sortedList);
if (sortedList->isEmpty())
return TriState();

View File

@ -685,8 +685,6 @@ IndexScanListIterator::IndexScanListIterator(thread_db* tdbb, const IndexRetriev
m_lowerValues(*tdbb->getDefaultPool()), m_upperValues(*tdbb->getDefaultPool()),
m_iterator(m_listValues.begin())
{
fb_assert(retrieval->irb_list && retrieval->irb_list->getCount());
// Find and store the position of the variable key segment
const auto count = MIN(retrieval->irb_lower_count, retrieval->irb_upper_count);
@ -703,24 +701,38 @@ IndexScanListIterator::IndexScanListIterator(thread_db* tdbb, const IndexRetriev
fb_assert(m_segno < count);
// Copy the list values. Reverse them if index is descending.
// Copy the sorted values, skipping duplicates
m_listValues.assign(retrieval->irb_list->begin(), retrieval->irb_list->getCount());
const auto sortedList = retrieval->irb_list->init(tdbb, tdbb->getRequest());
fb_assert(sortedList);
if (retrieval->irb_generic & irb_descending)
std::reverse(m_listValues.begin(), m_listValues.end());
const SortValueItem* prior = nullptr;
for (const auto& item : *sortedList)
{
if (!prior || *prior != item)
m_listValues.add(item.value);
prior = &item;
}
// Prepare the lower/upper key expressions for evaluation
if (m_listValues.hasData())
{
// Reverse the list if index is descending
auto values = m_retrieval->irb_value;
m_lowerValues.assign(values, m_retrieval->irb_lower_count);
fb_assert(!m_lowerValues[m_segno]);
m_lowerValues[m_segno] = *m_iterator;
if (retrieval->irb_generic & irb_descending)
std::reverse(m_listValues.begin(), m_listValues.end());
values += m_retrieval->irb_desc.idx_count;
m_upperValues.assign(values, m_retrieval->irb_upper_count);
fb_assert(!m_upperValues[m_segno]);
m_upperValues[m_segno] = *m_iterator;
// Prepare the lower/upper key expressions for evaluation
auto values = m_retrieval->irb_value;
m_lowerValues.assign(values, m_retrieval->irb_lower_count);
fb_assert(!m_lowerValues[m_segno]);
m_lowerValues[m_segno] = *m_iterator;
values += m_retrieval->irb_desc.idx_count;
m_upperValues.assign(values, m_retrieval->irb_upper_count);
fb_assert(!m_upperValues[m_segno]);
m_upperValues[m_segno] = *m_iterator;
}
}
void IndexScanListIterator::makeKeys(temporary_key* lower, temporary_key* upper)
@ -1118,7 +1130,9 @@ void BTR_evaluate(thread_db* tdbb, const IndexRetrieval* retrieval, RecordBitmap
temporary_key* lower = &lowerKey;
temporary_key* upper = &upperKey;
BTR_make_bounds(tdbb, retrieval, iterator, lower, upper);
if (!BTR_make_bounds(tdbb, retrieval, iterator, lower, upper))
return;
index_desc idx;
btree_page* page = nullptr;
@ -1719,7 +1733,7 @@ bool BTR_lookup(thread_db* tdbb, jrd_rel* relation, USHORT id, index_desc* buffe
}
void BTR_make_bounds(thread_db* tdbb, const IndexRetrieval* retrieval,
bool BTR_make_bounds(thread_db* tdbb, const IndexRetrieval* retrieval,
IndexScanListIterator* iterator,
temporary_key* lower, temporary_key* upper)
{
@ -1743,6 +1757,9 @@ void BTR_make_bounds(thread_db* tdbb, const IndexRetrieval* retrieval,
}
else
{
if (iterator && iterator->isEmpty())
return false;
idx_e errorCode = idx_e_ok;
const auto idx = &retrieval->irb_desc;
@ -1778,6 +1795,8 @@ void BTR_make_bounds(thread_db* tdbb, const IndexRetrieval* retrieval,
context.raise(tdbb, errorCode);
}
}
return true;
}

View File

@ -477,6 +477,11 @@ class IndexScanListIterator
public:
IndexScanListIterator(thread_db* tdbb, const IndexRetrieval* retrieval);
bool isEmpty() const
{
return m_listValues.isEmpty();
}
bool getNext(temporary_key* lower, temporary_key* upper)
{
if (++m_iterator < m_listValues.end())
@ -489,12 +494,12 @@ public:
return false;
}
ValueExprNode* const* getLowerValues() const
const ValueExprNode* const* getLowerValues() const
{
return m_lowerValues.begin();
}
ValueExprNode* const* getUpperValues() const
const ValueExprNode* const* getUpperValues() const
{
return m_upperValues.begin();
}
@ -504,10 +509,10 @@ private:
thread_db* const m_tdbb;
const IndexRetrieval* const m_retrieval;
Firebird::HalfStaticArray<ValueExprNode*, 4> m_listValues;
Firebird::HalfStaticArray<ValueExprNode*, 4> m_lowerValues;
Firebird::HalfStaticArray<ValueExprNode*, 4> m_upperValues;
ValueExprNode* const* m_iterator;
Firebird::HalfStaticArray<const ValueExprNode*, 16> m_listValues;
Firebird::HalfStaticArray<const ValueExprNode*, 4> m_lowerValues;
Firebird::HalfStaticArray<const ValueExprNode*, 4> m_upperValues;
const ValueExprNode* const* m_iterator;
USHORT m_segno = MAX_USHORT;
};

View File

@ -44,7 +44,7 @@ void BTR_insert(Jrd::thread_db*, Jrd::win*, Jrd::index_insertion*);
USHORT BTR_key_length(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::index_desc*);
Ods::btree_page* BTR_left_handoff(Jrd::thread_db*, Jrd::win*, Ods::btree_page*, SSHORT);
bool BTR_lookup(Jrd::thread_db*, Jrd::jrd_rel*, USHORT, Jrd::index_desc*, Jrd::RelationPages*);
void BTR_make_bounds(Jrd::thread_db*, const Jrd::IndexRetrieval*, Jrd::IndexScanListIterator*,
bool BTR_make_bounds(Jrd::thread_db*, const Jrd::IndexRetrieval*, Jrd::IndexScanListIterator*,
Jrd::temporary_key*, Jrd::temporary_key*);
Jrd::idx_e BTR_make_key(Jrd::thread_db*, USHORT, const Jrd::ValueExprNode* const*, const Jrd::index_desc*,
Jrd::temporary_key*, USHORT);

View File

@ -176,8 +176,12 @@ bool IndexTableScan::internalGetRecord(thread_db* tdbb) const
FB_NEW_POOL(*tdbb->getDefaultPool()) IndexScanListIterator(tdbb, m_index->retrieval) :
nullptr;
BTR_make_bounds(tdbb, m_index->retrieval, impure->irsb_iterator,
impure->irsb_nav_lower, impure->irsb_nav_upper);
if (!BTR_make_bounds(tdbb, m_index->retrieval, impure->irsb_iterator,
impure->irsb_nav_lower, impure->irsb_nav_upper))
{
rpb->rpb_number.setValid(false);
return false;
}
}
// If this is the first time, start at the beginning

View File

@ -71,6 +71,16 @@ struct SortValueItem
static int compare(const dsc* desc1, const dsc* desc2);
bool operator==(const SortValueItem& other) const
{
return (compare(desc, other.desc) == 0);
}
bool operator!=(const SortValueItem& other) const
{
return (compare(desc, other.desc) != 0);
}
bool operator>(const SortValueItem& other) const
{
return (compare(desc, other.desc) > 0);
@ -91,6 +101,8 @@ public:
ValueExprNode** begin() { return m_values.begin(); }
ValueExprNode** end() { return m_values.end(); }
const SortedValueList* init(thread_db* tdbb, Request* request) const;
TriState find(thread_db* tdbb, Request* request,
const ValueExprNode* value, const dsc* desc) const;