Commit 8a6ac83d authored by Tom Lane's avatar Tom Lane

Fix some planner performance problems with large WHERE clauses, by

introducing new 'FastList' list-construction subroutines to use in
hot spots.  This avoids the O(N^2) behavior of repeated lappend's
by keeping a tail pointer, while not changing behavior by reversing
list order as the lcons() method would do.
parent 0f3c68aa
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.129 2003/05/02 20:54:33 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.130 2003/05/28 22:32:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2320,9 +2320,10 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2320,9 +2320,10 @@ ExecInitExpr(Expr *node, PlanState *parent)
{ {
CaseExpr *caseexpr = (CaseExpr *) node; CaseExpr *caseexpr = (CaseExpr *) node;
CaseExprState *cstate = makeNode(CaseExprState); CaseExprState *cstate = makeNode(CaseExprState);
List *outlist = NIL; FastList outlist;
List *inlist; List *inlist;
FastListInit(&outlist);
foreach(inlist, caseexpr->args) foreach(inlist, caseexpr->args)
{ {
CaseWhen *when = (CaseWhen *) lfirst(inlist); CaseWhen *when = (CaseWhen *) lfirst(inlist);
...@@ -2332,9 +2333,9 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2332,9 +2333,9 @@ ExecInitExpr(Expr *node, PlanState *parent)
wstate->xprstate.expr = (Expr *) when; wstate->xprstate.expr = (Expr *) when;
wstate->expr = ExecInitExpr(when->expr, parent); wstate->expr = ExecInitExpr(when->expr, parent);
wstate->result = ExecInitExpr(when->result, parent); wstate->result = ExecInitExpr(when->result, parent);
outlist = lappend(outlist, wstate); FastAppend(&outlist, wstate);
} }
cstate->args = outlist; cstate->args = FastListValue(&outlist);
/* caseexpr->arg should be null by now */ /* caseexpr->arg should be null by now */
Assert(caseexpr->arg == NULL); Assert(caseexpr->arg == NULL);
cstate->defresult = ExecInitExpr(caseexpr->defresult, parent); cstate->defresult = ExecInitExpr(caseexpr->defresult, parent);
...@@ -2345,18 +2346,19 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2345,18 +2346,19 @@ ExecInitExpr(Expr *node, PlanState *parent)
{ {
ArrayExpr *arrayexpr = (ArrayExpr *) node; ArrayExpr *arrayexpr = (ArrayExpr *) node;
ArrayExprState *astate = makeNode(ArrayExprState); ArrayExprState *astate = makeNode(ArrayExprState);
List *outlist = NIL; FastList outlist;
List *inlist; List *inlist;
FastListInit(&outlist);
foreach(inlist, arrayexpr->elements) foreach(inlist, arrayexpr->elements)
{ {
Expr *e = (Expr *) lfirst(inlist); Expr *e = (Expr *) lfirst(inlist);
ExprState *estate; ExprState *estate;
estate = ExecInitExpr(e, parent); estate = ExecInitExpr(e, parent);
outlist = lappend(outlist, estate); FastAppend(&outlist, estate);
} }
astate->elements = outlist; astate->elements = FastListValue(&outlist);
/* do one-time catalog lookup for type info */ /* do one-time catalog lookup for type info */
get_typlenbyvalalign(arrayexpr->element_typeid, get_typlenbyvalalign(arrayexpr->element_typeid,
&astate->elemlength, &astate->elemlength,
...@@ -2369,18 +2371,19 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2369,18 +2371,19 @@ ExecInitExpr(Expr *node, PlanState *parent)
{ {
CoalesceExpr *coalesceexpr = (CoalesceExpr *) node; CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
CoalesceExprState *cstate = makeNode(CoalesceExprState); CoalesceExprState *cstate = makeNode(CoalesceExprState);
List *outlist = NIL; FastList outlist;
List *inlist; List *inlist;
FastListInit(&outlist);
foreach(inlist, coalesceexpr->args) foreach(inlist, coalesceexpr->args)
{ {
Expr *e = (Expr *) lfirst(inlist); Expr *e = (Expr *) lfirst(inlist);
ExprState *estate; ExprState *estate;
estate = ExecInitExpr(e, parent); estate = ExecInitExpr(e, parent);
outlist = lappend(outlist, estate); FastAppend(&outlist, estate);
} }
cstate->args = outlist; cstate->args = FastListValue(&outlist);
state = (ExprState *) cstate; state = (ExprState *) cstate;
} }
break; break;
...@@ -2434,17 +2437,18 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2434,17 +2437,18 @@ ExecInitExpr(Expr *node, PlanState *parent)
break; break;
case T_List: case T_List:
{ {
List *outlist = NIL; FastList outlist;
List *inlist; List *inlist;
FastListInit(&outlist);
foreach(inlist, (List *) node) foreach(inlist, (List *) node)
{ {
outlist = lappend(outlist, FastAppend(&outlist,
ExecInitExpr((Expr *) lfirst(inlist), ExecInitExpr((Expr *) lfirst(inlist),
parent)); parent));
} }
/* Don't fall through to the "common" code below */ /* Don't fall through to the "common" code below */
return (ExprState *) outlist; return (ExprState *) FastListValue(&outlist);
} }
default: default:
elog(ERROR, "ExecInitExpr: unknown expression type %d", elog(ERROR, "ExecInitExpr: unknown expression type %d",
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.48 2003/02/09 06:56:27 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.49 2003/05/28 22:32:49 tgl Exp $
* *
* NOTES * NOTES
* XXX a few of the following functions are duplicated to handle * XXX a few of the following functions are duplicated to handle
...@@ -141,9 +141,9 @@ lconso(Oid datum, List *list) ...@@ -141,9 +141,9 @@ lconso(Oid datum, List *list)
* MORE EXPENSIVE THAN lcons * MORE EXPENSIVE THAN lcons
*/ */
List * List *
lappend(List *list, void *obj) lappend(List *list, void *datum)
{ {
return nconc(list, makeList1(obj)); return nconc(list, makeList1(datum));
} }
/* /*
...@@ -195,6 +195,120 @@ nconc(List *l1, List *l2) ...@@ -195,6 +195,120 @@ nconc(List *l1, List *l2)
return l1; /* list1 is now list1+list2 */ return l1; /* list1 is now list1+list2 */
} }
/*
* FastAppend - append to a FastList.
*
* For long lists this is significantly faster than repeated lappend's,
* since we avoid having to chase down the list again each time.
*/
void
FastAppend(FastList *fl, void *datum)
{
List *cell = makeList1(datum);
if (fl->tail)
{
lnext(fl->tail) = cell;
fl->tail = cell;
}
else
{
/* First cell of list */
Assert(fl->head == NIL);
fl->head = fl->tail = cell;
}
}
/*
* FastAppendi - same for integers
*/
void
FastAppendi(FastList *fl, int datum)
{
List *cell = makeListi1(datum);
if (fl->tail)
{
lnext(fl->tail) = cell;
fl->tail = cell;
}
else
{
/* First cell of list */
Assert(fl->head == NIL);
fl->head = fl->tail = cell;
}
}
/*
* FastAppendo - same for Oids
*/
void
FastAppendo(FastList *fl, Oid datum)
{
List *cell = makeListo1(datum);
if (fl->tail)
{
lnext(fl->tail) = cell;
fl->tail = cell;
}
else
{
/* First cell of list */
Assert(fl->head == NIL);
fl->head = fl->tail = cell;
}
}
/*
* FastConc - nconc() for FastList building
*
* Note that the cells of the second argument are absorbed into the FastList.
*/
void
FastConc(FastList *fl, List *cells)
{
if (cells == NIL)
return; /* nothing to do */
if (fl->tail)
{
lnext(fl->tail) = cells;
}
else
{
/* First cell of list */
Assert(fl->head == NIL);
fl->head = cells;
}
while (lnext(cells) != NIL)
cells = lnext(cells);
fl->tail = cells;
}
/*
* FastConcFast - nconc() for FastList building
*
* Note that the cells of the second argument are absorbed into the first.
*/
void
FastConcFast(FastList *fl, FastList *fl2)
{
if (fl2->head == NIL)
return; /* nothing to do */
if (fl->tail)
{
lnext(fl->tail) = fl2->head;
}
else
{
/* First cell of list */
Assert(fl->head == NIL);
fl->head = fl2->head;
}
fl->tail = fl2->tail;
}
/* /*
* nth * nth
* *
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.142 2003/05/28 16:03:56 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.143 2003/05/28 22:32:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -417,10 +417,11 @@ extract_or_indexqual_conditions(RelOptInfo *rel, ...@@ -417,10 +417,11 @@ extract_or_indexqual_conditions(RelOptInfo *rel,
IndexOptInfo *index, IndexOptInfo *index,
Expr *orsubclause) Expr *orsubclause)
{ {
List *quals = NIL; FastList quals;
int indexcol = 0; int indexcol = 0;
Oid *classes = index->classlist; Oid *classes = index->classlist;
FastListInit(&quals);
/* /*
* Extract relevant indexclauses in indexkey order. This is * Extract relevant indexclauses in indexkey order. This is
* essentially just like group_clauses_by_indexkey() except that the * essentially just like group_clauses_by_indexkey() except that the
...@@ -430,9 +431,10 @@ extract_or_indexqual_conditions(RelOptInfo *rel, ...@@ -430,9 +431,10 @@ extract_or_indexqual_conditions(RelOptInfo *rel,
do do
{ {
Oid curClass = classes[0]; Oid curClass = classes[0];
List *clausegroup = NIL; FastList clausegroup;
List *item; List *item;
FastListInit(&clausegroup);
if (and_clause((Node *) orsubclause)) if (and_clause((Node *) orsubclause))
{ {
foreach(item, ((BoolExpr *) orsubclause)->args) foreach(item, ((BoolExpr *) orsubclause)->args)
...@@ -442,21 +444,23 @@ extract_or_indexqual_conditions(RelOptInfo *rel, ...@@ -442,21 +444,23 @@ extract_or_indexqual_conditions(RelOptInfo *rel,
if (match_clause_to_indexcol(rel, index, if (match_clause_to_indexcol(rel, index,
indexcol, curClass, indexcol, curClass,
subsubclause)) subsubclause))
clausegroup = nconc(clausegroup, FastConc(&clausegroup,
expand_indexqual_condition(subsubclause, expand_indexqual_condition(subsubclause,
curClass)); curClass));
} }
} }
else if (match_clause_to_indexcol(rel, index, else if (match_clause_to_indexcol(rel, index,
indexcol, curClass, indexcol, curClass,
orsubclause)) orsubclause))
clausegroup = expand_indexqual_condition(orsubclause, curClass); FastConc(&clausegroup,
expand_indexqual_condition(orsubclause,
curClass));
/* /*
* If we found no clauses for this indexkey in the OR subclause * If we found no clauses for this indexkey in the OR subclause
* itself, try looking in the rel's top-level restriction list. * itself, try looking in the rel's top-level restriction list.
*/ */
if (clausegroup == NIL) if (FastListValue(&clausegroup) == NIL)
{ {
foreach(item, rel->baserestrictinfo) foreach(item, rel->baserestrictinfo)
{ {
...@@ -465,9 +469,9 @@ extract_or_indexqual_conditions(RelOptInfo *rel, ...@@ -465,9 +469,9 @@ extract_or_indexqual_conditions(RelOptInfo *rel,
if (match_clause_to_indexcol(rel, index, if (match_clause_to_indexcol(rel, index,
indexcol, curClass, indexcol, curClass,
rinfo->clause)) rinfo->clause))
clausegroup = nconc(clausegroup, FastConc(&clausegroup,
expand_indexqual_condition(rinfo->clause, expand_indexqual_condition(rinfo->clause,
curClass)); curClass));
} }
} }
...@@ -475,20 +479,20 @@ extract_or_indexqual_conditions(RelOptInfo *rel, ...@@ -475,20 +479,20 @@ extract_or_indexqual_conditions(RelOptInfo *rel,
* If still no clauses match this key, we're done; we don't want * If still no clauses match this key, we're done; we don't want
* to look at keys to its right. * to look at keys to its right.
*/ */
if (clausegroup == NIL) if (FastListValue(&clausegroup) == NIL)
break; break;
quals = nconc(quals, clausegroup); FastConcFast(&quals, &clausegroup);
indexcol++; indexcol++;
classes++; classes++;
} while (!DoneMatchingIndexKeys(classes)); } while (!DoneMatchingIndexKeys(classes));
if (quals == NIL) if (FastListValue(&quals) == NIL)
elog(ERROR, "extract_or_indexqual_conditions: no matching clause"); elog(ERROR, "extract_or_indexqual_conditions: no matching clause");
return quals; return FastListValue(&quals);
} }
...@@ -520,7 +524,7 @@ extract_or_indexqual_conditions(RelOptInfo *rel, ...@@ -520,7 +524,7 @@ extract_or_indexqual_conditions(RelOptInfo *rel,
static List * static List *
group_clauses_by_indexkey(RelOptInfo *rel, IndexOptInfo *index) group_clauses_by_indexkey(RelOptInfo *rel, IndexOptInfo *index)
{ {
List *clausegroup_list = NIL; FastList clausegroup_list;
List *restrictinfo_list = rel->baserestrictinfo; List *restrictinfo_list = rel->baserestrictinfo;
int indexcol = 0; int indexcol = 0;
Oid *classes = index->classlist; Oid *classes = index->classlist;
...@@ -528,12 +532,14 @@ group_clauses_by_indexkey(RelOptInfo *rel, IndexOptInfo *index) ...@@ -528,12 +532,14 @@ group_clauses_by_indexkey(RelOptInfo *rel, IndexOptInfo *index)
if (restrictinfo_list == NIL) if (restrictinfo_list == NIL)
return NIL; return NIL;
FastListInit(&clausegroup_list);
do do
{ {
Oid curClass = classes[0]; Oid curClass = classes[0];
List *clausegroup = NIL; FastList clausegroup;
List *i; List *i;
FastListInit(&clausegroup);
foreach(i, restrictinfo_list) foreach(i, restrictinfo_list)
{ {
RestrictInfo *rinfo = (RestrictInfo *) lfirst(i); RestrictInfo *rinfo = (RestrictInfo *) lfirst(i);
...@@ -543,24 +549,24 @@ group_clauses_by_indexkey(RelOptInfo *rel, IndexOptInfo *index) ...@@ -543,24 +549,24 @@ group_clauses_by_indexkey(RelOptInfo *rel, IndexOptInfo *index)
indexcol, indexcol,
curClass, curClass,
rinfo->clause)) rinfo->clause))
clausegroup = lappend(clausegroup, rinfo); FastAppend(&clausegroup, rinfo);
} }
/* /*
* If no clauses match this key, we're done; we don't want to look * If no clauses match this key, we're done; we don't want to look
* at keys to its right. * at keys to its right.
*/ */
if (clausegroup == NIL) if (FastListValue(&clausegroup) == NIL)
break; break;
clausegroup_list = lappend(clausegroup_list, clausegroup); FastAppend(&clausegroup_list, FastListValue(&clausegroup));
indexcol++; indexcol++;
classes++; classes++;
} while (!DoneMatchingIndexKeys(classes)); } while (!DoneMatchingIndexKeys(classes));
return clausegroup_list; return FastListValue(&clausegroup_list);
} }
/* /*
...@@ -580,17 +586,20 @@ static List * ...@@ -580,17 +586,20 @@ static List *
group_clauses_by_indexkey_for_join(RelOptInfo *rel, IndexOptInfo *index, group_clauses_by_indexkey_for_join(RelOptInfo *rel, IndexOptInfo *index,
Relids outer_relids, bool isouterjoin) Relids outer_relids, bool isouterjoin)
{ {
List *clausegroup_list = NIL; FastList clausegroup_list;
bool jfound = false; bool jfound = false;
int indexcol = 0; int indexcol = 0;
Oid *classes = index->classlist; Oid *classes = index->classlist;
FastListInit(&clausegroup_list);
do do
{ {
Oid curClass = classes[0]; Oid curClass = classes[0];
List *clausegroup = NIL; FastList clausegroup;
List *i; List *i;
FastListInit(&clausegroup);
/* Look for joinclauses that are usable with given outer_relids */ /* Look for joinclauses that are usable with given outer_relids */
foreach(i, rel->joininfo) foreach(i, rel->joininfo)
{ {
...@@ -614,7 +623,7 @@ group_clauses_by_indexkey_for_join(RelOptInfo *rel, IndexOptInfo *index, ...@@ -614,7 +623,7 @@ group_clauses_by_indexkey_for_join(RelOptInfo *rel, IndexOptInfo *index,
curClass, curClass,
rinfo->clause)) rinfo->clause))
{ {
clausegroup = lappend(clausegroup, rinfo); FastAppend(&clausegroup, rinfo);
jfound = true; jfound = true;
} }
} }
...@@ -634,17 +643,17 @@ group_clauses_by_indexkey_for_join(RelOptInfo *rel, IndexOptInfo *index, ...@@ -634,17 +643,17 @@ group_clauses_by_indexkey_for_join(RelOptInfo *rel, IndexOptInfo *index,
indexcol, indexcol,
curClass, curClass,
rinfo->clause)) rinfo->clause))
clausegroup = lappend(clausegroup, rinfo); FastAppend(&clausegroup, rinfo);
} }
/* /*
* If no clauses match this key, we're done; we don't want to look * If no clauses match this key, we're done; we don't want to look
* at keys to its right. * at keys to its right.
*/ */
if (clausegroup == NIL) if (FastListValue(&clausegroup) == NIL)
break; break;
clausegroup_list = lappend(clausegroup_list, clausegroup); FastAppend(&clausegroup_list, FastListValue(&clausegroup));
indexcol++; indexcol++;
classes++; classes++;
...@@ -653,12 +662,9 @@ group_clauses_by_indexkey_for_join(RelOptInfo *rel, IndexOptInfo *index, ...@@ -653,12 +662,9 @@ group_clauses_by_indexkey_for_join(RelOptInfo *rel, IndexOptInfo *index,
/* if no join clause was matched then forget it, per comments above */ /* if no join clause was matched then forget it, per comments above */
if (!jfound) if (!jfound)
{
freeList(clausegroup_list);
return NIL; return NIL;
}
return clausegroup_list; return FastListValue(&clausegroup_list);
} }
...@@ -1870,12 +1876,13 @@ match_special_index_operator(Expr *clause, Oid opclass, ...@@ -1870,12 +1876,13 @@ match_special_index_operator(Expr *clause, Oid opclass,
List * List *
expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups) expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
{ {
List *resultquals = NIL; FastList resultquals;
Oid *classes = index->classlist; Oid *classes = index->classlist;
if (clausegroups == NIL) if (clausegroups == NIL)
return NIL; return NIL;
FastListInit(&resultquals);
do do
{ {
Oid curClass = classes[0]; Oid curClass = classes[0];
...@@ -1885,9 +1892,9 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups) ...@@ -1885,9 +1892,9 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
{ {
RestrictInfo *rinfo = (RestrictInfo *) lfirst(i); RestrictInfo *rinfo = (RestrictInfo *) lfirst(i);
resultquals = nconc(resultquals, FastConc(&resultquals,
expand_indexqual_condition(rinfo->clause, expand_indexqual_condition(rinfo->clause,
curClass)); curClass));
} }
clausegroups = lnext(clausegroups); clausegroups = lnext(clausegroups);
...@@ -1898,7 +1905,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups) ...@@ -1898,7 +1905,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
Assert(clausegroups == NIL); /* else more groups than indexkeys... */ Assert(clausegroups == NIL); /* else more groups than indexkeys... */
return resultquals; return FastListValue(&resultquals);
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.49 2002/12/12 15:49:31 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.50 2003/05/28 22:32:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -149,10 +149,12 @@ best_or_subclause_indices(Query *root, ...@@ -149,10 +149,12 @@ best_or_subclause_indices(Query *root,
List *indices, List *indices,
IndexPath *pathnode) IndexPath *pathnode)
{ {
FastList infos;
FastList quals;
List *slist; List *slist;
pathnode->indexinfo = NIL; FastListInit(&infos);
pathnode->indexqual = NIL; FastListInit(&quals);
pathnode->path.startup_cost = 0; pathnode->path.startup_cost = 0;
pathnode->path.total_cost = 0; pathnode->path.total_cost = 0;
...@@ -170,14 +172,17 @@ best_or_subclause_indices(Query *root, ...@@ -170,14 +172,17 @@ best_or_subclause_indices(Query *root,
Assert(best_indexinfo != NULL); Assert(best_indexinfo != NULL);
pathnode->indexinfo = lappend(pathnode->indexinfo, best_indexinfo); FastAppend(&infos, best_indexinfo);
pathnode->indexqual = lappend(pathnode->indexqual, best_indexqual); FastAppend(&quals, best_indexqual);
if (slist == subclauses) /* first scan? */ if (slist == subclauses) /* first scan? */
pathnode->path.startup_cost = best_startup_cost; pathnode->path.startup_cost = best_startup_cost;
pathnode->path.total_cost += best_total_cost; pathnode->path.total_cost += best_total_cost;
indices = lnext(indices); indices = lnext(indices);
} }
pathnode->indexinfo = FastListValue(&infos);
pathnode->indexqual = FastListValue(&quals);
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepqual.c,v 1.34 2002/12/12 15:49:32 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepqual.c,v 1.35 2003/05/28 22:32:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -21,8 +21,12 @@ ...@@ -21,8 +21,12 @@
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
static Expr *flatten_andors(Expr *qual); static Expr *flatten_andors(Expr *qual);
static List *pull_ors(List *orlist); static void flatten_andors_and_walker(FastList *out_list, List *andlist);
static void flatten_andors_or_walker(FastList *out_list, List *orlist);
static List *pull_ands(List *andlist); static List *pull_ands(List *andlist);
static void pull_ands_walker(FastList *out_list, List *andlist);
static List *pull_ors(List *orlist);
static void pull_ors_walker(FastList *out_list, List *orlist);
static Expr *find_nots(Expr *qual); static Expr *find_nots(Expr *qual);
static Expr *push_nots(Expr *qual); static Expr *push_nots(Expr *qual);
static Expr *find_ors(Expr *qual); static Expr *find_ors(Expr *qual);
...@@ -291,47 +295,19 @@ flatten_andors(Expr *qual) ...@@ -291,47 +295,19 @@ flatten_andors(Expr *qual)
if (and_clause((Node *) qual)) if (and_clause((Node *) qual))
{ {
List *out_list = NIL; FastList out_list;
List *arg;
foreach(arg, ((BoolExpr *) qual)->args) FastListInit(&out_list);
{ flatten_andors_and_walker(&out_list, ((BoolExpr *) qual)->args);
Expr *subexpr = flatten_andors((Expr *) lfirst(arg)); return make_andclause(FastListValue(&out_list));
/*
* Note: we can destructively nconc the subexpression's
* arglist because we know the recursive invocation of
* flatten_andors will have built a new arglist not shared
* with any other expr. Otherwise we'd need a listCopy here.
*/
if (and_clause((Node *) subexpr))
out_list = nconc(out_list, ((BoolExpr *) subexpr)->args);
else
out_list = lappend(out_list, subexpr);
}
return make_andclause(out_list);
} }
else if (or_clause((Node *) qual)) else if (or_clause((Node *) qual))
{ {
List *out_list = NIL; FastList out_list;
List *arg;
foreach(arg, ((BoolExpr *) qual)->args) FastListInit(&out_list);
{ flatten_andors_or_walker(&out_list, ((BoolExpr *) qual)->args);
Expr *subexpr = flatten_andors((Expr *) lfirst(arg)); return make_orclause(FastListValue(&out_list));
/*
* Note: we can destructively nconc the subexpression's
* arglist because we know the recursive invocation of
* flatten_andors will have built a new arglist not shared
* with any other expr. Otherwise we'd need a listCopy here.
*/
if (or_clause((Node *) subexpr))
out_list = nconc(out_list, ((BoolExpr *) subexpr)->args);
else
out_list = lappend(out_list, subexpr);
}
return make_orclause(out_list);
} }
else if (not_clause((Node *) qual)) else if (not_clause((Node *) qual))
return make_notclause(flatten_andors(get_notclausearg(qual))); return make_notclause(flatten_andors(get_notclausearg(qual)));
...@@ -351,69 +327,102 @@ flatten_andors(Expr *qual) ...@@ -351,69 +327,102 @@ flatten_andors(Expr *qual)
return qual; return qual;
} }
/* static void
* pull_ors flatten_andors_and_walker(FastList *out_list, List *andlist)
* Pull the arguments of an 'or' clause nested within another 'or' {
* clause up into the argument list of the parent. List *arg;
*
* Input is the arglist of an OR clause. foreach(arg, andlist)
* Returns the rebuilt arglist (note original list structure is not touched). {
*/ Expr *subexpr = (Expr *) lfirst(arg);
static List *
pull_ors(List *orlist) if (and_clause((Node *) subexpr))
flatten_andors_and_walker(out_list, ((BoolExpr *) subexpr)->args);
else
FastAppend(out_list, flatten_andors(subexpr));
}
}
static void
flatten_andors_or_walker(FastList *out_list, List *orlist)
{ {
List *out_list = NIL;
List *arg; List *arg;
foreach(arg, orlist) foreach(arg, orlist)
{ {
Expr *subexpr = (Expr *) lfirst(arg); Expr *subexpr = (Expr *) lfirst(arg);
/*
* Note: we can destructively nconc the subexpression's arglist
* because we know the recursive invocation of pull_ors will have
* built a new arglist not shared with any other expr. Otherwise
* we'd need a listCopy here.
*/
if (or_clause((Node *) subexpr)) if (or_clause((Node *) subexpr))
out_list = nconc(out_list, flatten_andors_or_walker(out_list, ((BoolExpr *) subexpr)->args);
pull_ors(((BoolExpr *) subexpr)->args));
else else
out_list = lappend(out_list, subexpr); FastAppend(out_list, flatten_andors(subexpr));
} }
return out_list;
} }
/* /*
* pull_ands * pull_ands
* Pull the arguments of an 'and' clause nested within another 'and' * Recursively flatten nested AND clauses into a single and-clause list.
* clause up into the argument list of the parent.
* *
* Returns the modified list. * Input is the arglist of an AND clause.
* Returns the rebuilt arglist (note original list structure is not touched).
*/ */
static List * static List *
pull_ands(List *andlist) pull_ands(List *andlist)
{ {
List *out_list = NIL; FastList out_list;
FastListInit(&out_list);
pull_ands_walker(&out_list, andlist);
return FastListValue(&out_list);
}
static void
pull_ands_walker(FastList *out_list, List *andlist)
{
List *arg; List *arg;
foreach(arg, andlist) foreach(arg, andlist)
{ {
Expr *subexpr = (Expr *) lfirst(arg); Expr *subexpr = (Expr *) lfirst(arg);
/*
* Note: we can destructively nconc the subexpression's arglist
* because we know the recursive invocation of pull_ands will have
* built a new arglist not shared with any other expr. Otherwise
* we'd need a listCopy here.
*/
if (and_clause((Node *) subexpr)) if (and_clause((Node *) subexpr))
out_list = nconc(out_list, pull_ands_walker(out_list, ((BoolExpr *) subexpr)->args);
pull_ands(((BoolExpr *) subexpr)->args)); else
FastAppend(out_list, subexpr);
}
}
/*
* pull_ors
* Recursively flatten nested OR clauses into a single or-clause list.
*
* Input is the arglist of an OR clause.
* Returns the rebuilt arglist (note original list structure is not touched).
*/
static List *
pull_ors(List *orlist)
{
FastList out_list;
FastListInit(&out_list);
pull_ors_walker(&out_list, orlist);
return FastListValue(&out_list);
}
static void
pull_ors_walker(FastList *out_list, List *orlist)
{
List *arg;
foreach(arg, orlist)
{
Expr *subexpr = (Expr *) lfirst(arg);
if (or_clause((Node *) subexpr))
pull_ors_walker(out_list, ((BoolExpr *) subexpr)->args);
else else
out_list = lappend(out_list, subexpr); FastAppend(out_list, subexpr);
} }
return out_list;
} }
/* /*
...@@ -447,21 +456,23 @@ find_nots(Expr *qual) ...@@ -447,21 +456,23 @@ find_nots(Expr *qual)
#endif #endif
if (and_clause((Node *) qual)) if (and_clause((Node *) qual))
{ {
List *t_list = NIL; FastList t_list;
List *temp; List *temp;
FastListInit(&t_list);
foreach(temp, ((BoolExpr *) qual)->args) foreach(temp, ((BoolExpr *) qual)->args)
t_list = lappend(t_list, find_nots(lfirst(temp))); FastAppend(&t_list, find_nots(lfirst(temp)));
return make_andclause(pull_ands(t_list)); return make_andclause(pull_ands(FastListValue(&t_list)));
} }
else if (or_clause((Node *) qual)) else if (or_clause((Node *) qual))
{ {
List *t_list = NIL; FastList t_list;
List *temp; List *temp;
FastListInit(&t_list);
foreach(temp, ((BoolExpr *) qual)->args) foreach(temp, ((BoolExpr *) qual)->args)
t_list = lappend(t_list, find_nots(lfirst(temp))); FastAppend(&t_list, find_nots(lfirst(temp)));
return make_orclause(pull_ors(t_list)); return make_orclause(pull_ors(FastListValue(&t_list)));
} }
else if (not_clause((Node *) qual)) else if (not_clause((Node *) qual))
return push_nots(get_notclausearg(qual)); return push_nots(get_notclausearg(qual));
...@@ -511,21 +522,23 @@ push_nots(Expr *qual) ...@@ -511,21 +522,23 @@ push_nots(Expr *qual)
* i.e., swap AND for OR and negate all the subclauses. * i.e., swap AND for OR and negate all the subclauses.
*-------------------- *--------------------
*/ */
List *t_list = NIL; FastList t_list;
List *temp; List *temp;
FastListInit(&t_list);
foreach(temp, ((BoolExpr *) qual)->args) foreach(temp, ((BoolExpr *) qual)->args)
t_list = lappend(t_list, push_nots(lfirst(temp))); FastAppend(&t_list, push_nots(lfirst(temp)));
return make_orclause(pull_ors(t_list)); return make_orclause(pull_ors(FastListValue(&t_list)));
} }
else if (or_clause((Node *) qual)) else if (or_clause((Node *) qual))
{ {
List *t_list = NIL; FastList t_list;
List *temp; List *temp;
FastListInit(&t_list);
foreach(temp, ((BoolExpr *) qual)->args) foreach(temp, ((BoolExpr *) qual)->args)
t_list = lappend(t_list, push_nots(lfirst(temp))); FastAppend(&t_list, push_nots(lfirst(temp)));
return make_andclause(pull_ands(t_list)); return make_andclause(pull_ands(FastListValue(&t_list)));
} }
else if (not_clause((Node *) qual)) else if (not_clause((Node *) qual))
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.137 2003/05/28 16:03:56 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.138 2003/05/28 22:32:49 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -771,21 +771,24 @@ is_pseudo_constant_clause(Node *clause) ...@@ -771,21 +771,24 @@ is_pseudo_constant_clause(Node *clause)
List * List *
pull_constant_clauses(List *quals, List **constantQual) pull_constant_clauses(List *quals, List **constantQual)
{ {
List *constqual = NIL; FastList constqual,
List *restqual = NIL; restqual;
List *q; List *q;
FastListInit(&constqual);
FastListInit(&restqual);
foreach(q, quals) foreach(q, quals)
{ {
Node *qual = (Node *) lfirst(q); Node *qual = (Node *) lfirst(q);
if (is_pseudo_constant_clause(qual)) if (is_pseudo_constant_clause(qual))
constqual = lappend(constqual, qual); FastAppend(&constqual, qual);
else else
restqual = lappend(restqual, qual); FastAppend(&restqual, qual);
} }
*constantQual = constqual; *constantQual = FastListValue(&constqual);
return restqual; return FastListValue(&restqual);
} }
...@@ -1187,16 +1190,17 @@ eval_const_expressions_mutator(Node *node, List *active_fns) ...@@ -1187,16 +1190,17 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
* when no input is TRUE and at least one is NULL. * when no input is TRUE and at least one is NULL.
*---------- *----------
*/ */
List *newargs = NIL; FastList newargs;
List *arg; List *arg;
bool haveNull = false; bool haveNull = false;
bool forceTrue = false; bool forceTrue = false;
FastListInit(&newargs);
foreach(arg, args) foreach(arg, args)
{ {
if (!IsA(lfirst(arg), Const)) if (!IsA(lfirst(arg), Const))
{ {
newargs = lappend(newargs, lfirst(arg)); FastAppend(&newargs, lfirst(arg));
continue; continue;
} }
const_input = (Const *) lfirst(arg); const_input = (Const *) lfirst(arg);
...@@ -1217,15 +1221,15 @@ eval_const_expressions_mutator(Node *node, List *active_fns) ...@@ -1217,15 +1221,15 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
if (forceTrue) if (forceTrue)
return MAKEBOOLCONST(true, false); return MAKEBOOLCONST(true, false);
if (haveNull) if (haveNull)
newargs = lappend(newargs, MAKEBOOLCONST(false, true)); FastAppend(&newargs, MAKEBOOLCONST(false, true));
/* If all the inputs are FALSE, result is FALSE */ /* If all the inputs are FALSE, result is FALSE */
if (newargs == NIL) if (FastListValue(&newargs) == NIL)
return MAKEBOOLCONST(false, false); return MAKEBOOLCONST(false, false);
/* If only one nonconst-or-NULL input, it's the result */ /* If only one nonconst-or-NULL input, it's the result */
if (lnext(newargs) == NIL) if (lnext(FastListValue(&newargs)) == NIL)
return (Node *) lfirst(newargs); return (Node *) lfirst(FastListValue(&newargs));
/* Else we still need an OR node */ /* Else we still need an OR node */
return (Node *) make_orclause(newargs); return (Node *) make_orclause(FastListValue(&newargs));
} }
case AND_EXPR: case AND_EXPR:
{ {
...@@ -1239,16 +1243,17 @@ eval_const_expressions_mutator(Node *node, List *active_fns) ...@@ -1239,16 +1243,17 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
* when no input is FALSE and at least one is NULL. * when no input is FALSE and at least one is NULL.
*---------- *----------
*/ */
List *newargs = NIL; FastList newargs;
List *arg; List *arg;
bool haveNull = false; bool haveNull = false;
bool forceFalse = false; bool forceFalse = false;
FastListInit(&newargs);
foreach(arg, args) foreach(arg, args)
{ {
if (!IsA(lfirst(arg), Const)) if (!IsA(lfirst(arg), Const))
{ {
newargs = lappend(newargs, lfirst(arg)); FastAppend(&newargs, lfirst(arg));
continue; continue;
} }
const_input = (Const *) lfirst(arg); const_input = (Const *) lfirst(arg);
...@@ -1269,15 +1274,15 @@ eval_const_expressions_mutator(Node *node, List *active_fns) ...@@ -1269,15 +1274,15 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
if (forceFalse) if (forceFalse)
return MAKEBOOLCONST(false, false); return MAKEBOOLCONST(false, false);
if (haveNull) if (haveNull)
newargs = lappend(newargs, MAKEBOOLCONST(false, true)); FastAppend(&newargs, MAKEBOOLCONST(false, true));
/* If all the inputs are TRUE, result is TRUE */ /* If all the inputs are TRUE, result is TRUE */
if (newargs == NIL) if (FastListValue(&newargs) == NIL)
return MAKEBOOLCONST(true, false); return MAKEBOOLCONST(true, false);
/* If only one nonconst-or-NULL input, it's the result */ /* If only one nonconst-or-NULL input, it's the result */
if (lnext(newargs) == NIL) if (lnext(FastListValue(&newargs)) == NIL)
return (Node *) lfirst(newargs); return (Node *) lfirst(FastListValue(&newargs));
/* Else we still need an AND node */ /* Else we still need an AND node */
return (Node *) make_andclause(newargs); return (Node *) make_andclause(FastListValue(&newargs));
} }
case NOT_EXPR: case NOT_EXPR:
Assert(length(args) == 1); Assert(length(args) == 1);
...@@ -1370,11 +1375,12 @@ eval_const_expressions_mutator(Node *node, List *active_fns) ...@@ -1370,11 +1375,12 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
*/ */
CaseExpr *caseexpr = (CaseExpr *) node; CaseExpr *caseexpr = (CaseExpr *) node;
CaseExpr *newcase; CaseExpr *newcase;
List *newargs = NIL; FastList newargs;
Node *defresult; Node *defresult;
Const *const_input; Const *const_input;
List *arg; List *arg;
FastListInit(&newargs);
foreach(arg, caseexpr->args) foreach(arg, caseexpr->args)
{ {
/* Simplify this alternative's condition and result */ /* Simplify this alternative's condition and result */
...@@ -1387,7 +1393,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns) ...@@ -1387,7 +1393,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
if (casewhen->expr == NULL || if (casewhen->expr == NULL ||
!IsA(casewhen->expr, Const)) !IsA(casewhen->expr, Const))
{ {
newargs = lappend(newargs, casewhen); FastAppend(&newargs, casewhen);
continue; continue;
} }
const_input = (Const *) casewhen->expr; const_input = (Const *) casewhen->expr;
...@@ -1399,13 +1405,13 @@ eval_const_expressions_mutator(Node *node, List *active_fns) ...@@ -1399,13 +1405,13 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
* Found a TRUE condition. If it's the first (un-dropped) * Found a TRUE condition. If it's the first (un-dropped)
* alternative, the CASE reduces to just this alternative. * alternative, the CASE reduces to just this alternative.
*/ */
if (newargs == NIL) if (FastListValue(&newargs) == NIL)
return (Node *) casewhen->result; return (Node *) casewhen->result;
/* /*
* Otherwise, add it to the list, and drop all the rest. * Otherwise, add it to the list, and drop all the rest.
*/ */
newargs = lappend(newargs, casewhen); FastAppend(&newargs, casewhen);
break; break;
} }
...@@ -1417,13 +1423,13 @@ eval_const_expressions_mutator(Node *node, List *active_fns) ...@@ -1417,13 +1423,13 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
* If no non-FALSE alternatives, CASE reduces to the default * If no non-FALSE alternatives, CASE reduces to the default
* result * result
*/ */
if (newargs == NIL) if (FastListValue(&newargs) == NIL)
return defresult; return defresult;
/* Otherwise we need a new CASE node */ /* Otherwise we need a new CASE node */
newcase = makeNode(CaseExpr); newcase = makeNode(CaseExpr);
newcase->casetype = caseexpr->casetype; newcase->casetype = caseexpr->casetype;
newcase->arg = NULL; newcase->arg = NULL;
newcase->args = newargs; newcase->args = FastListValue(&newargs);
newcase->defresult = (Expr *) defresult; newcase->defresult = (Expr *) defresult;
return (Node *) newcase; return (Node *) newcase;
} }
...@@ -1432,9 +1438,10 @@ eval_const_expressions_mutator(Node *node, List *active_fns) ...@@ -1432,9 +1438,10 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
ArrayExpr *arrayexpr = (ArrayExpr *) node; ArrayExpr *arrayexpr = (ArrayExpr *) node;
ArrayExpr *newarray; ArrayExpr *newarray;
bool all_const = true; bool all_const = true;
List *newelems = NIL; FastList newelems;
List *element; List *element;
FastListInit(&newelems);
foreach(element, arrayexpr->elements) foreach(element, arrayexpr->elements)
{ {
Node *e; Node *e;
...@@ -1443,13 +1450,13 @@ eval_const_expressions_mutator(Node *node, List *active_fns) ...@@ -1443,13 +1450,13 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
active_fns); active_fns);
if (!IsA(e, Const)) if (!IsA(e, Const))
all_const = false; all_const = false;
newelems = lappend(newelems, e); FastAppend(&newelems, e);
} }
newarray = makeNode(ArrayExpr); newarray = makeNode(ArrayExpr);
newarray->array_typeid = arrayexpr->array_typeid; newarray->array_typeid = arrayexpr->array_typeid;
newarray->element_typeid = arrayexpr->element_typeid; newarray->element_typeid = arrayexpr->element_typeid;
newarray->elements = newelems; newarray->elements = FastListValue(&newelems);
newarray->ndims = arrayexpr->ndims; newarray->ndims = arrayexpr->ndims;
if (all_const) if (all_const)
...@@ -1462,9 +1469,10 @@ eval_const_expressions_mutator(Node *node, List *active_fns) ...@@ -1462,9 +1469,10 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
{ {
CoalesceExpr *coalesceexpr = (CoalesceExpr *) node; CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
CoalesceExpr *newcoalesce; CoalesceExpr *newcoalesce;
List *newargs = NIL; FastList newargs;
List *arg; List *arg;
FastListInit(&newargs);
foreach(arg, coalesceexpr->args) foreach(arg, coalesceexpr->args)
{ {
Node *e; Node *e;
...@@ -1480,15 +1488,15 @@ eval_const_expressions_mutator(Node *node, List *active_fns) ...@@ -1480,15 +1488,15 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
{ {
if (((Const *) e)->constisnull) if (((Const *) e)->constisnull)
continue; /* drop null constant */ continue; /* drop null constant */
if (newargs == NIL) if (FastListValue(&newargs) == NIL)
return e; /* first expr */ return e; /* first expr */
} }
newargs = lappend(newargs, e); FastAppend(&newargs, e);
} }
newcoalesce = makeNode(CoalesceExpr); newcoalesce = makeNode(CoalesceExpr);
newcoalesce->coalescetype = coalesceexpr->coalescetype; newcoalesce->coalescetype = coalesceexpr->coalescetype;
newcoalesce->args = newargs; newcoalesce->args = FastListValue(&newargs);
return (Node *) newcoalesce; return (Node *) newcoalesce;
} }
if (IsA(node, FieldSelect)) if (IsA(node, FieldSelect))
...@@ -2647,16 +2655,16 @@ expression_tree_mutator(Node *node, ...@@ -2647,16 +2655,16 @@ expression_tree_mutator(Node *node,
* NOTE: this would fail badly on a list with integer * NOTE: this would fail badly on a list with integer
* elements! * elements!
*/ */
List *resultlist = NIL; FastList resultlist;
List *temp; List *temp;
FastListInit(&resultlist);
foreach(temp, (List *) node) foreach(temp, (List *) node)
{ {
resultlist = lappend(resultlist, FastAppend(&resultlist,
mutator((Node *) lfirst(temp), mutator((Node *) lfirst(temp), context));
context));
} }
return (Node *) resultlist; return (Node *) FastListValue(&resultlist);
} }
break; break;
case T_FromExpr: case T_FromExpr:
...@@ -2739,7 +2747,7 @@ query_tree_mutator(Query *query, ...@@ -2739,7 +2747,7 @@ query_tree_mutator(Query *query,
void *context, void *context,
int flags) int flags)
{ {
List *newrt = NIL; FastList newrt;
List *rt; List *rt;
Assert(query != NULL && IsA(query, Query)); Assert(query != NULL && IsA(query, Query));
...@@ -2757,6 +2765,7 @@ query_tree_mutator(Query *query, ...@@ -2757,6 +2765,7 @@ query_tree_mutator(Query *query,
MUTATE(query->setOperations, query->setOperations, Node *); MUTATE(query->setOperations, query->setOperations, Node *);
MUTATE(query->havingQual, query->havingQual, Node *); MUTATE(query->havingQual, query->havingQual, Node *);
MUTATE(query->in_info_list, query->in_info_list, List *); MUTATE(query->in_info_list, query->in_info_list, List *);
FastListInit(&newrt);
foreach(rt, query->rtable) foreach(rt, query->rtable)
{ {
RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
...@@ -2791,9 +2800,9 @@ query_tree_mutator(Query *query, ...@@ -2791,9 +2800,9 @@ query_tree_mutator(Query *query,
rte = newrte; rte = newrte;
break; break;
} }
newrt = lappend(newrt, rte); FastAppend(&newrt, rte);
} }
query->rtable = newrt; query->rtable = FastListValue(&newrt);
return query; return query;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.49 2003/02/08 20:20:55 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.50 2003/05/28 22:32:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -37,7 +37,7 @@ typedef struct ...@@ -37,7 +37,7 @@ typedef struct
typedef struct typedef struct
{ {
List *varlist; FastList varlist;
bool includeUpperVars; bool includeUpperVars;
} pull_var_clause_context; } pull_var_clause_context;
...@@ -344,11 +344,11 @@ pull_var_clause(Node *node, bool includeUpperVars) ...@@ -344,11 +344,11 @@ pull_var_clause(Node *node, bool includeUpperVars)
{ {
pull_var_clause_context context; pull_var_clause_context context;
context.varlist = NIL; FastListInit(&context.varlist);
context.includeUpperVars = includeUpperVars; context.includeUpperVars = includeUpperVars;
pull_var_clause_walker(node, &context); pull_var_clause_walker(node, &context);
return context.varlist; return FastListValue(&context.varlist);
} }
static bool static bool
...@@ -359,7 +359,7 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context) ...@@ -359,7 +359,7 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context)
if (IsA(node, Var)) if (IsA(node, Var))
{ {
if (((Var *) node)->varlevelsup == 0 || context->includeUpperVars) if (((Var *) node)->varlevelsup == 0 || context->includeUpperVars)
context->varlist = lappend(context->varlist, node); FastAppend(&context->varlist, node);
return false; return false;
} }
return expression_tree_walker(node, pull_var_clause_walker, return expression_tree_walker(node, pull_var_clause_walker,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_list.h,v 1.35 2003/02/09 06:56:28 tgl Exp $ * $Id: pg_list.h,v 1.36 2003/05/28 22:32:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -128,6 +128,21 @@ typedef struct List ...@@ -128,6 +128,21 @@ typedef struct List
#define makeListo1(x1) lconso(x1, NIL) #define makeListo1(x1) lconso(x1, NIL)
#define makeListo2(x1,x2) lconso(x1, makeListo1(x2)) #define makeListo2(x1,x2) lconso(x1, makeListo1(x2))
/*
* FastList is an optimization for building large lists. The conventional
* way to build a list is repeated lappend() operations, but that is O(N^2)
* in the number of list items, which gets tedious for large lists.
*/
typedef struct FastList
{
List *head;
List *tail;
} FastList;
#define FastListInit(fl) ( (fl)->head = (fl)->tail = NIL )
#define FastListValue(fl) ( (fl)->head )
/* /*
* function prototypes in nodes/list.c * function prototypes in nodes/list.c
*/ */
...@@ -143,6 +158,11 @@ extern List *lappend(List *list, void *datum); ...@@ -143,6 +158,11 @@ extern List *lappend(List *list, void *datum);
extern List *lappendi(List *list, int datum); extern List *lappendi(List *list, int datum);
extern List *lappendo(List *list, Oid datum); extern List *lappendo(List *list, Oid datum);
extern List *nconc(List *list1, List *list2); extern List *nconc(List *list1, List *list2);
extern void FastAppend(FastList *fl, void *datum);
extern void FastAppendi(FastList *fl, int datum);
extern void FastAppendo(FastList *fl, Oid datum);
extern void FastConc(FastList *fl, List *cells);
extern void FastConcFast(FastList *fl, FastList *fl2);
extern void *nth(int n, List *l); extern void *nth(int n, List *l);
extern int length(List *list); extern int length(List *list);
extern void *llast(List *list); extern void *llast(List *list);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment