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:
parent
6a93123a8c
commit
0950f997fb
@ -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)
|
||||
{
|
||||
|
@ -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:
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user