8
0
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:
arnobrinkman 2004-03-21 02:07:48 +00:00
parent 5ddd2d1cb0
commit b355d3411e

View File

@ -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)
{ {