8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 00:03:03 +01:00

Fixed bug CORE-2311 : Possible memory leak in WITH RECURSIVE query

This commit is contained in:
hvlad 2009-02-08 15:50:12 +00:00
parent 6a93123a8c
commit 0950f997fb
3 changed files with 131 additions and 15 deletions

View File

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

View File

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

View File

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