diff --git a/src/jrd/opt.cpp b/src/jrd/opt.cpp index b1d949e377..704e02ff79 100644 --- a/src/jrd/opt.cpp +++ b/src/jrd/opt.cpp @@ -159,6 +159,7 @@ static jrd_nod* make_missing(thread_db*, OptimizerBlk*, jrd_rel*, jrd_nod*, USHO static jrd_nod* make_starts(thread_db*, OptimizerBlk*, jrd_rel*, jrd_nod*, USHORT, index_desc*); static bool map_equal(const jrd_nod*, const jrd_nod*, const jrd_nod*); static void mark_indices(CompilerScratch::csb_repeat*, SSHORT); +static void mark_rsb_recursive(RecordSource*); static int match_index(thread_db*, OptimizerBlk*, SSHORT, jrd_nod*, const index_desc*); static bool match_indices(thread_db*, OptimizerBlk*, SSHORT, jrd_nod*, const index_desc*); static bool node_equality(const jrd_nod*, const jrd_nod*); @@ -2515,7 +2516,7 @@ static bool dump_rsb(const jrd_req* request, *buffer++ = isc_info_rsb_union; break; - case rsb_recurse: + case rsb_recursive_union: *buffer++ = isc_info_rsb_recursive; break; @@ -2576,7 +2577,7 @@ static bool dump_rsb(const jrd_req* request, break; case rsb_union: - case rsb_recurse: + case rsb_recursive_union: *buffer++ = rsb->rsb_count / 2; ptr = rsb->rsb_arg; for (end = ptr + rsb->rsb_count; ptr < end; ptr++) { @@ -3520,7 +3521,7 @@ static void find_rsbs(RecordSource* rsb, StreamStack* stream_list, RsbStack* rsb switch (rsb->rsb_type) { case rsb_union: - case rsb_recurse: + case rsb_recursive_union: case rsb_aggregate: case rsb_procedure: if (rsb_list) { @@ -3598,7 +3599,7 @@ static void find_used_streams(const RecordSource* rsb, UCHAR* streams) case rsb_procedure: case rsb_sequential: case rsb_union: - case rsb_recurse: + case rsb_recursive_union: case rsb_virt_sequential: stream = rsb->rsb_stream; found = true; @@ -5732,7 +5733,7 @@ static RecordSource* gen_union(thread_db* tdbb, FB_NEW_RPT(*tdbb->getDefaultPool(), count + nstreams + 1 + (recurse ? 2 : 0)) RecordSource(); if (recurse) { - rsb->rsb_type = rsb_recurse; + rsb->rsb_type = rsb_recursive_union; rsb->rsb_impure = CMP_impure(csb, sizeof(struct irsb_recurse)); } else @@ -5779,9 +5780,12 @@ static RecordSource* gen_union(thread_db* tdbb, // hvlad: save size of inner impure area and context of mapped record // for recursive processing later - if (recurse) { + if (recurse) + { *rsb_ptr++ = (RecordSource*)(IPTR) (csb->csb_impure - rsb->rsb_impure); *rsb_ptr = (RecordSource*) (IPTR) union_node->nod_arg[e_uni_map_stream]; + + mark_rsb_recursive(rsb); } return rsb; } @@ -6787,6 +6791,88 @@ static void mark_indices(CompilerScratch::csb_repeat* csb_tail, SSHORT relation_ } +static void mark_rsb_recursive(RecordSource* rsb) +{ +/************************************** + * + * m a r k _ r s b _ r e c u r s i v e + * + ************************************** + * + * Functional description + * Mark all RSB's at sub-tree as recursive. + * + **************************************/ + + while (true) + { + rsb->rsb_flags |= rsb_recursive; + switch (rsb->rsb_type) + { + case rsb_indexed: + case rsb_navigate: + case rsb_sequential: + case rsb_ext_sequential: + case rsb_ext_indexed: + case rsb_ext_dbkey: + case rsb_virt_sequential: + case rsb_procedure: + return; + + case rsb_first: + case rsb_skip: + case rsb_boolean: + case rsb_aggregate: + case rsb_sort: + rsb = rsb->rsb_next; + break; + + case rsb_cross: + { + RecordSource** ptr = rsb->rsb_arg; + const RecordSource* const* const end = ptr + rsb->rsb_count; + for (; ptr < end; ptr++) + mark_rsb_recursive(*ptr); + } + return; + + case rsb_left_cross: + mark_rsb_recursive(rsb->rsb_arg[RSB_LEFT_outer]); + mark_rsb_recursive(rsb->rsb_arg[RSB_LEFT_inner]); + return; + + case rsb_merge: + { + RecordSource** ptr = rsb->rsb_arg; + const RecordSource* const* const end = ptr + rsb->rsb_count * 2; + + for (; ptr < end; ptr += 2) + mark_rsb_recursive(*ptr); + } + return; + + case rsb_union: + { + RecordSource** ptr = rsb->rsb_arg; + const RecordSource* const* end = ptr + rsb->rsb_count; + + for (; ptr < end; ptr += 2) + mark_rsb_recursive(*ptr); + } + return; + + case rsb_recursive_union: + mark_rsb_recursive(rsb->rsb_arg[0]); + mark_rsb_recursive(rsb->rsb_arg[2]); + return; + + default: + BUGCHECK(166); /* msg 166 invalid rsb type */ + } + } +} + + static int match_index(thread_db* tdbb, OptimizerBlk* opt, SSHORT stream, jrd_nod* boolean, const index_desc* idx) { diff --git a/src/jrd/rse.cpp b/src/jrd/rse.cpp index 75853af97b..5b110d3763 100644 --- a/src/jrd/rse.cpp +++ b/src/jrd/rse.cpp @@ -138,14 +138,21 @@ void RSE_close(thread_db* tdbb, RecordSource* rsb) * * Functional description * + * hvlad: for RSB's marked as part of recursive sub-tree we must free + * resources stored in impure area as this area is over-written when + * recursion returns to the upper level. See also RSBRecurse::get() + * **************************************/ SET_TDBB(tdbb); invalidate_child_rpbs(tdbb, rsb); + jrd_req* request = tdbb->getRequest(); + const bool bFreeAll = (rsb->rsb_flags & rsb_recursive); + while (true) { - irsb_sort* impure = (irsb_sort*) ((UCHAR*) tdbb->getRequest() + rsb->rsb_impure); + irsb_sort* impure = (irsb_sort*) ((UCHAR*) request + rsb->rsb_impure); if (!(impure->irsb_flags & irsb_open)) return; @@ -154,12 +161,34 @@ void RSE_close(thread_db* tdbb, RecordSource* rsb) switch (rsb->rsb_type) { case rsb_indexed: + if (bFreeAll) + { + irsb_index* imp_idx = (irsb_index*) impure; + if (imp_idx->irsb_bitmap) + { + delete (*imp_idx->irsb_bitmap); + *imp_idx->irsb_bitmap = NULL; + } + } + return; + case rsb_navigate: + if (bFreeAll) + { + irsb_nav* imp_nav = (irsb_nav*) impure; + if (imp_nav->irsb_nav_bitmap) + { + delete (*imp_nav->irsb_nav_bitmap); + *imp_nav->irsb_nav_bitmap = NULL; + } + + delete imp_nav->irsb_nav_records_visited; + imp_nav->irsb_nav_records_visited = NULL; + } return; case rsb_sequential: { - jrd_req* request = tdbb->getRequest(); record_param* rpb = &request->req_rpb[rsb->rsb_stream]; if (rpb->getWindow(tdbb).win_flags & WIN_large_scan && rpb->rpb_relation->rel_scan_count) @@ -214,7 +243,7 @@ void RSE_close(thread_db* tdbb, RecordSource* rsb) } break; - case rsb_recurse: + case rsb_recursive_union: RSBRecurse::close(tdbb, rsb, (irsb_recurse*)impure); return; @@ -492,7 +521,7 @@ void RSE_open(thread_db* tdbb, RecordSource* rsb) } break; - case rsb_recurse: + case rsb_recursive_union: RSBRecurse::open(tdbb, rsb, (irsb_recurse*)impure); return; @@ -2334,7 +2363,7 @@ static bool get_record(thread_db* tdbb, return false; break; - case rsb_recurse: + case rsb_recursive_union: if (!RSBRecurse::get(tdbb, rsb, (irsb_recurse*)impure)) return false; break; @@ -2561,7 +2590,7 @@ static void invalidate_child_rpbs(thread_db* tdbb, RecordSource* rsb) } return; - case rsb_recurse: + case rsb_recursive_union: { // hvlad: recursive CTE is always a 'union all' of // exactly two members. @@ -3104,7 +3133,7 @@ static void pop_rpbs(jrd_req* request, RecordSource* rsb) case rsb_ext_dbkey: case rsb_navigate: case rsb_union: - case rsb_recurse: + case rsb_recursive_union: case rsb_aggregate: case rsb_virt_sequential: { @@ -3219,7 +3248,7 @@ static void push_rpbs(thread_db* tdbb, jrd_req* request, RecordSource* rsb) case rsb_ext_dbkey: case rsb_navigate: case rsb_union: - case rsb_recurse: + case rsb_recursive_union: case rsb_aggregate: case rsb_virt_sequential: { diff --git a/src/jrd/rse.h b/src/jrd/rse.h index e13e20a305..8a4140efd5 100644 --- a/src/jrd/rse.h +++ b/src/jrd/rse.h @@ -75,7 +75,7 @@ enum rsb_t rsb_left_cross, // left outer join as a nested loop rsb_procedure, // stored procedure rsb_virt_sequential, // sequential access to a virtual table - rsb_recurse // Recursive union + rsb_recursive_union // Recursive union }; @@ -121,6 +121,7 @@ const USHORT rsb_singular = 1; // singleton select, expect 0 or 1 records const USHORT rsb_descending = 4; // an ascending index is being used for a descending sort or vice versa const USHORT rsb_project = 8; // projection on this stream is requested const USHORT rsb_writelock = 16; // records should be locked for writing +const USHORT rsb_recursive = 32; // this rsb is a sub_rsb of recursive rsb // special argument positions within the RecordSource