mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 23:23:04 +01:00
1) Fix bug with LEFT JOIN ViewX and where clause with ViewX.FieldX IS NULL
2) When FIRST / SKIP is used in a sub-query it may not be affected by conjunctions in higher contexts. Example (should return 1 row instead of 5): SELECT * FROM (SELECT FIRST 5 SKIP 2 cs.* FROM RDB$CHARACTER_SETS cs) WHERE RDB$CHARACTER_SET_NAME starting with 'D'
This commit is contained in:
parent
5ddd2d1cb0
commit
b355d3411e
@ -104,6 +104,7 @@ static USHORT distribute_equalities(LLS *, Csb*, USHORT);
|
|||||||
static bool dump_index(const jrd_nod*, SCHAR**, SSHORT*);
|
static bool dump_index(const jrd_nod*, SCHAR**, SSHORT*);
|
||||||
static bool dump_rsb(const jrd_req*, const Rsb*, SCHAR**, SSHORT*);
|
static bool dump_rsb(const jrd_req*, const Rsb*, SCHAR**, SSHORT*);
|
||||||
static bool estimate_cost(thread_db*, OPT, USHORT, double *, double *);
|
static bool estimate_cost(thread_db*, OPT, USHORT, double *, double *);
|
||||||
|
static bool expression_contains(const jrd_nod*, NOD_T, bool, bool);
|
||||||
#ifdef EXPRESSION_INDICES
|
#ifdef EXPRESSION_INDICES
|
||||||
static bool expression_equal(thread_db*, jrd_nod*, jrd_nod*);
|
static bool expression_equal(thread_db*, jrd_nod*, jrd_nod*);
|
||||||
#endif
|
#endif
|
||||||
@ -180,7 +181,8 @@ static SSHORT sort_indices_by_priority(Csb::csb_repeat*, IDX **, UINT64 *);
|
|||||||
#define DEBUG_NONE 0
|
#define DEBUG_NONE 0
|
||||||
|
|
||||||
IB_FILE *opt_debug_file = 0;
|
IB_FILE *opt_debug_file = 0;
|
||||||
static int opt_debug_flag = DEBUG_NONE;
|
static int opt_debug_flag = DEBUG_RELATIONSHIPS;
|
||||||
|
//static int opt_debug_flag = DEBUG_NONE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline void SET_DEP_BIT(ULONG* array, const SLONG bit)
|
inline void SET_DEP_BIT(ULONG* array, const SLONG bit)
|
||||||
@ -364,7 +366,6 @@ Rsb* OPT_compile(thread_db* tdbb,
|
|||||||
// put any additional booleans on the conjunct stack, and see if we
|
// put any additional booleans on the conjunct stack, and see if we
|
||||||
// can generate additional booleans by associativity--this will help
|
// can generate additional booleans by associativity--this will help
|
||||||
// to utilize indices that we might not have noticed
|
// to utilize indices that we might not have noticed
|
||||||
|
|
||||||
if (rse->rse_boolean) {
|
if (rse->rse_boolean) {
|
||||||
conjunct_count =
|
conjunct_count =
|
||||||
decompose(tdbb, rse->rse_boolean, &conjunct_stack, csb);
|
decompose(tdbb, rse->rse_boolean, &conjunct_stack, csb);
|
||||||
@ -378,6 +379,13 @@ Rsb* OPT_compile(thread_db* tdbb,
|
|||||||
stack_end = &(*stack_end)->lls_next;
|
stack_end = &(*stack_end)->lls_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AB: If we have limit our retrieval with FIRST / SKIP syntax then
|
||||||
|
// we may not deliver above conditions (from higher rse's) to this
|
||||||
|
// rse, because the results should be consistent.
|
||||||
|
if (rse->rse_skip || rse->rse_first) {
|
||||||
|
parent_stack = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// clear the csb_active flag of all streams in the rse
|
// clear the csb_active flag of all streams in the rse
|
||||||
set_rse_inactive(csb, rse);
|
set_rse_inactive(csb, rse);
|
||||||
|
|
||||||
@ -461,9 +469,40 @@ Rsb* OPT_compile(thread_db* tdbb,
|
|||||||
csb->csb_rpt[outer_streams[i]].csb_flags |= csb_active;
|
csb->csb_rpt[outer_streams[i]].csb_flags |= csb_active;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lls** stackSavepoint = &conjunct_stack;
|
||||||
|
if (rse->rse_jointype != blr_inner) {
|
||||||
|
// Make list of nodes that can be delivered to a outer-stream.
|
||||||
|
// In fact this are all nodes except IS NULL (nod_missing).
|
||||||
|
// Note! That for OR nodes this meant the whole node must be ignored.
|
||||||
|
lls** stackItem = &parent_stack;
|
||||||
|
for (; *stackItem; stackItem = &(*stackItem)->lls_next) {
|
||||||
|
jrd_nod* deliverNode = (jrd_nod*) (*stackItem)->lls_object;
|
||||||
|
if (!expression_contains(deliverNode, nod_missing, true, true)) {
|
||||||
|
LLS_PUSH(deliverNode, &conjunct_stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
*stack_end = parent_stack;
|
*stack_end = parent_stack;
|
||||||
|
}
|
||||||
|
|
||||||
rsb = OPT_compile(tdbb, csb, (RSE) node, conjunct_stack);
|
rsb = OPT_compile(tdbb, csb, (RSE) node, conjunct_stack);
|
||||||
|
|
||||||
|
if (rse->rse_jointype != blr_inner) {
|
||||||
|
if (parent_stack) {
|
||||||
|
// Remove previously added parent conjuctions from the stack.
|
||||||
|
lls** stackItem = &conjunct_stack;
|
||||||
|
for (; stackSavepoint != stackItem; stackItem = &(*stackItem)->lls_next) {
|
||||||
|
LLS_POP(&conjunct_stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
*stack_end = NULL;
|
*stack_end = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (rse->rse_jointype == blr_left) {
|
if (rse->rse_jointype == blr_left) {
|
||||||
for (SSHORT i = 1; i <= outer_streams[0]; i++) {
|
for (SSHORT i = 1; i <= outer_streams[0]; i++) {
|
||||||
csb->csb_rpt[outer_streams[i]].csb_flags &= ~csb_active;
|
csb->csb_rpt[outer_streams[i]].csb_flags &= ~csb_active;
|
||||||
@ -572,6 +611,7 @@ Rsb* OPT_compile(thread_db* tdbb,
|
|||||||
for (stack_end = &conjunct_stack; *stack_end;
|
for (stack_end = &conjunct_stack; *stack_end;
|
||||||
stack_end = &(*stack_end)->lls_next);
|
stack_end = &(*stack_end)->lls_next);
|
||||||
const SLONG saved_conjunct_count = conjunct_count;
|
const SLONG saved_conjunct_count = conjunct_count;
|
||||||
|
|
||||||
*stack_end = parent_stack;
|
*stack_end = parent_stack;
|
||||||
conjunct_count += distribute_equalities(&conjunct_stack, csb, conjunct_count);
|
conjunct_count += distribute_equalities(&conjunct_stack, csb, conjunct_count);
|
||||||
if (parent_stack) {
|
if (parent_stack) {
|
||||||
@ -2675,6 +2715,46 @@ static bool estimate_cost(thread_db* tdbb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool expression_contains(const jrd_nod* node, NOD_T node_type, bool go_into_or, bool go_into_and)
|
||||||
|
{
|
||||||
|
/**************************************
|
||||||
|
*
|
||||||
|
* e x p r e s s i o n _ c o n t a i n s
|
||||||
|
*
|
||||||
|
**************************************
|
||||||
|
*
|
||||||
|
* Functional description
|
||||||
|
* Search if somewhere in the expression the give
|
||||||
|
* node_type is burried.
|
||||||
|
*
|
||||||
|
**************************************/
|
||||||
|
DEV_BLKCHK(node, type_nod);
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->nod_type == node_type) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
if (go_into_or && (node->nod_type == nod_or)) {
|
||||||
|
return expression_contains(node->nod_arg[0], node_type, go_into_or, go_into_and) ||
|
||||||
|
expression_contains(node->nod_arg[1], node_type, go_into_or, go_into_and);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (go_into_and && (node->nod_type == nod_and)) {
|
||||||
|
return expression_contains(node->nod_arg[0], node_type, go_into_or, go_into_and) ||
|
||||||
|
expression_contains(node->nod_arg[1], node_type, go_into_or, go_into_and);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef EXPRESSION_INDICES
|
#ifdef EXPRESSION_INDICES
|
||||||
static bool expression_equal(thread_db* tdbb, jrd_nod* node1, jrd_nod* node2)
|
static bool expression_equal(thread_db* tdbb, jrd_nod* node1, jrd_nod* node2)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user