diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index a2d0a8346f1..8dac4b2e440 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * 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) { CaseExpr *caseexpr = (CaseExpr *) node; CaseExprState *cstate = makeNode(CaseExprState); - List *outlist = NIL; + FastList outlist; List *inlist; + FastListInit(&outlist); foreach(inlist, caseexpr->args) { CaseWhen *when = (CaseWhen *) lfirst(inlist); @@ -2332,9 +2333,9 @@ ExecInitExpr(Expr *node, PlanState *parent) wstate->xprstate.expr = (Expr *) when; wstate->expr = ExecInitExpr(when->expr, 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 */ Assert(caseexpr->arg == NULL); cstate->defresult = ExecInitExpr(caseexpr->defresult, parent); @@ -2345,18 +2346,19 @@ ExecInitExpr(Expr *node, PlanState *parent) { ArrayExpr *arrayexpr = (ArrayExpr *) node; ArrayExprState *astate = makeNode(ArrayExprState); - List *outlist = NIL; + FastList outlist; List *inlist; + FastListInit(&outlist); foreach(inlist, arrayexpr->elements) { Expr *e = (Expr *) lfirst(inlist); ExprState *estate; 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 */ get_typlenbyvalalign(arrayexpr->element_typeid, &astate->elemlength, @@ -2369,18 +2371,19 @@ ExecInitExpr(Expr *node, PlanState *parent) { CoalesceExpr *coalesceexpr = (CoalesceExpr *) node; CoalesceExprState *cstate = makeNode(CoalesceExprState); - List *outlist = NIL; + FastList outlist; List *inlist; + FastListInit(&outlist); foreach(inlist, coalesceexpr->args) { Expr *e = (Expr *) lfirst(inlist); ExprState *estate; estate = ExecInitExpr(e, parent); - outlist = lappend(outlist, estate); + FastAppend(&outlist, estate); } - cstate->args = outlist; + cstate->args = FastListValue(&outlist); state = (ExprState *) cstate; } break; @@ -2434,17 +2437,18 @@ ExecInitExpr(Expr *node, PlanState *parent) break; case T_List: { - List *outlist = NIL; + FastList outlist; List *inlist; + FastListInit(&outlist); foreach(inlist, (List *) node) { - outlist = lappend(outlist, - ExecInitExpr((Expr *) lfirst(inlist), - parent)); + FastAppend(&outlist, + ExecInitExpr((Expr *) lfirst(inlist), + parent)); } /* Don't fall through to the "common" code below */ - return (ExprState *) outlist; + return (ExprState *) FastListValue(&outlist); } default: elog(ERROR, "ExecInitExpr: unknown expression type %d", diff --git a/src/backend/nodes/list.c b/src/backend/nodes/list.c index 0a379a753b1..207acea9472 100644 --- a/src/backend/nodes/list.c +++ b/src/backend/nodes/list.c @@ -9,7 +9,7 @@ * * * 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 * XXX a few of the following functions are duplicated to handle @@ -141,9 +141,9 @@ lconso(Oid datum, List *list) * MORE EXPENSIVE THAN lcons */ 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) 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 * diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 9319f8c1474..ace494ba20b 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -9,7 +9,7 @@ * * * 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, IndexOptInfo *index, Expr *orsubclause) { - List *quals = NIL; + FastList quals; int indexcol = 0; Oid *classes = index->classlist; + FastListInit(&quals); /* * Extract relevant indexclauses in indexkey order. This is * essentially just like group_clauses_by_indexkey() except that the @@ -430,9 +431,10 @@ extract_or_indexqual_conditions(RelOptInfo *rel, do { Oid curClass = classes[0]; - List *clausegroup = NIL; + FastList clausegroup; List *item; + FastListInit(&clausegroup); if (and_clause((Node *) orsubclause)) { foreach(item, ((BoolExpr *) orsubclause)->args) @@ -442,21 +444,23 @@ extract_or_indexqual_conditions(RelOptInfo *rel, if (match_clause_to_indexcol(rel, index, indexcol, curClass, subsubclause)) - clausegroup = nconc(clausegroup, - expand_indexqual_condition(subsubclause, - curClass)); + FastConc(&clausegroup, + expand_indexqual_condition(subsubclause, + curClass)); } } else if (match_clause_to_indexcol(rel, index, indexcol, curClass, 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 * itself, try looking in the rel's top-level restriction list. */ - if (clausegroup == NIL) + if (FastListValue(&clausegroup) == NIL) { foreach(item, rel->baserestrictinfo) { @@ -465,9 +469,9 @@ extract_or_indexqual_conditions(RelOptInfo *rel, if (match_clause_to_indexcol(rel, index, indexcol, curClass, rinfo->clause)) - clausegroup = nconc(clausegroup, - expand_indexqual_condition(rinfo->clause, - curClass)); + FastConc(&clausegroup, + expand_indexqual_condition(rinfo->clause, + curClass)); } } @@ -475,20 +479,20 @@ extract_or_indexqual_conditions(RelOptInfo *rel, * If still no clauses match this key, we're done; we don't want * to look at keys to its right. */ - if (clausegroup == NIL) + if (FastListValue(&clausegroup) == NIL) break; - quals = nconc(quals, clausegroup); + FastConcFast(&quals, &clausegroup); indexcol++; classes++; } while (!DoneMatchingIndexKeys(classes)); - if (quals == NIL) + if (FastListValue(&quals) == NIL) elog(ERROR, "extract_or_indexqual_conditions: no matching clause"); - return quals; + return FastListValue(&quals); } @@ -520,7 +524,7 @@ extract_or_indexqual_conditions(RelOptInfo *rel, static List * group_clauses_by_indexkey(RelOptInfo *rel, IndexOptInfo *index) { - List *clausegroup_list = NIL; + FastList clausegroup_list; List *restrictinfo_list = rel->baserestrictinfo; int indexcol = 0; Oid *classes = index->classlist; @@ -528,12 +532,14 @@ group_clauses_by_indexkey(RelOptInfo *rel, IndexOptInfo *index) if (restrictinfo_list == NIL) return NIL; + FastListInit(&clausegroup_list); do { Oid curClass = classes[0]; - List *clausegroup = NIL; + FastList clausegroup; List *i; + FastListInit(&clausegroup); foreach(i, restrictinfo_list) { RestrictInfo *rinfo = (RestrictInfo *) lfirst(i); @@ -543,24 +549,24 @@ group_clauses_by_indexkey(RelOptInfo *rel, IndexOptInfo *index) indexcol, curClass, rinfo->clause)) - clausegroup = lappend(clausegroup, rinfo); + FastAppend(&clausegroup, rinfo); } /* * If no clauses match this key, we're done; we don't want to look * at keys to its right. */ - if (clausegroup == NIL) + if (FastListValue(&clausegroup) == NIL) break; - clausegroup_list = lappend(clausegroup_list, clausegroup); + FastAppend(&clausegroup_list, FastListValue(&clausegroup)); indexcol++; classes++; } while (!DoneMatchingIndexKeys(classes)); - return clausegroup_list; + return FastListValue(&clausegroup_list); } /* @@ -580,17 +586,20 @@ static List * group_clauses_by_indexkey_for_join(RelOptInfo *rel, IndexOptInfo *index, Relids outer_relids, bool isouterjoin) { - List *clausegroup_list = NIL; + FastList clausegroup_list; bool jfound = false; int indexcol = 0; Oid *classes = index->classlist; + FastListInit(&clausegroup_list); do { Oid curClass = classes[0]; - List *clausegroup = NIL; + FastList clausegroup; List *i; + FastListInit(&clausegroup); + /* Look for joinclauses that are usable with given outer_relids */ foreach(i, rel->joininfo) { @@ -614,7 +623,7 @@ group_clauses_by_indexkey_for_join(RelOptInfo *rel, IndexOptInfo *index, curClass, rinfo->clause)) { - clausegroup = lappend(clausegroup, rinfo); + FastAppend(&clausegroup, rinfo); jfound = true; } } @@ -634,17 +643,17 @@ group_clauses_by_indexkey_for_join(RelOptInfo *rel, IndexOptInfo *index, indexcol, curClass, rinfo->clause)) - clausegroup = lappend(clausegroup, rinfo); + FastAppend(&clausegroup, rinfo); } /* * If no clauses match this key, we're done; we don't want to look * at keys to its right. */ - if (clausegroup == NIL) + if (FastListValue(&clausegroup) == NIL) break; - clausegroup_list = lappend(clausegroup_list, clausegroup); + FastAppend(&clausegroup_list, FastListValue(&clausegroup)); indexcol++; classes++; @@ -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 (!jfound) - { - freeList(clausegroup_list); return NIL; - } - return clausegroup_list; + return FastListValue(&clausegroup_list); } @@ -1870,12 +1876,13 @@ match_special_index_operator(Expr *clause, Oid opclass, List * expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups) { - List *resultquals = NIL; + FastList resultquals; Oid *classes = index->classlist; if (clausegroups == NIL) return NIL; + FastListInit(&resultquals); do { Oid curClass = classes[0]; @@ -1885,9 +1892,9 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups) { RestrictInfo *rinfo = (RestrictInfo *) lfirst(i); - resultquals = nconc(resultquals, - expand_indexqual_condition(rinfo->clause, - curClass)); + FastConc(&resultquals, + expand_indexqual_condition(rinfo->clause, + curClass)); } clausegroups = lnext(clausegroups); @@ -1898,7 +1905,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups) Assert(clausegroups == NIL); /* else more groups than indexkeys... */ - return resultquals; + return FastListValue(&resultquals); } /* diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c index 101866867b9..10eb050f3a3 100644 --- a/src/backend/optimizer/path/orindxpath.c +++ b/src/backend/optimizer/path/orindxpath.c @@ -8,7 +8,7 @@ * * * 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, List *indices, IndexPath *pathnode) { + FastList infos; + FastList quals; List *slist; - pathnode->indexinfo = NIL; - pathnode->indexqual = NIL; + FastListInit(&infos); + FastListInit(&quals); pathnode->path.startup_cost = 0; pathnode->path.total_cost = 0; @@ -170,14 +172,17 @@ best_or_subclause_indices(Query *root, Assert(best_indexinfo != NULL); - pathnode->indexinfo = lappend(pathnode->indexinfo, best_indexinfo); - pathnode->indexqual = lappend(pathnode->indexqual, best_indexqual); + FastAppend(&infos, best_indexinfo); + FastAppend(&quals, best_indexqual); if (slist == subclauses) /* first scan? */ pathnode->path.startup_cost = best_startup_cost; pathnode->path.total_cost += best_total_cost; indices = lnext(indices); } + + pathnode->indexinfo = FastListValue(&infos); + pathnode->indexqual = FastListValue(&quals); } /* diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c index 4016ba476de..24ea1316e11 100644 --- a/src/backend/optimizer/prep/prepqual.c +++ b/src/backend/optimizer/prep/prepqual.c @@ -8,7 +8,7 @@ * * * 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 @@ #include "utils/lsyscache.h" 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 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 *push_nots(Expr *qual); static Expr *find_ors(Expr *qual); @@ -291,47 +295,19 @@ flatten_andors(Expr *qual) if (and_clause((Node *) qual)) { - List *out_list = NIL; - List *arg; + FastList out_list; - foreach(arg, ((BoolExpr *) qual)->args) - { - Expr *subexpr = flatten_andors((Expr *) lfirst(arg)); - - /* - * 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); + FastListInit(&out_list); + flatten_andors_and_walker(&out_list, ((BoolExpr *) qual)->args); + return make_andclause(FastListValue(&out_list)); } else if (or_clause((Node *) qual)) { - List *out_list = NIL; - List *arg; + FastList out_list; - foreach(arg, ((BoolExpr *) qual)->args) - { - Expr *subexpr = flatten_andors((Expr *) lfirst(arg)); - - /* - * 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); + FastListInit(&out_list); + flatten_andors_or_walker(&out_list, ((BoolExpr *) qual)->args); + return make_orclause(FastListValue(&out_list)); } else if (not_clause((Node *) qual)) return make_notclause(flatten_andors(get_notclausearg(qual))); @@ -351,10 +327,74 @@ flatten_andors(Expr *qual) return qual; } +static void +flatten_andors_and_walker(FastList *out_list, List *andlist) +{ + List *arg; + + foreach(arg, andlist) + { + Expr *subexpr = (Expr *) lfirst(arg); + + 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 *arg; + + foreach(arg, orlist) + { + Expr *subexpr = (Expr *) lfirst(arg); + + if (or_clause((Node *) subexpr)) + flatten_andors_or_walker(out_list, ((BoolExpr *) subexpr)->args); + else + FastAppend(out_list, flatten_andors(subexpr)); + } +} + +/* + * pull_ands + * Recursively flatten nested AND clauses into a single and-clause list. + * + * Input is the arglist of an AND clause. + * Returns the rebuilt arglist (note original list structure is not touched). + */ +static List * +pull_ands(List *andlist) +{ + 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; + + foreach(arg, andlist) + { + Expr *subexpr = (Expr *) lfirst(arg); + + if (and_clause((Node *) subexpr)) + pull_ands_walker(out_list, ((BoolExpr *) subexpr)->args); + else + FastAppend(out_list, subexpr); + } +} + /* * pull_ors - * Pull the arguments of an 'or' clause nested within another 'or' - * clause up into the argument list of the parent. + * 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). @@ -362,58 +402,27 @@ flatten_andors(Expr *qual) static List * pull_ors(List *orlist) { - List *out_list = NIL; + 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); - /* - * 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)) - out_list = nconc(out_list, - pull_ors(((BoolExpr *) subexpr)->args)); + pull_ors_walker(out_list, ((BoolExpr *) subexpr)->args); else - out_list = lappend(out_list, subexpr); + FastAppend(out_list, subexpr); } - return out_list; -} - -/* - * pull_ands - * Pull the arguments of an 'and' clause nested within another 'and' - * clause up into the argument list of the parent. - * - * Returns the modified list. - */ -static List * -pull_ands(List *andlist) -{ - List *out_list = NIL; - List *arg; - - foreach(arg, andlist) - { - 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)) - out_list = nconc(out_list, - pull_ands(((BoolExpr *) subexpr)->args)); - else - out_list = lappend(out_list, subexpr); - } - return out_list; } /* @@ -447,21 +456,23 @@ find_nots(Expr *qual) #endif if (and_clause((Node *) qual)) { - List *t_list = NIL; + FastList t_list; List *temp; + FastListInit(&t_list); foreach(temp, ((BoolExpr *) qual)->args) - t_list = lappend(t_list, find_nots(lfirst(temp))); - return make_andclause(pull_ands(t_list)); + FastAppend(&t_list, find_nots(lfirst(temp))); + return make_andclause(pull_ands(FastListValue(&t_list))); } else if (or_clause((Node *) qual)) { - List *t_list = NIL; + FastList t_list; List *temp; + FastListInit(&t_list); foreach(temp, ((BoolExpr *) qual)->args) - t_list = lappend(t_list, find_nots(lfirst(temp))); - return make_orclause(pull_ors(t_list)); + FastAppend(&t_list, find_nots(lfirst(temp))); + return make_orclause(pull_ors(FastListValue(&t_list))); } else if (not_clause((Node *) qual)) return push_nots(get_notclausearg(qual)); @@ -511,21 +522,23 @@ push_nots(Expr *qual) * i.e., swap AND for OR and negate all the subclauses. *-------------------- */ - List *t_list = NIL; + FastList t_list; List *temp; + FastListInit(&t_list); foreach(temp, ((BoolExpr *) qual)->args) - t_list = lappend(t_list, push_nots(lfirst(temp))); - return make_orclause(pull_ors(t_list)); + FastAppend(&t_list, push_nots(lfirst(temp))); + return make_orclause(pull_ors(FastListValue(&t_list))); } else if (or_clause((Node *) qual)) { - List *t_list = NIL; + FastList t_list; List *temp; + FastListInit(&t_list); foreach(temp, ((BoolExpr *) qual)->args) - t_list = lappend(t_list, push_nots(lfirst(temp))); - return make_andclause(pull_ands(t_list)); + FastAppend(&t_list, push_nots(lfirst(temp))); + return make_andclause(pull_ands(FastListValue(&t_list))); } else if (not_clause((Node *) qual)) { diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 4d51e7ffbc0..0c2e652c795 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * 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 * AUTHOR DATE MAJOR EVENT @@ -771,21 +771,24 @@ is_pseudo_constant_clause(Node *clause) List * pull_constant_clauses(List *quals, List **constantQual) { - List *constqual = NIL; - List *restqual = NIL; + FastList constqual, + restqual; List *q; + FastListInit(&constqual); + FastListInit(&restqual); + foreach(q, quals) { Node *qual = (Node *) lfirst(q); if (is_pseudo_constant_clause(qual)) - constqual = lappend(constqual, qual); + FastAppend(&constqual, qual); else - restqual = lappend(restqual, qual); + FastAppend(&restqual, qual); } - *constantQual = constqual; - return restqual; + *constantQual = FastListValue(&constqual); + return FastListValue(&restqual); } @@ -1187,16 +1190,17 @@ eval_const_expressions_mutator(Node *node, List *active_fns) * when no input is TRUE and at least one is NULL. *---------- */ - List *newargs = NIL; + FastList newargs; List *arg; bool haveNull = false; bool forceTrue = false; + FastListInit(&newargs); foreach(arg, args) { if (!IsA(lfirst(arg), Const)) { - newargs = lappend(newargs, lfirst(arg)); + FastAppend(&newargs, lfirst(arg)); continue; } const_input = (Const *) lfirst(arg); @@ -1217,15 +1221,15 @@ eval_const_expressions_mutator(Node *node, List *active_fns) if (forceTrue) return MAKEBOOLCONST(true, false); if (haveNull) - newargs = lappend(newargs, MAKEBOOLCONST(false, true)); + FastAppend(&newargs, MAKEBOOLCONST(false, true)); /* If all the inputs are FALSE, result is FALSE */ - if (newargs == NIL) + if (FastListValue(&newargs) == NIL) return MAKEBOOLCONST(false, false); /* If only one nonconst-or-NULL input, it's the result */ - if (lnext(newargs) == NIL) - return (Node *) lfirst(newargs); + if (lnext(FastListValue(&newargs)) == NIL) + return (Node *) lfirst(FastListValue(&newargs)); /* Else we still need an OR node */ - return (Node *) make_orclause(newargs); + return (Node *) make_orclause(FastListValue(&newargs)); } case AND_EXPR: { @@ -1239,16 +1243,17 @@ eval_const_expressions_mutator(Node *node, List *active_fns) * when no input is FALSE and at least one is NULL. *---------- */ - List *newargs = NIL; + FastList newargs; List *arg; bool haveNull = false; bool forceFalse = false; + FastListInit(&newargs); foreach(arg, args) { if (!IsA(lfirst(arg), Const)) { - newargs = lappend(newargs, lfirst(arg)); + FastAppend(&newargs, lfirst(arg)); continue; } const_input = (Const *) lfirst(arg); @@ -1269,15 +1274,15 @@ eval_const_expressions_mutator(Node *node, List *active_fns) if (forceFalse) return MAKEBOOLCONST(false, false); if (haveNull) - newargs = lappend(newargs, MAKEBOOLCONST(false, true)); + FastAppend(&newargs, MAKEBOOLCONST(false, true)); /* If all the inputs are TRUE, result is TRUE */ - if (newargs == NIL) + if (FastListValue(&newargs) == NIL) return MAKEBOOLCONST(true, false); /* If only one nonconst-or-NULL input, it's the result */ - if (lnext(newargs) == NIL) - return (Node *) lfirst(newargs); + if (lnext(FastListValue(&newargs)) == NIL) + return (Node *) lfirst(FastListValue(&newargs)); /* Else we still need an AND node */ - return (Node *) make_andclause(newargs); + return (Node *) make_andclause(FastListValue(&newargs)); } case NOT_EXPR: Assert(length(args) == 1); @@ -1370,11 +1375,12 @@ eval_const_expressions_mutator(Node *node, List *active_fns) */ CaseExpr *caseexpr = (CaseExpr *) node; CaseExpr *newcase; - List *newargs = NIL; + FastList newargs; Node *defresult; Const *const_input; List *arg; + FastListInit(&newargs); foreach(arg, caseexpr->args) { /* Simplify this alternative's condition and result */ @@ -1387,7 +1393,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns) if (casewhen->expr == NULL || !IsA(casewhen->expr, Const)) { - newargs = lappend(newargs, casewhen); + FastAppend(&newargs, casewhen); continue; } const_input = (Const *) casewhen->expr; @@ -1399,13 +1405,13 @@ eval_const_expressions_mutator(Node *node, List *active_fns) * Found a TRUE condition. If it's the first (un-dropped) * alternative, the CASE reduces to just this alternative. */ - if (newargs == NIL) + if (FastListValue(&newargs) == NIL) return (Node *) casewhen->result; /* * Otherwise, add it to the list, and drop all the rest. */ - newargs = lappend(newargs, casewhen); + FastAppend(&newargs, casewhen); break; } @@ -1417,13 +1423,13 @@ eval_const_expressions_mutator(Node *node, List *active_fns) * If no non-FALSE alternatives, CASE reduces to the default * result */ - if (newargs == NIL) + if (FastListValue(&newargs) == NIL) return defresult; /* Otherwise we need a new CASE node */ newcase = makeNode(CaseExpr); newcase->casetype = caseexpr->casetype; newcase->arg = NULL; - newcase->args = newargs; + newcase->args = FastListValue(&newargs); newcase->defresult = (Expr *) defresult; return (Node *) newcase; } @@ -1432,9 +1438,10 @@ eval_const_expressions_mutator(Node *node, List *active_fns) ArrayExpr *arrayexpr = (ArrayExpr *) node; ArrayExpr *newarray; bool all_const = true; - List *newelems = NIL; + FastList newelems; List *element; + FastListInit(&newelems); foreach(element, arrayexpr->elements) { Node *e; @@ -1443,13 +1450,13 @@ eval_const_expressions_mutator(Node *node, List *active_fns) active_fns); if (!IsA(e, Const)) all_const = false; - newelems = lappend(newelems, e); + FastAppend(&newelems, e); } newarray = makeNode(ArrayExpr); newarray->array_typeid = arrayexpr->array_typeid; newarray->element_typeid = arrayexpr->element_typeid; - newarray->elements = newelems; + newarray->elements = FastListValue(&newelems); newarray->ndims = arrayexpr->ndims; if (all_const) @@ -1462,9 +1469,10 @@ eval_const_expressions_mutator(Node *node, List *active_fns) { CoalesceExpr *coalesceexpr = (CoalesceExpr *) node; CoalesceExpr *newcoalesce; - List *newargs = NIL; + FastList newargs; List *arg; + FastListInit(&newargs); foreach(arg, coalesceexpr->args) { Node *e; @@ -1480,15 +1488,15 @@ eval_const_expressions_mutator(Node *node, List *active_fns) { if (((Const *) e)->constisnull) continue; /* drop null constant */ - if (newargs == NIL) + if (FastListValue(&newargs) == NIL) return e; /* first expr */ } - newargs = lappend(newargs, e); + FastAppend(&newargs, e); } newcoalesce = makeNode(CoalesceExpr); newcoalesce->coalescetype = coalesceexpr->coalescetype; - newcoalesce->args = newargs; + newcoalesce->args = FastListValue(&newargs); return (Node *) newcoalesce; } if (IsA(node, FieldSelect)) @@ -2647,16 +2655,16 @@ expression_tree_mutator(Node *node, * NOTE: this would fail badly on a list with integer * elements! */ - List *resultlist = NIL; + FastList resultlist; List *temp; + FastListInit(&resultlist); foreach(temp, (List *) node) { - resultlist = lappend(resultlist, - mutator((Node *) lfirst(temp), - context)); + FastAppend(&resultlist, + mutator((Node *) lfirst(temp), context)); } - return (Node *) resultlist; + return (Node *) FastListValue(&resultlist); } break; case T_FromExpr: @@ -2739,7 +2747,7 @@ query_tree_mutator(Query *query, void *context, int flags) { - List *newrt = NIL; + FastList newrt; List *rt; Assert(query != NULL && IsA(query, Query)); @@ -2757,6 +2765,7 @@ query_tree_mutator(Query *query, MUTATE(query->setOperations, query->setOperations, Node *); MUTATE(query->havingQual, query->havingQual, Node *); MUTATE(query->in_info_list, query->in_info_list, List *); + FastListInit(&newrt); foreach(rt, query->rtable) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); @@ -2791,9 +2800,9 @@ query_tree_mutator(Query *query, rte = newrte; break; } - newrt = lappend(newrt, rte); + FastAppend(&newrt, rte); } - query->rtable = newrt; + query->rtable = FastListValue(&newrt); return query; } diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index 929f5561dbc..a365b7b159e 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -8,7 +8,7 @@ * * * 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 typedef struct { - List *varlist; + FastList varlist; bool includeUpperVars; } pull_var_clause_context; @@ -344,11 +344,11 @@ pull_var_clause(Node *node, bool includeUpperVars) { pull_var_clause_context context; - context.varlist = NIL; + FastListInit(&context.varlist); context.includeUpperVars = includeUpperVars; pull_var_clause_walker(node, &context); - return context.varlist; + return FastListValue(&context.varlist); } static bool @@ -359,7 +359,7 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context) if (IsA(node, Var)) { if (((Var *) node)->varlevelsup == 0 || context->includeUpperVars) - context->varlist = lappend(context->varlist, node); + FastAppend(&context->varlist, node); return false; } return expression_tree_walker(node, pull_var_clause_walker, diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h index b48fc02e855..bc42917a355 100644 --- a/src/include/nodes/pg_list.h +++ b/src/include/nodes/pg_list.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * 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 #define makeListo1(x1) lconso(x1, NIL) #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 */ @@ -143,6 +158,11 @@ extern List *lappend(List *list, void *datum); extern List *lappendi(List *list, int datum); extern List *lappendo(List *list, Oid datum); 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 int length(List *list); extern void *llast(List *list);