1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-26 01:22:12 +03:00

New cost model for planning, incorporating a penalty for random page

accesses versus sequential accesses, a (very crude) estimate of the
effects of caching on random page accesses, and cost to evaluate WHERE-
clause expressions.  Export critical parameters for this model as SET
variables.  Also, create SET variables for the planner's enable flags
(enable_seqscan, enable_indexscan, etc) so that these can be controlled
more conveniently than via PGOPTIONS.

Planner now estimates both startup cost (cost before retrieving
first tuple) and total cost of each path, so it can optimize queries
with LIMIT on a reasonable basis by interpolating between these costs.
Same facility is a win for EXISTS(...) subqueries and some other cases.

Redesign pathkey representation to achieve a major speedup in planning
(I saw as much as 5X on a 10-way join); also minor changes in planner
to reduce memory consumption by recycling discarded Path nodes and
not constructing unnecessary lists.

Minor cleanups to display more-plausible costs in some cases in
EXPLAIN output.

Initdb forced by change in interface to index cost estimation
functions.
This commit is contained in:
Tom Lane
2000-02-15 20:49:31 +00:00
parent 553b5da6a1
commit b1577a7c78
50 changed files with 3200 additions and 1723 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.105 2000/02/15 03:37:08 thomas Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.106 2000/02/15 20:49:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -75,7 +75,8 @@ listCopy(List *list)
static void
CopyPlanFields(Plan *from, Plan *newnode)
{
newnode->cost = from->cost;
newnode->startup_cost = from->startup_cost;
newnode->total_cost = from->total_cost;
newnode->plan_rows = from->plan_rows;
newnode->plan_width = from->plan_width;
/* state is NOT copied */
@ -981,8 +982,9 @@ _copyRelOptInfo(RelOptInfo *from)
Node_Copy(from, newnode, targetlist);
Node_Copy(from, newnode, pathlist);
/* XXX cheapestpath should point to a member of pathlist? */
Node_Copy(from, newnode, cheapestpath);
/* XXX cheapest-path fields should point to members of pathlist? */
Node_Copy(from, newnode, cheapest_startup_path);
Node_Copy(from, newnode, cheapest_total_path);
newnode->pruneable = from->pruneable;
newnode->indexed = from->indexed;
@ -990,6 +992,7 @@ _copyRelOptInfo(RelOptInfo *from)
newnode->tuples = from->tuples;
Node_Copy(from, newnode, baserestrictinfo);
newnode->baserestrictcost = from->baserestrictcost;
Node_Copy(from, newnode, joininfo);
Node_Copy(from, newnode, innerjoin);
@ -1045,6 +1048,7 @@ _copyIndexOptInfo(IndexOptInfo *from)
newnode->amcostestimate = from->amcostestimate;
newnode->indproc = from->indproc;
Node_Copy(from, newnode, indpred);
newnode->lossy = from->lossy;
return newnode;
}
@ -1066,7 +1070,8 @@ CopyPathFields(Path *from, Path *newnode)
*/
newnode->parent = from->parent;
newnode->path_cost = from->path_cost;
newnode->startup_cost = from->startup_cost;
newnode->total_cost = from->total_cost;
newnode->pathtype = from->pathtype;
@ -1108,6 +1113,7 @@ _copyIndexPath(IndexPath *from)
*/
newnode->indexid = listCopy(from->indexid);
Node_Copy(from, newnode, indexqual);
newnode->indexscandir = from->indexscandir;
newnode->joinrelids = listCopy(from->joinrelids);
return newnode;
@ -1339,8 +1345,7 @@ _copyRangeTblEntry(RangeTblEntry *from)
if (from->relname)
newnode->relname = pstrdup(from->relname);
if (from->ref)
Node_Copy(from, newnode, ref);
Node_Copy(from, newnode, ref);
newnode->relid = from->relid;
newnode->inh = from->inh;
newnode->inFromCl = from->inFromCl;
@ -1449,8 +1454,10 @@ _copyQuery(Query *from)
Node_Copy(from, newnode, limitOffset);
Node_Copy(from, newnode, limitCount);
/* we do not copy the planner internal fields: base_rel_list,
* join_rel_list, query_pathkeys. Not entirely clear if this is right?
/*
* We do not copy the planner internal fields: base_rel_list,
* join_rel_list, equi_key_list, query_pathkeys.
* Not entirely clear if this is right?
*/
return newnode;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.60 2000/02/15 03:37:08 thomas Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.61 2000/02/15 20:49:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -100,10 +100,10 @@ _equalAttr(Attr *a, Attr *b)
{
if (!strcmp(a->relname, b->relname))
return false;
if (length(a->attrs) != length(b->attrs))
if (!equal(a->attrs, b->attrs))
return false;
return equal(a->attrs, b->attrs);
return true;
}
static bool
@ -342,8 +342,8 @@ _equalPath(Path *a, Path *b)
return false;
if (!equal(a->parent, b->parent))
return false;
/* do not check path_cost, since it may not be set yet, and being
* a float there are roundoff error issues anyway...
/* do not check path costs, since they may not be set yet, and being
* float values there are roundoff error issues anyway...
*/
if (!equal(a->pathkeys, b->pathkeys))
return false;
@ -359,6 +359,8 @@ _equalIndexPath(IndexPath *a, IndexPath *b)
return false;
if (!equal(a->indexqual, b->indexqual))
return false;
if (a->indexscandir != b->indexscandir)
return false;
if (!equali(a->joinrelids, b->joinrelids))
return false;
return true;
@ -625,8 +627,9 @@ _equalQuery(Query *a, Query *b)
/*
* We do not check the internal-to-the-planner fields: base_rel_list,
* join_rel_list, query_pathkeys. They might not be set yet, and
* in any case they should be derivable from the other fields.
* join_rel_list, equi_key_list, query_pathkeys.
* They might not be set yet, and in any case they should be derivable
* from the other fields.
*/
return true;
}
@ -644,16 +647,8 @@ _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
if (a->relname != b->relname)
return false;
}
if (a->ref && b->ref)
{
if (! equal(a->ref, b->ref))
return false;
}
else
{
if (a->ref != b->ref)
return false;
}
if (!equal(a->ref, b->ref))
return false;
if (a->relid != b->relid)
return false;
if (a->inh != b->inh)
@ -784,6 +779,9 @@ equal(void *a, void *b)
case T_Stream:
retval = _equalStream(a, b);
break;
case T_Attr:
retval = _equalAttr(a, b);
break;
case T_Var:
retval = _equalVar(a, b);
break;
@ -856,9 +854,6 @@ equal(void *a, void *b)
case T_EState:
retval = _equalEState(a, b);
break;
case T_Attr:
retval = _equalAttr(a, b);
break;
case T_Integer:
case T_String:
case T_Float:

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.35 2000/02/15 03:37:08 thomas Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.36 2000/02/15 20:49:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -730,10 +730,11 @@ _freeRelOptInfo(RelOptInfo *node)
freeObject(node->targetlist);
freeObject(node->pathlist);
/* XXX is this right? cheapestpath will typically be a pointer into
* pathlist, won't it?
/* XXX is this right? cheapest-path fields will typically be pointers
* into pathlist, not separate structs...
*/
freeObject(node->cheapestpath);
freeObject(node->cheapest_startup_path);
freeObject(node->cheapest_total_path);
freeObject(node->baserestrictinfo);
freeObject(node->joininfo);
@ -1013,8 +1014,7 @@ _freeRangeTblEntry(RangeTblEntry *node)
{
if (node->relname)
pfree(node->relname);
if (node->ref)
freeObject(node->ref);
freeObject(node->ref);
pfree(node);
}
@ -1024,8 +1024,7 @@ _freeAttr(Attr *node)
{
if (node->relname)
pfree(node->relname);
if (node->attrs)
freeObject(node->attrs);
freeObject(node->attrs);
pfree(node);
}
@ -1346,10 +1345,3 @@ freeObject(void *node)
break;
}
}

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.107 2000/02/15 03:37:09 thomas Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.108 2000/02/15 20:49:09 tgl Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
@ -321,8 +321,9 @@ static void
_outPlanInfo(StringInfo str, Plan *node)
{
appendStringInfo(str,
":cost %g :rows %.0f :width %d :state %s :qptargetlist ",
node->cost,
":startup_cost %.2f :total_cost %.2f :rows %.0f :width %d :state %s :qptargetlist ",
node->startup_cost,
node->total_cost,
node->plan_rows,
node->plan_width,
node->state ? "not-NULL" : "<>");
@ -908,15 +909,13 @@ _outRelOptInfo(StringInfo str, RelOptInfo *node)
appendStringInfo(str, " :pathlist ");
_outNode(str, node->pathlist);
/*
* Not sure if these are nodes or not. They're declared as struct
* Path *. Since i don't know, i'll just print the addresses for now.
* This can be changed later, if necessary.
*/
appendStringInfo(str, " :cheapest_startup_path ");
_outNode(str, node->cheapest_startup_path);
appendStringInfo(str, " :cheapest_total_path ");
_outNode(str, node->cheapest_total_path);
appendStringInfo(str,
" :cheapestpath @ 0x%x :pruneable %s :baserestrictinfo ",
(int) node->cheapestpath,
" :pruneable %s :baserestrictinfo ",
node->pruneable ? "true" : "false");
_outNode(str, node->baserestrictinfo);
@ -977,9 +976,11 @@ _outRowMark(StringInfo str, RowMark *node)
static void
_outPath(StringInfo str, Path *node)
{
appendStringInfo(str, " PATH :pathtype %d :cost %.2f :pathkeys ",
appendStringInfo(str,
" PATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
node->pathtype,
node->path_cost);
node->startup_cost,
node->total_cost);
_outNode(str, node->pathkeys);
}
@ -990,9 +991,10 @@ static void
_outIndexPath(StringInfo str, IndexPath *node)
{
appendStringInfo(str,
" INDEXPATH :pathtype %d :cost %.2f :pathkeys ",
" INDEXPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
node->path.pathtype,
node->path.path_cost);
node->path.startup_cost,
node->path.total_cost);
_outNode(str, node->path.pathkeys);
appendStringInfo(str, " :indexid ");
@ -1001,7 +1003,8 @@ _outIndexPath(StringInfo str, IndexPath *node)
appendStringInfo(str, " :indexqual ");
_outNode(str, node->indexqual);
appendStringInfo(str, " :joinrelids ");
appendStringInfo(str, " :indexscandir %d :joinrelids ",
(int) node->indexscandir);
_outIntList(str, node->joinrelids);
}
@ -1012,9 +1015,10 @@ static void
_outTidPath(StringInfo str, TidPath *node)
{
appendStringInfo(str,
" TIDPATH :pathtype %d :cost %.2f :pathkeys ",
" TIDPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
node->path.pathtype,
node->path.path_cost);
node->path.startup_cost,
node->path.total_cost);
_outNode(str, node->path.pathkeys);
appendStringInfo(str, " :tideval ");
@ -1031,9 +1035,10 @@ static void
_outNestPath(StringInfo str, NestPath *node)
{
appendStringInfo(str,
" NESTPATH :pathtype %d :cost %.2f :pathkeys ",
" NESTPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
node->path.pathtype,
node->path.path_cost);
node->path.startup_cost,
node->path.total_cost);
_outNode(str, node->path.pathkeys);
appendStringInfo(str, " :outerjoinpath ");
_outNode(str, node->outerjoinpath);
@ -1050,9 +1055,10 @@ static void
_outMergePath(StringInfo str, MergePath *node)
{
appendStringInfo(str,
" MERGEPATH :pathtype %d :cost %.2f :pathkeys ",
" MERGEPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
node->jpath.path.pathtype,
node->jpath.path.path_cost);
node->jpath.path.startup_cost,
node->jpath.path.total_cost);
_outNode(str, node->jpath.path.pathkeys);
appendStringInfo(str, " :outerjoinpath ");
_outNode(str, node->jpath.outerjoinpath);
@ -1078,9 +1084,10 @@ static void
_outHashPath(StringInfo str, HashPath *node)
{
appendStringInfo(str,
" HASHPATH :pathtype %d :cost %.2f :pathkeys ",
" HASHPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
node->jpath.path.pathtype,
node->jpath.path.path_cost);
node->jpath.path.startup_cost,
node->jpath.path.total_cost);
_outNode(str, node->jpath.path.pathkeys);
appendStringInfo(str, " :outerjoinpath ");
_outNode(str, node->jpath.outerjoinpath);
@ -1364,7 +1371,7 @@ _outNode(StringInfo str, void *obj)
return;
}
if (nodeTag(obj) == T_List)
if (IsA(obj, List))
{
List *l;
@ -1377,6 +1384,11 @@ _outNode(StringInfo str, void *obj)
}
appendStringInfoChar(str, ')');
}
else if (IsA_Value(obj))
{
/* nodeRead does not want to see { } around these! */
_outValue(str, obj);
}
else
{
appendStringInfoChar(str, '{');
@ -1550,11 +1562,6 @@ _outNode(StringInfo str, void *obj)
case T_Stream:
_outStream(str, obj);
break;
case T_Integer:
case T_String:
case T_Float:
_outValue(str, obj);
break;
case T_A_Expr:
_outAExpr(str, obj);
break;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.36 2000/02/15 03:37:09 thomas Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.37 2000/02/15 20:49:12 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -175,9 +175,8 @@ print_expr(Node *expr, List *rtable)
{
rt = rt_fetch(var->varno, rtable);
relname = rt->relname;
if (rt->ref)
if (rt->ref->relname)
relname = rt->relname; /* table renamed */
if (rt->ref && rt->ref->relname)
relname = rt->ref->relname; /* table renamed */
attname = get_attname(rt->relid, var->varattno);
}
break;
@ -366,8 +365,9 @@ print_plan_recursive(Plan *p, Query *parsetree, int indentLevel, char *label)
return;
for (i = 0; i < indentLevel; i++)
printf(" ");
printf("%s%s :c=%.4f :r=%.0f :w=%d ", label, plannode_type(p),
p->cost, p->plan_rows, p->plan_width);
printf("%s%s :c=%.2f..%.2f :r=%.0f :w=%d ", label, plannode_type(p),
p->startup_cost, p->total_cost,
p->plan_rows, p->plan_width);
if (IsA(p, Scan) ||IsA(p, SeqScan))
{
RangeTblEntry *rte;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.83 2000/02/15 03:37:09 thomas Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.84 2000/02/15 20:49:12 tgl Exp $
*
* NOTES
* Most of the read functions for plan nodes are tested. (In fact, they
@ -217,9 +217,13 @@ _getPlan(Plan *node)
char *token;
int length;
token = lsptok(NULL, &length); /* first token is :cost */
token = lsptok(NULL, &length); /* first token is :startup_cost */
token = lsptok(NULL, &length); /* next is the actual cost */
node->cost = (Cost) atof(token);
node->startup_cost = (Cost) atof(token);
token = lsptok(NULL, &length); /* skip the :total_cost */
token = lsptok(NULL, &length); /* next is the actual cost */
node->total_cost = (Cost) atof(token);
token = lsptok(NULL, &length); /* skip the :rows */
token = lsptok(NULL, &length); /* get the plan_rows */
@ -520,7 +524,6 @@ _readIndexScan()
token = lsptok(NULL, &length); /* eat :indxorderdir */
token = lsptok(NULL, &length); /* get indxorderdir */
local_node->indxorderdir = atoi(token);
return local_node;
@ -1275,18 +1278,15 @@ _readRelOptInfo()
token = lsptok(NULL, &length); /* get :pathlist */
local_node->pathlist = nodeRead(true); /* now read it */
/*
* Not sure if these are nodes or not. They're declared as struct
* Path *. Since i don't know, i'll just print the addresses for now.
* This can be changed later, if necessary.
*/
token = lsptok(NULL, &length); /* get :cheapest_startup_path */
local_node->cheapest_startup_path = nodeRead(true); /* now read it */
token = lsptok(NULL, &length); /* get :cheapestpath */
token = lsptok(NULL, &length); /* get @ */
token = lsptok(NULL, &length); /* now read it */
sscanf(token, "%x", (unsigned int *) &local_node->cheapestpath);
token = lsptok(NULL, &length); /* get :cheapest_total_path */
local_node->cheapest_total_path = nodeRead(true); /* now read it */
token = lsptok(NULL, &length); /* eat :pruneable */
token = lsptok(NULL, &length); /* get :pruneable */
local_node->pruneable = (token[0] == 't') ? true : false;
token = lsptok(NULL, &length); /* get :baserestrictinfo */
local_node->baserestrictinfo = nodeRead(true); /* now read it */
@ -1322,29 +1322,6 @@ _readTargetEntry()
return local_node;
}
static List *
_readList()
{
List *local_node = NULL;
char *token;
int length;
token = lsptok(NULL, &length); /* eat "(" */
token = lsptok(NULL, &length); /* get "{" */
while (strncmp(token, "{", length) == 0)
{
nconc(local_node, nodeRead(true));
token = lsptok(NULL, &length); /* eat ")" */
if (strncmp(token, "}", length) != 0)
elog(ERROR, "badly formatted attribute list"
" in planstring \"%.10s\"...\n", token);
token = lsptok(NULL, &length); /* "{" or ")" */
}
return local_node;
}
static Attr *
_readAttr()
{
@ -1356,13 +1333,10 @@ _readAttr()
token = lsptok(NULL, &length); /* eat :relname */
token = lsptok(NULL, &length); /* get relname */
if (length == 0)
local_node->relname = pstrdup("");
else
local_node->relname = debackslash(token, length);
local_node->relname = debackslash(token, length);
token = lsptok(NULL, &length); /* eat :attrs */
local_node->attrs = _readList();
local_node->attrs = nodeRead(true); /* now read it */
return local_node;
}
@ -1388,7 +1362,7 @@ _readRangeTblEntry()
local_node->relname = debackslash(token, length);
token = lsptok(NULL, &length); /* eat :ref */
local_node->ref = nodeRead(true);
local_node->ref = nodeRead(true); /* now read it */
token = lsptok(NULL, &length); /* eat :relid */
token = lsptok(NULL, &length); /* get :relid */
@ -1450,9 +1424,13 @@ _readPath()
token = lsptok(NULL, &length); /* now read it */
local_node->pathtype = atol(token);
token = lsptok(NULL, &length); /* get :cost */
token = lsptok(NULL, &length); /* get :startup_cost */
token = lsptok(NULL, &length); /* now read it */
local_node->path_cost = (Cost) atof(token);
local_node->startup_cost = (Cost) atof(token);
token = lsptok(NULL, &length); /* get :total_cost */
token = lsptok(NULL, &length); /* now read it */
local_node->total_cost = (Cost) atof(token);
token = lsptok(NULL, &length); /* get :pathkeys */
local_node->pathkeys = nodeRead(true); /* now read it */
@ -1479,9 +1457,13 @@ _readIndexPath()
token = lsptok(NULL, &length); /* now read it */
local_node->path.pathtype = atol(token);
token = lsptok(NULL, &length); /* get :cost */
token = lsptok(NULL, &length); /* get :startup_cost */
token = lsptok(NULL, &length); /* now read it */
local_node->path.path_cost = (Cost) atof(token);
local_node->path.startup_cost = (Cost) atof(token);
token = lsptok(NULL, &length); /* get :total_cost */
token = lsptok(NULL, &length); /* now read it */
local_node->path.total_cost = (Cost) atof(token);
token = lsptok(NULL, &length); /* get :pathkeys */
local_node->path.pathkeys = nodeRead(true); /* now read it */
@ -1492,6 +1474,10 @@ _readIndexPath()
token = lsptok(NULL, &length); /* get :indexqual */
local_node->indexqual = nodeRead(true); /* now read it */
token = lsptok(NULL, &length); /* get :indexscandir */
token = lsptok(NULL, &length); /* now read it */
local_node->indexscandir = (ScanDirection) atoi(token);
token = lsptok(NULL, &length); /* get :joinrelids */
local_node->joinrelids = toIntList(nodeRead(true));
@ -1517,9 +1503,13 @@ _readTidPath()
token = lsptok(NULL, &length); /* now read it */
local_node->path.pathtype = atol(token);
token = lsptok(NULL, &length); /* get :cost */
token = lsptok(NULL, &length); /* get :startup_cost */
token = lsptok(NULL, &length); /* now read it */
local_node->path.path_cost = (Cost) atof(token);
local_node->path.startup_cost = (Cost) atof(token);
token = lsptok(NULL, &length); /* get :total_cost */
token = lsptok(NULL, &length); /* now read it */
local_node->path.total_cost = (Cost) atof(token);
token = lsptok(NULL, &length); /* get :pathkeys */
local_node->path.pathkeys = nodeRead(true); /* now read it */
@ -1552,9 +1542,13 @@ _readNestPath()
token = lsptok(NULL, &length); /* now read it */
local_node->path.pathtype = atol(token);
token = lsptok(NULL, &length); /* get :cost */
token = lsptok(NULL, &length); /* get :startup_cost */
token = lsptok(NULL, &length); /* now read it */
local_node->path.path_cost = (Cost) atof(token);
local_node->path.startup_cost = (Cost) atof(token);
token = lsptok(NULL, &length); /* get :total_cost */
token = lsptok(NULL, &length); /* now read it */
local_node->path.total_cost = (Cost) atof(token);
token = lsptok(NULL, &length); /* get :pathkeys */
local_node->path.pathkeys = nodeRead(true); /* now read it */
@ -1588,13 +1582,15 @@ _readMergePath()
token = lsptok(NULL, &length); /* get :pathtype */
token = lsptok(NULL, &length); /* now read it */
local_node->jpath.path.pathtype = atol(token);
token = lsptok(NULL, &length); /* get :cost */
token = lsptok(NULL, &length); /* get :startup_cost */
token = lsptok(NULL, &length); /* now read it */
local_node->jpath.path.startup_cost = (Cost) atof(token);
local_node->jpath.path.path_cost = (Cost) atof(token);
token = lsptok(NULL, &length); /* get :total_cost */
token = lsptok(NULL, &length); /* now read it */
local_node->jpath.path.total_cost = (Cost) atof(token);
token = lsptok(NULL, &length); /* get :pathkeys */
local_node->jpath.path.pathkeys = nodeRead(true); /* now read it */
@ -1637,13 +1633,15 @@ _readHashPath()
token = lsptok(NULL, &length); /* get :pathtype */
token = lsptok(NULL, &length); /* now read it */
local_node->jpath.path.pathtype = atol(token);
token = lsptok(NULL, &length); /* get :cost */
token = lsptok(NULL, &length); /* get :startup_cost */
token = lsptok(NULL, &length); /* now read it */
local_node->jpath.path.startup_cost = (Cost) atof(token);
local_node->jpath.path.path_cost = (Cost) atof(token);
token = lsptok(NULL, &length); /* get :total_cost */
token = lsptok(NULL, &length); /* now read it */
local_node->jpath.path.total_cost = (Cost) atof(token);
token = lsptok(NULL, &length); /* get :pathkeys */
local_node->jpath.path.pathkeys = nodeRead(true); /* now read it */
@ -1886,14 +1884,6 @@ parsePlanString(void)
return_value = _readCaseWhen();
else if (length == 7 && strncmp(token, "ROWMARK", length) == 0)
return_value = _readRowMark();
#if 0
else if (length == 1 && strncmp(token, "{", length) == 0)
{
/* raw list (of strings?) found in Attr structure - thomas 2000-02-09 */
return_value = nodeRead(true);
token = lsptok(NULL, &length); /* eat trailing brace */
}
#endif
else
elog(ERROR, "badly formatted planstring \"%.10s\"...\n", token);