mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 22:03: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;
|
tail += optimizer->opt_base_parent_conjuncts;
|
||||||
}
|
}
|
||||||
for (; tail < opt_end; tail++) {
|
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) &&
|
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);
|
getInversionCandidates(&inversions, &indexScratches, 1);
|
||||||
@ -1201,12 +1205,16 @@ InversionCandidate* OptimizerRetrieval::generateInversion(RecordSource** rsb)
|
|||||||
tail += optimizer->opt_base_parent_conjuncts;
|
tail += optimizer->opt_base_parent_conjuncts;
|
||||||
}
|
}
|
||||||
for (; tail < opt_end; tail++) {
|
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) &&
|
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) {
|
if (invCandidate) {
|
||||||
invCandidate->boolean = tail->opt_conjunct_node;
|
invCandidate->boolean = node;
|
||||||
inversions.add(invCandidate);
|
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
|
// 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
|
// 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,
|
void BTR_create(thread_db* tdbb,
|
||||||
jrd_rel* relation,
|
jrd_rel* relation,
|
||||||
index_desc* idx,
|
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,
|
static SLONG add_node(thread_db* tdbb,
|
||||||
WIN * window,
|
WIN * window,
|
||||||
index_insertion* insertion,
|
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,
|
static void compress(thread_db* tdbb,
|
||||||
const dsc* desc,
|
const dsc* desc,
|
||||||
temporary_key* key,
|
temporary_key* key,
|
||||||
|
@ -33,6 +33,7 @@ struct btree_exp;
|
|||||||
struct exp_index_buf;
|
struct exp_index_buf;
|
||||||
|
|
||||||
USHORT BTR_all(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::IndexDescAlloc**);
|
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_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);
|
void BTR_delete_index(Jrd::thread_db*, Jrd::win*, USHORT);
|
||||||
//USHORT BTR_delete_node(Jrd::thread_db*, Ods::btree_page*, 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_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_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_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
|
#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
|
/* 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 */
|
as either the lower or upper bound for retrieval, or both */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user