8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 16:03:02 +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_rsb(const jrd_req*, const Rsb*, SCHAR**, SSHORT*);
static bool estimate_cost(thread_db*, OPT, USHORT, double *, double *);
static bool expression_contains(const jrd_nod*, NOD_T, bool, bool);
#ifdef EXPRESSION_INDICES
static bool expression_equal(thread_db*, jrd_nod*, jrd_nod*);
#endif
@ -180,7 +181,8 @@ static SSHORT sort_indices_by_priority(Csb::csb_repeat*, IDX **, UINT64 *);
#define DEBUG_NONE 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
inline void SET_DEP_BIT(ULONG* array, const SLONG bit)
@ -361,10 +363,9 @@ Rsb* OPT_compile(thread_db* tdbb,
jrd_nod* project = rse->rse_projection;
jrd_nod* aggregate = rse->rse_aggregate;
// put any additional booleans on the conjunct stack, and see if we
// can generate additional booleans by associativity--this will help
// to utilize indices that we might not have noticed
// put any additional booleans on the conjunct stack, and see if we
// can generate additional booleans by associativity--this will help
// to utilize indices that we might not have noticed
if (rse->rse_boolean) {
conjunct_count =
decompose(tdbb, rse->rse_boolean, &conjunct_stack, csb);
@ -372,19 +373,26 @@ Rsb* OPT_compile(thread_db* tdbb,
conjunct_count += distribute_equalities(&conjunct_stack, csb, conjunct_count);
// find the end of the conjunct stack.
// find the end of the conjunct stack.
lls** stack_end = &conjunct_stack;
while (*stack_end) {
stack_end = &(*stack_end)->lls_next;
}
// clear the csb_active flag of all streams in the rse
// 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
set_rse_inactive(csb, rse);
UCHAR* p = streams + 1;
// go through the record selection expression generating
// record source blocks for all streams
// go through the record selection expression generating
// record source blocks for all streams
// CVC: I defined this var here because it's assigned inside an if() shortly
// below but it's used later in the loop always, so I assume the idea is that
@ -461,9 +469,40 @@ Rsb* OPT_compile(thread_db* tdbb,
csb->csb_rpt[outer_streams[i]].csb_flags |= csb_active;
}
}
*stack_end = parent_stack;
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;
}
rsb = OPT_compile(tdbb, csb, (RSE) node, conjunct_stack);
*stack_end = NULL;
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;
}
if (rse->rse_jointype == blr_left) {
for (SSHORT i = 1; i <= outer_streams[0]; i++) {
csb->csb_rpt[outer_streams[i]].csb_flags &= ~csb_active;
@ -543,36 +582,37 @@ Rsb* OPT_compile(thread_db* tdbb,
}
}
// this is an attempt to make sure we have a large enough cache to
// efficiently retrieve this query; make sure the cache has a minimum
// number of pages for each stream in the RSE (the number is just a guess)
// this is an attempt to make sure we have a large enough cache to
// efficiently retrieve this query; make sure the cache has a minimum
// number of pages for each stream in the RSE (the number is just a guess)
if (streams[0] > 5) {
CCH_expand(tdbb, (ULONG) (streams[0] * CACHE_PAGES_PER_STREAM));
}
// At this point we are ready to start optimizing.
// We will use the opt block to hold information of
// a global nature, meaning that it needs to stick
// around for the rest of the optimization process.
// At this point we are ready to start optimizing.
// We will use the opt block to hold information of
// a global nature, meaning that it needs to stick
// around for the rest of the optimization process.
// first fill out the conjuncts at the end of opt
// first fill out the conjuncts at the end of opt
opt_->opt_base_conjuncts = (SSHORT) conjunct_count;
// Check if size of optimizer block exceeded.
// Check if size of optimizer block exceeded.
if (conjunct_count > MAX_CONJUNCTS) {
ERR_post(isc_optimizer_blk_exc, 0);
// Msg442: size of optimizer block exceeded
}
// AB: Because know we're going to use both parent & conjunct_stack
// try to again to make additional conjuncts for an inner join,
// but be sure that opt_->opt_base_conjuncts contains the real "base"
// AB: Because know we're going to use both parent & conjunct_stack
// try to again to make additional conjuncts for an inner join,
// but be sure that opt_->opt_base_conjuncts contains the real "base"
// find the end of the conjunct stack.
// find the end of the conjunct stack.
for (stack_end = &conjunct_stack; *stack_end;
stack_end = &(*stack_end)->lls_next);
const SLONG saved_conjunct_count = conjunct_count;
*stack_end = parent_stack;
*stack_end = parent_stack;
conjunct_count += distribute_equalities(&conjunct_stack, csb, conjunct_count);
if (parent_stack) {
// Find parent_stack position and reset it to NULL
@ -590,7 +630,7 @@ Rsb* OPT_compile(thread_db* tdbb,
SSHORT i;
// AB: If equality nodes could be made get them first from the stack
// AB: If equality nodes could be made get them first from the stack
for (i = saved_conjunct_count; i < conjunct_count; i++) {
jrd_nod* node = (jrd_nod*) LLS_POP(&conjunct_stack);
opt_->opt_conjuncts[i].opt_conjunct_node = node;
@ -603,25 +643,25 @@ Rsb* OPT_compile(thread_db* tdbb,
compute_dependencies(node, opt_->opt_conjuncts[i].opt_dependencies);
}
// Store the conjuncts from the parent rse. But don't fiddle with
// the parent's stack itself.
// Store the conjuncts from the parent rse. But don't fiddle with
// the parent's stack itself.
for (; parent_stack && conjunct_count < MAX_CONJUNCTS;
parent_stack = parent_stack->lls_next, conjunct_count++)
parent_stack = parent_stack->lls_next, conjunct_count++)
{
opt_->opt_conjuncts.grow(conjunct_count + 1);
jrd_nod* node = (jrd_nod*) parent_stack->lls_object;
opt_->opt_conjuncts[conjunct_count].opt_conjunct_node = node;
compute_dependencies(node,
opt_->opt_conjuncts[conjunct_count].opt_dependencies);
opt_->opt_conjuncts[conjunct_count].opt_dependencies);
}
// Check if size of optimizer block exceeded.
// Check if size of optimizer block exceeded.
if (parent_stack) {
ERR_post(isc_optimizer_blk_exc, 0);
// Msg442: size of optimizer block exceeded
}
// attempt to optimize aggregates via an index, if possible
// attempt to optimize aggregates via an index, if possible
if (aggregate && !sort && !project) {
sort = aggregate;
}
@ -629,12 +669,12 @@ Rsb* OPT_compile(thread_db* tdbb,
rse->rse_aggregate = aggregate = NULL;
}
// AB: Mark the previous used streams (sub-rse's) as active
// AB: Mark the previous used streams (sub-rse's) as active
for (i = 1; i <= sub_streams[0]; i++) {
csb->csb_rpt[sub_streams[i]].csb_flags |= csb_active;
}
// outer joins require some extra processing
// outer joins require some extra processing
if (rse->rse_jointype != blr_inner) {
rsb = gen_outer(tdbb, opt_, rse, rivers_stack, &sort, &project);
}
@ -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
static bool expression_equal(thread_db* tdbb, jrd_nod* node1, jrd_nod* node2)
{