To suppress memory leakage in long-lived Lists, lremove() should pfree

the cons cell it's deleting from the list.  Do this, and fix a few callers
that were bogusly assuming it wouldn't free the cons cell.
This commit is contained in:
Tom Lane 2002-12-17 01:18:35 +00:00
parent 9f76d0d926
commit e932a724a4
6 changed files with 51 additions and 32 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.42 2002/11/24 21:52:13 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.43 2002/12/17 01:18:18 tgl Exp $
*
* NOTES
* XXX a few of the following functions are duplicated to handle
@ -269,7 +269,6 @@ llasti(List *l)
* Free the List nodes of a list
* The pointed-to nodes, if any, are NOT freed.
* This works for integer lists too.
*
*/
void
freeList(List *list)
@ -487,6 +486,7 @@ lremove(void *elem, List *list)
result = lnext(l);
else
lnext(prev) = lnext(l);
pfree(l);
}
return result;
}
@ -518,6 +518,7 @@ LispRemove(void *elem, List *list)
result = lnext(l);
else
lnext(prev) = lnext(l);
pfree(l);
}
return result;
}
@ -545,6 +546,7 @@ lremovei(int elem, List *list)
result = lnext(l);
else
lnext(prev) = lnext(l);
pfree(l);
}
return result;
}

View File

@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.42 2002/12/12 15:49:32 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.43 2002/12/17 01:18:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -101,12 +101,17 @@ add_equijoined_keys(Query *root, RestrictInfo *restrictinfo)
*/
newset = NIL;
foreach(cursetlink, root->equi_key_list)
/* cannot use foreach here because of possible lremove */
cursetlink = root->equi_key_list;
while (cursetlink)
{
List *curset = lfirst(cursetlink);
bool item1here = member(item1, curset);
bool item2here = member(item2, curset);
/* must advance cursetlink before lremove possibly pfree's it */
cursetlink = lnext(cursetlink);
if (item1here || item2here)
{
/*
@ -128,9 +133,7 @@ add_equijoined_keys(Query *root, RestrictInfo *restrictinfo)
newset = set_union(newset, curset);
/*
* Remove old set from equi_key_list. NOTE this does not
* change lnext(cursetlink), so the foreach loop doesn't
* break.
* Remove old set from equi_key_list.
*/
root->equi_key_list = lremove(curset, root->equi_key_list);
freeList(curset); /* might as well recycle old cons cells */

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.78 2002/12/12 15:49:32 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.79 2002/12/17 01:18:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -910,13 +910,18 @@ qual_is_redundant(Query *root,
do
{
someadded = false;
foreach(olditem, oldquals)
/* cannot use foreach here because of possible lremove */
olditem = oldquals;
while (olditem)
{
RestrictInfo *oldrinfo = (RestrictInfo *) lfirst(olditem);
Node *oldleft = (Node *) get_leftop(oldrinfo->clause);
Node *oldright = (Node *) get_rightop(oldrinfo->clause);
Node *newguy = NULL;
/* must advance olditem before lremove possibly pfree's it */
olditem = lnext(olditem);
if (member(oldleft, equalvars))
newguy = oldright;
else if (member(oldright, equalvars))
@ -930,8 +935,6 @@ qual_is_redundant(Query *root,
/*
* Remove this qual from list, since we don't need it anymore.
* Note this doesn't break the foreach() loop, since lremove
* doesn't touch the next-link of the removed cons cell.
*/
oldquals = lremove(oldrinfo, oldquals);
}

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.257 2002/12/13 19:45:56 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.258 2002/12/17 01:18:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -521,32 +521,38 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
* Prepare columns for assignment to target table.
*/
attnos = attrnos;
foreach(tl, qry->targetList)
/* cannot use foreach here because of possible lremove */
tl = qry->targetList;
while (tl)
{
TargetEntry *tle = (TargetEntry *) lfirst(tl);
ResTarget *col;
/* must advance tl before lremove possibly pfree's it */
tl = lnext(tl);
if (icolumns == NIL || attnos == NIL)
elog(ERROR, "INSERT has more expressions than target columns");
col = (ResTarget *) lfirst(icolumns);
Assert(IsA(col, ResTarget));
/*
* When the value is to be set to the column default we can simply
* drop it now and handle it later on using methods for missing
* drop the TLE now and handle it later on using methods for missing
* columns.
*/
if (!IsA(tle, InsertDefault))
if (IsA(tle, InsertDefault))
{
Assert(IsA(col, ResTarget));
Assert(!tle->resdom->resjunk);
updateTargetListEntry(pstate, tle, col->name, lfirsti(attnos),
col->indirection);
qry->targetList = lremove(tle, qry->targetList);
/* Note: the stmt->cols list is not adjusted to match */
}
else
{
icolumns = lremove(icolumns, icolumns);
attnos = lremove(attnos, attnos);
qry->targetList = lremove(tle, qry->targetList);
/* Normal case */
Assert(!tle->resdom->resjunk);
updateTargetListEntry(pstate, tle, col->name, lfirsti(attnos),
col->indirection);
}
icolumns = lnext(icolumns);
@ -554,8 +560,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
}
/*
* Ensure that the targetlist has the same number of entries that
* were present in the columns list. Don't do the check for select
* Ensure that the targetlist has the same number of entries that
* were present in the columns list. Don't do the check unless
* an explicit columns list was given, though.
* statements.
*/
if (stmt->cols != NIL && (icolumns != NIL || attnos != NIL))

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.114 2002/12/12 15:49:40 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.115 2002/12/17 01:18:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -205,9 +205,11 @@ adjustJoinTreeList(Query *parsetree, bool removert, int rt_index)
{
RangeTblRef *rtr = lfirst(jjt);
if (IsA(rtr, RangeTblRef) &&rtr->rtindex == rt_index)
if (IsA(rtr, RangeTblRef) &&
rtr->rtindex == rt_index)
{
newjointree = lremove(rtr, newjointree);
/* foreach is safe because we exit loop after lremove... */
break;
}
}

View File

@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.123 2002/12/12 15:49:40 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.124 2002/12/17 01:18:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1953,10 +1953,15 @@ estimate_num_groups(Query *root, List *groupClauses, double input_rows)
if (HeapTupleIsValid(statsTuple))
ReleaseSysCache(statsTuple);
foreach(l2, varinfos)
/* cannot use foreach here because of possible lremove */
l2 = varinfos;
while (l2)
{
MyVarInfo *varinfo = (MyVarInfo *) lfirst(l2);
/* must advance l2 before lremove possibly pfree's it */
l2 = lnext(l2);
if (var->varno != varinfo->var->varno &&
vars_known_equal(root, var, varinfo->var))
{
@ -1969,10 +1974,7 @@ estimate_num_groups(Query *root, List *groupClauses, double input_rows)
}
else
{
/*
* Delete the older item. We assume lremove() will not
* break the lnext link of the item...
*/
/* Delete the older item */
varinfos = lremove(varinfo, varinfos);
}
}