mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 18:43:03 +01:00
1) Fixed wrong ALL results in the ODS11 optimizer.
2) Fixed SF #527681 -- Strange/Inconsistent query results
This commit is contained in:
parent
1c0ad0e6ce
commit
8c66a4883a
@ -1182,10 +1182,14 @@ InversionCandidate* OptimizerRetrieval::generateInversion(RecordSource** rsb)
|
||||
tail += optimizer->opt_base_parent_conjuncts;
|
||||
}
|
||||
for (; tail < opt_end; tail++) {
|
||||
if (tail->opt_conjunct_flags & opt_conjunct_matched) {
|
||||
continue;
|
||||
}
|
||||
jrd_nod* const node = tail->opt_conjunct_node;
|
||||
if (!(tail->opt_conjunct_flags & opt_conjunct_used) &&
|
||||
tail->opt_conjunct_node && (tail->opt_conjunct_node->nod_type != nod_or))
|
||||
node && (node->nod_type != nod_or))
|
||||
{
|
||||
matchOnIndexes(&indexScratches, tail->opt_conjunct_node, 1);
|
||||
matchOnIndexes(&indexScratches, node, 1);
|
||||
}
|
||||
}
|
||||
getInversionCandidates(&inversions, &indexScratches, 1);
|
||||
@ -1201,12 +1205,16 @@ InversionCandidate* OptimizerRetrieval::generateInversion(RecordSource** rsb)
|
||||
tail += optimizer->opt_base_parent_conjuncts;
|
||||
}
|
||||
for (; tail < opt_end; tail++) {
|
||||
if (tail->opt_conjunct_flags & opt_conjunct_matched) {
|
||||
continue;
|
||||
}
|
||||
jrd_nod* const node = tail->opt_conjunct_node;
|
||||
if (!(tail->opt_conjunct_flags & opt_conjunct_used) &&
|
||||
tail->opt_conjunct_node && (tail->opt_conjunct_node->nod_type == nod_or))
|
||||
node && (node->nod_type == nod_or))
|
||||
{
|
||||
invCandidate = matchOnIndexes(&indexScratches, tail->opt_conjunct_node, 1);
|
||||
invCandidate = matchOnIndexes(&indexScratches, node, 1);
|
||||
if (invCandidate) {
|
||||
invCandidate->boolean = tail->opt_conjunct_node;
|
||||
invCandidate->boolean = node;
|
||||
inversions.add(invCandidate);
|
||||
}
|
||||
}
|
||||
@ -2255,6 +2263,17 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch,
|
||||
}
|
||||
}
|
||||
|
||||
// check datatypes to ensure that the index scan is guaranteed
|
||||
// to deliver correct results
|
||||
|
||||
if (value) {
|
||||
dsc desc1, desc2;
|
||||
CMP_get_desc(tdbb, optimizer->opt_csb, match, &desc1);
|
||||
CMP_get_desc(tdbb, optimizer->opt_csb, value, &desc2);
|
||||
if (!BTR_types_comparable(desc1, desc2))
|
||||
return false;
|
||||
}
|
||||
|
||||
// match the field to an index, if possible, and save the value to be matched
|
||||
// as either the lower or upper bound for retrieval, or both
|
||||
|
||||
|
@ -256,6 +256,25 @@ USHORT BTR_all(thread_db* tdbb,
|
||||
}
|
||||
|
||||
|
||||
void BTR_complement_key(temporary_key* key)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* B T R _ c o m p l e m e n t _ k e y
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Negate a key for descending index.
|
||||
*
|
||||
**************************************/
|
||||
UCHAR* p = key->key_data;
|
||||
for (const UCHAR* const end = p + key->key_length; p < end; p++) {
|
||||
*p ^= -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BTR_create(thread_db* tdbb,
|
||||
jrd_rel* relation,
|
||||
index_desc* idx,
|
||||
@ -2019,6 +2038,54 @@ void BTR_selectivity(thread_db* tdbb, const jrd_rel* relation, USHORT id,
|
||||
}
|
||||
|
||||
|
||||
bool BTR_types_comparable(const dsc& target, const dsc& source)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* B T R _ t y p e s _ c o m p a r a b l e
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Return whether two datatypes are comparable in terms of the CVT rules.
|
||||
* The purpose is to ensure that compress() converts datatypes in the same
|
||||
* direction as CVT2_compare(), thus causing index scans to always deliver
|
||||
* the same results as the generic boolean evaluation.
|
||||
*
|
||||
**************************************/
|
||||
if (DTYPE_IS_TEXT(target.dsc_dtype))
|
||||
{
|
||||
// should we also check for the INTL stuff here?
|
||||
return (DTYPE_IS_TEXT(source.dsc_dtype));
|
||||
}
|
||||
else if (DTYPE_IS_NUMERIC(target.dsc_dtype))
|
||||
{
|
||||
return (DTYPE_IS_TEXT(source.dsc_dtype) ||
|
||||
DTYPE_IS_NUMERIC(source.dsc_dtype));
|
||||
}
|
||||
else if (target.dsc_dtype == dtype_sql_date)
|
||||
{
|
||||
return (DTYPE_IS_TEXT(source.dsc_dtype) ||
|
||||
source.dsc_dtype == dtype_sql_date);
|
||||
}
|
||||
else if (target.dsc_dtype == dtype_sql_time)
|
||||
{
|
||||
return (DTYPE_IS_TEXT(source.dsc_dtype) ||
|
||||
source.dsc_dtype == dtype_sql_time);
|
||||
}
|
||||
else if (target.dsc_dtype == dtype_timestamp)
|
||||
{
|
||||
return (DTYPE_IS_TEXT(source.dsc_dtype) ||
|
||||
DTYPE_IS_DATE(source.dsc_dtype));
|
||||
}
|
||||
else
|
||||
{
|
||||
fb_assert(DTYPE_IS_BLOB(target.dsc_dtype));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static SLONG add_node(thread_db* tdbb,
|
||||
WIN * window,
|
||||
index_insertion* insertion,
|
||||
@ -2134,25 +2201,6 @@ static SLONG add_node(thread_db* tdbb,
|
||||
}
|
||||
|
||||
|
||||
void BTR_complement_key(temporary_key* key)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* B T R _ c o m p l e m e n t _ k e y
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Negate a key for descending index.
|
||||
*
|
||||
**************************************/
|
||||
UCHAR* p = key->key_data;
|
||||
for (const UCHAR* const end = p + key->key_length; p < end; p++) {
|
||||
*p ^= -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void compress(thread_db* tdbb,
|
||||
const dsc* desc,
|
||||
temporary_key* key,
|
||||
|
@ -33,6 +33,7 @@ struct btree_exp;
|
||||
struct exp_index_buf;
|
||||
|
||||
USHORT BTR_all(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::IndexDescAlloc**);
|
||||
void BTR_complement_key(Jrd::temporary_key*);
|
||||
void BTR_create(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::index_desc*, USHORT, Jrd::sort_context*, Jrd::SelectivityList&);
|
||||
void BTR_delete_index(Jrd::thread_db*, Jrd::win*, USHORT);
|
||||
//USHORT BTR_delete_node(Jrd::thread_db*, Ods::btree_page*, USHORT);
|
||||
@ -55,7 +56,7 @@ bool BTR_next_index(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::jrd_tra*, Jrd::index_de
|
||||
void BTR_remove(Jrd::thread_db*, Jrd::win*, Jrd::index_insertion*);
|
||||
void BTR_reserve_slot(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::jrd_tra*, Jrd::index_desc*);
|
||||
void BTR_selectivity(Jrd::thread_db*, const Jrd::jrd_rel*, USHORT, Jrd::SelectivityList&);
|
||||
void BTR_complement_key(Jrd::temporary_key*);
|
||||
bool BTR_types_comparable(const dsc& target, const dsc& source);
|
||||
|
||||
#endif // JRD_BTR_PROTO_H
|
||||
|
||||
|
@ -6803,6 +6803,17 @@ static int match_index(thread_db* tdbb,
|
||||
}
|
||||
}
|
||||
|
||||
/* check datatypes to ensure that the index scan is guaranteed
|
||||
to deliver correct results */
|
||||
|
||||
if (value) {
|
||||
dsc desc1, desc2;
|
||||
CMP_get_desc(tdbb, opt->opt_csb, match, &desc1);
|
||||
CMP_get_desc(tdbb, opt->opt_csb, value, &desc2);
|
||||
if (!BTR_types_comparable(desc1, desc2))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* match the field to an index, if possible, and save the value to be matched
|
||||
as either the lower or upper bound for retrieval, or both */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user