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:
parent
171cb8368a
commit
8a46a13fd1
@ -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
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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*);
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user