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:
parent
0e3ddc3c45
commit
bdce8b1341
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user