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

Avoid inserting additional cast node in index key calculation tree

(cherry picked from commit 60fd8db300)
This commit is contained in:
AlexPeshkoff 2024-03-05 15:27:49 +03:00
parent 171cb8368a
commit 8a46a13fd1
5 changed files with 57 additions and 62 deletions

View File

@ -189,7 +189,7 @@ namespace
static ULONG add_node(thread_db*, WIN*, index_insertion*, temporary_key*, RecordNumber*,
ULONG*, ULONG*);
static void compress(thread_db*, const dsc*, temporary_key*, USHORT, bool, USHORT);
static void compress(thread_db*, const dsc*, const SSHORT scale, temporary_key*, USHORT, bool, USHORT);
static USHORT compress_root(thread_db*, index_root_page*);
static void copy_key(const temporary_key*, temporary_key*);
static contents delete_node(thread_db*, WIN*, UCHAR*);
@ -594,7 +594,7 @@ idx_e IndexKey::compose(Record* record)
m_key.key_flags |= key_empty;
compress(m_tdbb, desc_ptr, &m_key, tail->idx_itype, descending, m_keyType);
compress(m_tdbb, desc_ptr, 0, &m_key, tail->idx_itype, descending, m_keyType);
}
else
{
@ -633,7 +633,7 @@ idx_e IndexKey::compose(Record* record)
m_key.key_nulls |= 1 << n;
}
compress(m_tdbb, desc_ptr, &temp, tail->idx_itype, descending, m_keyType);
compress(m_tdbb, desc_ptr, 0, &temp, tail->idx_itype, descending, m_keyType);
const UCHAR* q = temp.key_data;
for (USHORT l = temp.key_length; l; --l, --stuff_count)
@ -770,7 +770,7 @@ void IndexScanListIterator::makeKeys(thread_db* tdbb, temporary_key* lower, temp
// Make the lower bound key
idx_e errorCode = BTR_make_key(tdbb, m_retrieval->irb_lower_count, getLowerValues(),
&m_retrieval->irb_desc, lower, keyType);
getScale(), &m_retrieval->irb_desc, lower, keyType);
if (errorCode == idx_e_ok)
{
@ -784,7 +784,7 @@ void IndexScanListIterator::makeKeys(thread_db* tdbb, temporary_key* lower, temp
// Make the upper bound key
errorCode = BTR_make_key(tdbb, m_retrieval->irb_upper_count, getUpperValues(),
&m_retrieval->irb_desc, upper, keyType);
getScale(), &m_retrieval->irb_desc, upper, keyType);
}
}
@ -1792,7 +1792,8 @@ bool BTR_make_bounds(thread_db* tdbb, const IndexRetrieval* retrieval,
const auto values = iterator ? iterator->getUpperValues() :
retrieval->irb_value + retrieval->irb_desc.idx_count;
errorCode = BTR_make_key(tdbb, count, values, idx, upper, keyType);
errorCode = BTR_make_key(tdbb, count, values, retrieval->irb_scale,
idx, upper, keyType);
}
if (errorCode == idx_e_ok)
@ -1802,7 +1803,8 @@ bool BTR_make_bounds(thread_db* tdbb, const IndexRetrieval* retrieval,
const auto values = iterator ? iterator->getLowerValues() :
retrieval->irb_value;
errorCode = BTR_make_key(tdbb, count, values, idx, lower, keyType);
errorCode = BTR_make_key(tdbb, count, values, retrieval->irb_scale,
idx, lower, keyType);
}
}
@ -1821,6 +1823,7 @@ bool BTR_make_bounds(thread_db* tdbb, const IndexRetrieval* retrieval,
idx_e BTR_make_key(thread_db* tdbb,
USHORT count,
const ValueExprNode* const* exprs,
const SSHORT* scale,
const index_desc* idx,
temporary_key* key,
USHORT keyType)
@ -1868,7 +1871,7 @@ idx_e BTR_make_key(thread_db* tdbb,
key->key_flags |= key_empty;
compress(tdbb, desc, key, tail->idx_itype, descending, keyType);
compress(tdbb, desc, scale ? *scale : 0, key, tail->idx_itype, descending, keyType);
if (fuzzy && (key->key_flags & key_empty))
{
@ -1901,7 +1904,7 @@ idx_e BTR_make_key(thread_db* tdbb,
temp.key_flags |= key_empty;
compress(tdbb, desc, &temp, tail->idx_itype, descending,
compress(tdbb, desc, scale ? *scale++ : 0, &temp, tail->idx_itype, descending,
(n == count - 1 ?
keyType : ((idx->idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT)));
@ -2026,7 +2029,7 @@ void BTR_make_null_key(thread_db* tdbb, const index_desc* idx, temporary_key* ke
// If the index is a single segment index, don't sweat the compound stuff
if ((idx->idx_count == 1) || (idx->idx_flags & idx_expression))
{
compress(tdbb, nullptr, key, tail->idx_itype, descending, INTL_KEY_SORT);
compress(tdbb, nullptr, 0, key, tail->idx_itype, descending, INTL_KEY_SORT);
}
else
{
@ -2040,7 +2043,7 @@ void BTR_make_null_key(thread_db* tdbb, const index_desc* idx, temporary_key* ke
for (; stuff_count; --stuff_count)
*p++ = 0;
compress(tdbb, nullptr, &temp, tail->idx_itype, descending, INTL_KEY_SORT);
compress(tdbb, nullptr, 0, &temp, tail->idx_itype, descending, INTL_KEY_SORT);
const UCHAR* q = temp.key_data;
for (USHORT l = temp.key_length; l; --l, --stuff_count)
@ -2736,6 +2739,7 @@ static ULONG add_node(thread_db* tdbb,
static void compress(thread_db* tdbb,
const dsc* desc,
const SSHORT matchScale,
temporary_key* key,
USHORT itype,
bool descending, USHORT key_type)
@ -2783,6 +2787,8 @@ static void compress(thread_db* tdbb,
size_t multiKeyLength;
UCHAR* ptr;
UCHAR* p = key->key_data;
fb_assert(matchScale == 0 || desc->dsc_scale == 0 || matchScale == desc->dsc_scale);
SSHORT scale = matchScale ? matchScale : desc->dsc_scale;
if (itype == idx_string || itype == idx_byte_array || itype == idx_metadata ||
itype == idx_decimal || itype == idx_bcd || itype >= idx_first_intl_string)
@ -2802,8 +2808,8 @@ static void compress(thread_db* tdbb,
if (itype == idx_bcd)
{
Int128 i = MOV_get_int128(tdbb, desc, desc->dsc_scale);
length = i.makeIndexKey(&buffer, desc->dsc_scale);
Int128 i = MOV_get_int128(tdbb, desc, scale);
length = i.makeIndexKey(&buffer, scale);
ptr = reinterpret_cast<UCHAR*>(buffer.vary_string);
}
else if (itype == idx_decimal)
@ -2954,13 +2960,13 @@ static void compress(thread_db* tdbb,
else if (itype == idx_numeric2)
{
int64_key_op = true;
temp.temp_int64_key = make_int64_key(MOV_get_int64(tdbb, desc, desc->dsc_scale), desc->dsc_scale);
temp.temp_int64_key = make_int64_key(MOV_get_int64(tdbb, desc, scale), scale);
temp_copy_length = sizeof(temp.temp_int64_key.d_part);
temp_is_negative = (temp.temp_int64_key.d_part < 0);
#ifdef DEBUG_INDEXKEY
print_int64_key(*(const SINT64*) desc->dsc_address,
desc->dsc_scale, temp.temp_int64_key);
scale, temp.temp_int64_key);
#endif
}

View File

@ -190,7 +190,7 @@ public:
IndexRetrieval(jrd_rel* relation, const index_desc* idx, USHORT count, temporary_key* key)
: irb_relation(relation), irb_index(idx->idx_id),
irb_generic(0), irb_lower_count(count), irb_upper_count(count), irb_key(key),
irb_name(nullptr), irb_value(nullptr), irb_list(nullptr)
irb_name(nullptr), irb_value(nullptr), irb_list(nullptr), irb_scale(nullptr)
{
memcpy(&irb_desc, idx, sizeof(irb_desc));
}
@ -201,7 +201,7 @@ public:
irb_generic(0), irb_lower_count(0), irb_upper_count(0), irb_key(NULL),
irb_name(FB_NEW_POOL(pool) MetaName(name)),
irb_value(FB_NEW_POOL(pool) ValueExprNode*[idx->idx_count * 2]),
irb_list(nullptr)
irb_list(nullptr), irb_scale(nullptr)
{
memcpy(&irb_desc, idx, sizeof(irb_desc));
}
@ -210,6 +210,7 @@ public:
{
delete irb_name;
delete[] irb_value;
delete[] irb_scale;
}
index_desc irb_desc; // Index descriptor
@ -222,6 +223,7 @@ public:
MetaName* irb_name; // Index name
ValueExprNode** irb_value; // Matching value (for equality search)
LookupValueList* irb_list; // Matching values list (for IN <list>)
SSHORT* irb_scale; // Scale for int64 key
};
// Flag values for irb_generic
@ -506,6 +508,11 @@ public:
return m_upperValues.begin();
}
SSHORT* getScale()
{
return m_retrieval->irb_scale;
}
private:
void makeKeys(thread_db* tdbb, temporary_key* lower, temporary_key* upper);

View File

@ -45,8 +45,8 @@ Ods::btree_page* BTR_left_handoff(Jrd::thread_db*, Jrd::win*, Ods::btree_page*,
bool BTR_lookup(Jrd::thread_db*, Jrd::jrd_rel*, USHORT, Jrd::index_desc*, Jrd::RelationPages*);
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);
Jrd::idx_e BTR_make_key(Jrd::thread_db*, USHORT, const Jrd::ValueExprNode* const*, const SSHORT* scale,
const Jrd::index_desc*, Jrd::temporary_key*, USHORT);
void BTR_make_null_key(Jrd::thread_db*, const Jrd::index_desc*, Jrd::temporary_key*);
bool BTR_next_index(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::jrd_tra*, Jrd::index_desc*, Jrd::win*);
void BTR_remove(Jrd::thread_db*, Jrd::win*, Jrd::index_insertion*);

View File

@ -595,6 +595,7 @@ struct IndexScratchSegment
bool excludeUpper = false; // exclude upper bound value from scan
unsigned scope = 0; // highest scope level
segmentScanType scanType = segmentScanNone; // scan type
SSHORT scale = 0; // scale for SINT64 (idx_numeric2) index
MatchedBooleanList matches; // matched booleans
};

View File

@ -55,29 +55,6 @@ using namespace Jrd;
namespace
{
ValueExprNode* injectCast(CompilerScratch* csb,
ValueExprNode* value, CastNode*& cast,
const dsc& desc)
{
// If the indexed column is of type int64, then we need to inject
// an extra cast to deliver the scale value to the BTR level
if (value && desc.dsc_dtype == dtype_int64)
{
if (!cast)
{
cast = FB_NEW_POOL(csb->csb_pool) CastNode(csb->csb_pool);
cast->source = value;
cast->castDesc = desc;
cast->impureOffset = csb->allocImpure<impure_value>();
}
value = cast;
}
return value;
}
ValueExprNode* invertBoolValue(CompilerScratch* csb, ValueExprNode* value)
{
// Having a condition (<field> != <boolean value>),
@ -1212,6 +1189,16 @@ InversionNode* Retrieval::makeIndexScanNode(IndexScratch* indexScratch) const
fb_assert(!retrieval->irb_list);
retrieval->irb_list = segments[i].valueList;
}
if (segments[i].scale)
{
if (!retrieval->irb_scale)
{
retrieval->irb_scale = FB_NEW_POOL(getPool()) SSHORT[count];
memset(retrieval->irb_scale, 0, sizeof(SSHORT) * count);
}
retrieval->irb_scale[i] = segments[i].scale;
}
}
}
@ -1770,9 +1757,6 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch,
const bool isDesc = (idx->idx_flags & idx_descending);
// Needed for int64 matches, see injectCast() function
CastNode *cast = nullptr, *cast2 = nullptr;
fb_assert(indexScratch->segments.getCount() == idx->idx_count);
for (unsigned i = 0; i < idx->idx_count; i++)
@ -1799,8 +1783,8 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch,
(segment->scanType == segmentScanEquivalent) ||
(segment->scanType == segmentScanList)))
{
segment->lowerValue = injectCast(csb, value, cast, matchDesc);
segment->upperValue = injectCast(csb, value2, cast2, matchDesc);
segment->lowerValue = value;
segment->upperValue = value2;
segment->scanType = segmentScanBetween;
segment->excludeLower = false;
segment->excludeUpper = false;
@ -1813,8 +1797,7 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch,
// override it with worser matches.
if (!(segment->scanType == segmentScanEqual))
{
segment->lowerValue = segment->upperValue =
injectCast(csb, value, cast, matchDesc);
segment->lowerValue = segment->upperValue = value;
segment->scanType = segmentScanEquivalent;
segment->excludeLower = false;
segment->excludeUpper = false;
@ -1823,8 +1806,7 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch,
case blr_eql:
segment->matches.add(boolean);
segment->lowerValue = segment->upperValue =
injectCast(csb, value, cast, matchDesc);
segment->lowerValue = segment->upperValue = value;
segment->scanType = segmentScanEqual;
segment->excludeLower = false;
segment->excludeUpper = false;
@ -1861,7 +1843,7 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch,
if (forward)
{
segment->lowerValue = injectCast(csb, value, cast, matchDesc);
segment->lowerValue = value;
if (segment->scanType == segmentScanLess)
segment->scanType = segmentScanBetween;
else
@ -1869,7 +1851,7 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch,
}
else
{
segment->upperValue = injectCast(csb, value, cast, matchDesc);
segment->upperValue = value;
if (segment->scanType == segmentScanGreater)
segment->scanType = segmentScanBetween;
else
@ -1893,7 +1875,7 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch,
if (forward)
{
segment->upperValue = injectCast(csb, value, cast, matchDesc);
segment->upperValue = value;
if (segment->scanType == segmentScanGreater)
segment->scanType = segmentScanBetween;
else
@ -1901,7 +1883,7 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch,
}
else
{
segment->lowerValue = injectCast(csb, value, cast, matchDesc);
segment->lowerValue = value;
if (segment->scanType == segmentScanLess)
segment->scanType = segmentScanBetween;
else
@ -1918,8 +1900,7 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch,
if (!((segment->scanType == segmentScanEqual) ||
(segment->scanType == segmentScanEquivalent)))
{
segment->lowerValue = segment->upperValue =
injectCast(csb, value, cast, matchDesc);
segment->lowerValue = segment->upperValue = value;
segment->scanType = segmentScanStarting;
segment->excludeLower = false;
segment->excludeUpper = false;
@ -1937,11 +1918,7 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch,
(segment->scanType == segmentScanEquivalent)))
{
fb_assert(listNode->lookup);
for (auto& item : *listNode->lookup)
{
cast = nullptr; // create new cast node for every value
item = injectCast(csb, item, cast, matchDesc);
}
segment->lowerValue = segment->upperValue = nullptr;
segment->valueList = listNode->lookup;
segment->scanType = segmentScanList;
@ -1967,6 +1944,10 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch,
return false;
}
// Scale idx_numeric2
if ((!missingNode) && (matchDesc.dsc_dtype == dtype_int64))
segment->scale = matchDesc.dsc_scale;
// A match could be made
if (segment->scope < scope)
segment->scope = scope;