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.
This commit is contained in:
parent
0f3c68aa43
commit
8a6ac83dab
@ -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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
* 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)
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
* 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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 *
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
/* 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,
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
|
|
||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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,
|
|||||||
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,
|
|||||||
|
|
||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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 @@
|
|||||||
#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)
|
|||||||
|
|
||||||
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,10 +327,74 @@ flatten_andors(Expr *qual)
|
|||||||
return 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_ors
|
||||||
* Pull the arguments of an 'or' clause nested within another 'or'
|
* Recursively flatten nested OR clauses into a single or-clause list.
|
||||||
* clause up into the argument list of the parent.
|
|
||||||
*
|
*
|
||||||
* Input is the arglist of an OR clause.
|
* Input is the arglist of an OR clause.
|
||||||
* Returns the rebuilt arglist (note original list structure is not touched).
|
* Returns the rebuilt arglist (note original list structure is not touched).
|
||||||
@ -362,58 +402,27 @@ flatten_andors(Expr *qual)
|
|||||||
static List *
|
static List *
|
||||||
pull_ors(List *orlist)
|
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;
|
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,
|
pull_ors_walker(out_list, ((BoolExpr *) subexpr)->args);
|
||||||
pull_ors(((BoolExpr *) subexpr)->args));
|
|
||||||
else
|
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
|
#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)
|
|||||||
* 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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
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)
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
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)
|
|||||||
* 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)
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
* 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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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
|
|||||||
|
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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 @@
|
|||||||
* 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
|
|||||||
#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);
|
|||||||
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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user