mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-09 08:10:09 +08:00
Modify optimizer data structures so that IndexOptInfo lists built for
create_index_paths are not immediately discarded, but are available for subsequent planner work. This allows avoiding redundant syscache lookups in several places. Change interface to operator selectivity estimation procedures to allow faster and more flexible estimation. Initdb forced due to change of pg_proc entries for selectivity functions!
This commit is contained in:
parent
5d53389cfe
commit
be03eb25f3
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.57 2001/03/22 06:16:10 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.58 2001/05/20 20:28:17 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* these routines moved here from commands/define.c and somewhat cleaned up.
|
||||
@ -69,7 +69,7 @@ static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
|
||||
/* ----------------------------------------------------------------
|
||||
* OperatorGetWithOpenRelation
|
||||
*
|
||||
* preforms a scan on pg_operator for an operator tuple
|
||||
* performs a scan on pg_operator for an operator tuple
|
||||
* with given name and left/right type oids.
|
||||
* ----------------------------------------------------------------
|
||||
* pg_operator_desc -- reldesc for pg_operator
|
||||
@ -570,26 +570,25 @@ OperatorDef(char *operatorName,
|
||||
ReleaseSysCache(tup);
|
||||
|
||||
/*
|
||||
* find restriction
|
||||
* find restriction estimator
|
||||
*/
|
||||
if (restrictionName)
|
||||
{ /* optional */
|
||||
Oid restOid;
|
||||
|
||||
MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||
typeId[0] = OIDOID; /* operator OID */
|
||||
typeId[1] = OIDOID; /* relation OID */
|
||||
typeId[2] = INT2OID; /* attribute number */
|
||||
typeId[3] = 0; /* value - can be any type */
|
||||
typeId[4] = INT4OID; /* flags - left or right selectivity */
|
||||
typeId[0] = 0; /* Query (opaque type) */
|
||||
typeId[1] = OIDOID; /* operator OID */
|
||||
typeId[2] = 0; /* args list (opaque type) */
|
||||
typeId[3] = INT4OID; /* varRelid */
|
||||
|
||||
restOid = GetSysCacheOid(PROCNAME,
|
||||
PointerGetDatum(restrictionName),
|
||||
Int32GetDatum(5),
|
||||
Int32GetDatum(4),
|
||||
PointerGetDatum(typeId),
|
||||
0);
|
||||
if (!OidIsValid(restOid))
|
||||
func_error("OperatorDef", restrictionName, 5, typeId, NULL);
|
||||
func_error("OperatorDef", restrictionName, 4, typeId, NULL);
|
||||
|
||||
values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restOid);
|
||||
}
|
||||
@ -597,26 +596,24 @@ OperatorDef(char *operatorName,
|
||||
values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
|
||||
|
||||
/*
|
||||
* find join - only valid for binary operators
|
||||
* find join estimator
|
||||
*/
|
||||
if (joinName)
|
||||
{ /* optional */
|
||||
Oid joinOid;
|
||||
|
||||
MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||
typeId[0] = OIDOID; /* operator OID */
|
||||
typeId[1] = OIDOID; /* relation OID 1 */
|
||||
typeId[2] = INT2OID; /* attribute number 1 */
|
||||
typeId[3] = OIDOID; /* relation OID 2 */
|
||||
typeId[4] = INT2OID; /* attribute number 2 */
|
||||
typeId[0] = 0; /* Query (opaque type) */
|
||||
typeId[1] = OIDOID; /* operator OID */
|
||||
typeId[2] = 0; /* args list (opaque type) */
|
||||
|
||||
joinOid = GetSysCacheOid(PROCNAME,
|
||||
PointerGetDatum(joinName),
|
||||
Int32GetDatum(5),
|
||||
Int32GetDatum(3),
|
||||
PointerGetDatum(typeId),
|
||||
0);
|
||||
if (!OidIsValid(joinOid))
|
||||
func_error("OperatorDef", joinName, 5, typeId, NULL);
|
||||
func_error("OperatorDef", joinName, 3, typeId, NULL);
|
||||
|
||||
values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
|
||||
}
|
||||
@ -1044,10 +1041,8 @@ OperatorCreate(char *operatorName,
|
||||
/* If it's not a binary op, these things mustn't be set: */
|
||||
if (commutatorName)
|
||||
elog(ERROR, "OperatorCreate: only binary operators can have commutators");
|
||||
if (negatorName)
|
||||
elog(ERROR, "OperatorCreate: only binary operators can have negators");
|
||||
if (restrictionName || joinName)
|
||||
elog(ERROR, "OperatorCreate: only binary operators can have selectivity");
|
||||
if (joinName)
|
||||
elog(ERROR, "OperatorCreate: only binary operators can have join selectivity");
|
||||
if (canHash)
|
||||
elog(ERROR, "OperatorCreate: only binary operators can hash");
|
||||
if (leftSortName || rightSortName)
|
||||
|
@ -15,7 +15,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.141 2001/05/07 00:43:18 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.142 2001/05/20 20:28:17 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1071,7 +1071,7 @@ _copyRelOptInfo(RelOptInfo *from)
|
||||
newnode->pruneable = from->pruneable;
|
||||
|
||||
newnode->issubquery = from->issubquery;
|
||||
newnode->indexed = from->indexed;
|
||||
Node_Copy(from, newnode, indexlist);
|
||||
newnode->pages = from->pages;
|
||||
newnode->tuples = from->tuples;
|
||||
Node_Copy(from, newnode, subplan);
|
||||
@ -1093,47 +1093,44 @@ static IndexOptInfo *
|
||||
_copyIndexOptInfo(IndexOptInfo *from)
|
||||
{
|
||||
IndexOptInfo *newnode = makeNode(IndexOptInfo);
|
||||
int i,
|
||||
len;
|
||||
Size len;
|
||||
|
||||
newnode->indexoid = from->indexoid;
|
||||
newnode->pages = from->pages;
|
||||
newnode->tuples = from->tuples;
|
||||
|
||||
newnode->ncolumns = from->ncolumns;
|
||||
newnode->nkeys = from->nkeys;
|
||||
|
||||
if (from->classlist)
|
||||
{
|
||||
for (len = 0; from->classlist[len] != 0; len++)
|
||||
;
|
||||
newnode->classlist = (Oid *) palloc(sizeof(Oid) * (len + 1));
|
||||
for (i = 0; i < len; i++)
|
||||
newnode->classlist[i] = from->classlist[i];
|
||||
newnode->classlist[len] = 0;
|
||||
/* copy the trailing zero too */
|
||||
len = (from->ncolumns + 1) * sizeof(Oid);
|
||||
newnode->classlist = (Oid *) palloc(len);
|
||||
memcpy(newnode->classlist, from->classlist, len);
|
||||
}
|
||||
|
||||
if (from->indexkeys)
|
||||
{
|
||||
for (len = 0; from->indexkeys[len] != 0; len++)
|
||||
;
|
||||
newnode->indexkeys = (int *) palloc(sizeof(int) * (len + 1));
|
||||
for (i = 0; i < len; i++)
|
||||
newnode->indexkeys[i] = from->indexkeys[i];
|
||||
newnode->indexkeys[len] = 0;
|
||||
/* copy the trailing zero too */
|
||||
len = (from->nkeys + 1) * sizeof(int);
|
||||
newnode->indexkeys = (int *) palloc(len);
|
||||
memcpy(newnode->indexkeys, from->indexkeys, len);
|
||||
}
|
||||
|
||||
if (from->ordering)
|
||||
{
|
||||
for (len = 0; from->ordering[len] != 0; len++)
|
||||
;
|
||||
newnode->ordering = (Oid *) palloc(sizeof(Oid) * (len + 1));
|
||||
for (i = 0; i < len; i++)
|
||||
newnode->ordering[i] = from->ordering[i];
|
||||
newnode->ordering[len] = 0;
|
||||
/* copy the trailing zero too */
|
||||
len = (from->ncolumns + 1) * sizeof(Oid);
|
||||
newnode->ordering = (Oid *) palloc(len);
|
||||
memcpy(newnode->ordering, from->ordering, len);
|
||||
}
|
||||
|
||||
newnode->relam = from->relam;
|
||||
newnode->amcostestimate = from->amcostestimate;
|
||||
newnode->indproc = from->indproc;
|
||||
Node_Copy(from, newnode, indpred);
|
||||
newnode->unique = from->unique;
|
||||
newnode->lossy = from->lossy;
|
||||
|
||||
return newnode;
|
||||
@ -1196,7 +1193,7 @@ _copyIndexPath(IndexPath *from)
|
||||
/*
|
||||
* copy remainder of node
|
||||
*/
|
||||
newnode->indexid = listCopy(from->indexid);
|
||||
Node_Copy(from, newnode, indexinfo);
|
||||
Node_Copy(from, newnode, indexqual);
|
||||
newnode->indexscandir = from->indexscandir;
|
||||
newnode->joinrelids = listCopy(from->joinrelids);
|
||||
@ -1749,8 +1746,8 @@ _copyQuery(Query *from)
|
||||
|
||||
/*
|
||||
* 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?
|
||||
* other_rel_list, join_rel_list, equi_key_list, query_pathkeys.
|
||||
* Not entirely clear if this is right?
|
||||
*/
|
||||
|
||||
return newnode;
|
||||
|
@ -20,7 +20,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.89 2001/05/07 00:43:19 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.90 2001/05/20 20:28:18 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -405,7 +405,7 @@ _equalIndexPath(IndexPath *a, IndexPath *b)
|
||||
{
|
||||
if (!_equalPath((Path *) a, (Path *) b))
|
||||
return false;
|
||||
if (!equali(a->indexid, b->indexid))
|
||||
if (!equal(a->indexinfo, b->indexinfo))
|
||||
return false;
|
||||
if (!equal(a->indexqual, b->indexqual))
|
||||
return false;
|
||||
@ -623,9 +623,9 @@ _equalQuery(Query *a, Query *b)
|
||||
|
||||
/*
|
||||
* We do not check the internal-to-the-planner fields: base_rel_list,
|
||||
* 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.
|
||||
* other_rel_list, 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;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.140 2001/03/22 03:59:32 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.141 2001/05/20 20:28:18 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Every (plan) node in POSTGRES has an associated "out" routine which
|
||||
@ -952,56 +952,6 @@ _outJoinExpr(StringInfo str, JoinExpr *node)
|
||||
_outNode(str, node->colvars);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stuff from relation.h
|
||||
*/
|
||||
|
||||
static void
|
||||
_outRelOptInfo(StringInfo str, RelOptInfo *node)
|
||||
{
|
||||
appendStringInfo(str, " RELOPTINFO :relids ");
|
||||
_outIntList(str, node->relids);
|
||||
|
||||
appendStringInfo(str, " :rows %.0f :width %d :targetlist ",
|
||||
node->rows,
|
||||
node->width);
|
||||
_outNode(str, node->targetlist);
|
||||
|
||||
appendStringInfo(str, " :pathlist ");
|
||||
_outNode(str, node->pathlist);
|
||||
appendStringInfo(str, " :cheapest_startup_path ");
|
||||
_outNode(str, node->cheapest_startup_path);
|
||||
appendStringInfo(str, " :cheapest_total_path ");
|
||||
_outNode(str, node->cheapest_total_path);
|
||||
|
||||
appendStringInfo(str, " :pruneable %s :issubquery %s :indexed %s :pages %ld :tuples %.0f :subplan ",
|
||||
booltostr(node->pruneable),
|
||||
booltostr(node->issubquery),
|
||||
booltostr(node->indexed),
|
||||
node->pages,
|
||||
node->tuples);
|
||||
_outNode(str, node->subplan);
|
||||
|
||||
appendStringInfo(str, " :baserestrictinfo ");
|
||||
_outNode(str, node->baserestrictinfo);
|
||||
appendStringInfo(str, " :baserestrictcost %.2f :outerjoinset ",
|
||||
node->baserestrictcost);
|
||||
_outIntList(str, node->outerjoinset);
|
||||
appendStringInfo(str, " :joininfo ");
|
||||
_outNode(str, node->joininfo);
|
||||
appendStringInfo(str, " :innerjoin ");
|
||||
_outNode(str, node->innerjoin);
|
||||
}
|
||||
|
||||
static void
|
||||
_outIndexOptInfo(StringInfo str, IndexOptInfo *node)
|
||||
{
|
||||
appendStringInfo(str, " INDEXOPTINFO :indexoid %u :pages %ld :tuples %g ",
|
||||
node->indexoid,
|
||||
node->pages,
|
||||
node->tuples);
|
||||
}
|
||||
|
||||
/*
|
||||
* TargetEntry is a subclass of Node.
|
||||
*/
|
||||
@ -1064,8 +1014,8 @@ _outIndexPath(StringInfo str, IndexPath *node)
|
||||
node->path.total_cost);
|
||||
_outNode(str, node->path.pathkeys);
|
||||
|
||||
appendStringInfo(str, " :indexid ");
|
||||
_outOidList(str, node->indexid);
|
||||
appendStringInfo(str, " :indexinfo ");
|
||||
_outNode(str, node->indexinfo);
|
||||
|
||||
appendStringInfo(str, " :indexqual ");
|
||||
_outNode(str, node->indexqual);
|
||||
@ -1629,12 +1579,6 @@ _outNode(StringInfo str, void *obj)
|
||||
case T_JoinExpr:
|
||||
_outJoinExpr(str, obj);
|
||||
break;
|
||||
case T_RelOptInfo:
|
||||
_outRelOptInfo(str, obj);
|
||||
break;
|
||||
case T_IndexOptInfo:
|
||||
_outIndexOptInfo(str, obj);
|
||||
break;
|
||||
case T_TargetEntry:
|
||||
_outTargetEntry(str, obj);
|
||||
break;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.108 2001/05/07 00:43:19 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.109 2001/05/20 20:28:18 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Most of the read functions for plan nodes are tested. (In fact, they
|
||||
@ -1318,88 +1318,6 @@ _readJoinExpr(void)
|
||||
return local_node;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stuff from relation.h
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* _readRelOptInfo
|
||||
* ----------------
|
||||
*/
|
||||
static RelOptInfo *
|
||||
_readRelOptInfo(void)
|
||||
{
|
||||
RelOptInfo *local_node;
|
||||
char *token;
|
||||
int length;
|
||||
|
||||
local_node = makeNode(RelOptInfo);
|
||||
|
||||
token = pg_strtok(&length); /* get :relids */
|
||||
local_node->relids = toIntList(nodeRead(true)); /* now read it */
|
||||
|
||||
token = pg_strtok(&length); /* get :rows */
|
||||
token = pg_strtok(&length); /* now read it */
|
||||
local_node->rows = atof(token);
|
||||
|
||||
token = pg_strtok(&length); /* get :width */
|
||||
token = pg_strtok(&length); /* now read it */
|
||||
local_node->width = atoi(token);
|
||||
|
||||
token = pg_strtok(&length); /* get :targetlist */
|
||||
local_node->targetlist = nodeRead(true); /* now read it */
|
||||
|
||||
token = pg_strtok(&length); /* get :pathlist */
|
||||
local_node->pathlist = nodeRead(true); /* now read it */
|
||||
|
||||
token = pg_strtok(&length); /* get :cheapest_startup_path */
|
||||
local_node->cheapest_startup_path = nodeRead(true); /* now read it */
|
||||
|
||||
token = pg_strtok(&length); /* get :cheapest_total_path */
|
||||
local_node->cheapest_total_path = nodeRead(true); /* now read it */
|
||||
|
||||
token = pg_strtok(&length); /* eat :pruneable */
|
||||
token = pg_strtok(&length); /* get :pruneable */
|
||||
local_node->pruneable = strtobool(token);
|
||||
|
||||
token = pg_strtok(&length); /* get :issubquery */
|
||||
token = pg_strtok(&length); /* now read it */
|
||||
local_node->issubquery = strtobool(token);
|
||||
|
||||
token = pg_strtok(&length); /* get :indexed */
|
||||
token = pg_strtok(&length); /* now read it */
|
||||
local_node->indexed = strtobool(token);
|
||||
|
||||
token = pg_strtok(&length); /* get :pages */
|
||||
token = pg_strtok(&length); /* now read it */
|
||||
local_node->pages = atol(token);
|
||||
|
||||
token = pg_strtok(&length); /* get :tuples */
|
||||
token = pg_strtok(&length); /* now read it */
|
||||
local_node->tuples = atof(token);
|
||||
|
||||
token = pg_strtok(&length); /* get :subplan */
|
||||
local_node->subplan = nodeRead(true); /* now read it */
|
||||
|
||||
token = pg_strtok(&length); /* get :baserestrictinfo */
|
||||
local_node->baserestrictinfo = nodeRead(true); /* now read it */
|
||||
|
||||
token = pg_strtok(&length); /* get :baserestrictcost */
|
||||
token = pg_strtok(&length); /* now read it */
|
||||
local_node->baserestrictcost = (Cost) atof(token);
|
||||
|
||||
token = pg_strtok(&length); /* get :outerjoinset */
|
||||
local_node->outerjoinset = toIntList(nodeRead(true)); /* now read it */
|
||||
|
||||
token = pg_strtok(&length); /* get :joininfo */
|
||||
local_node->joininfo = nodeRead(true); /* now read it */
|
||||
|
||||
token = pg_strtok(&length); /* get :innerjoin */
|
||||
local_node->innerjoin = nodeRead(true); /* now read it */
|
||||
|
||||
return local_node;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* _readTargetEntry
|
||||
* ----------------
|
||||
@ -1557,8 +1475,8 @@ _readIndexPath(void)
|
||||
token = pg_strtok(&length); /* get :pathkeys */
|
||||
local_node->path.pathkeys = nodeRead(true); /* now read it */
|
||||
|
||||
token = pg_strtok(&length); /* get :indexid */
|
||||
local_node->indexid = toOidList(nodeRead(true));
|
||||
token = pg_strtok(&length); /* get :indexinfo */
|
||||
local_node->indexinfo = nodeRead(true); /* now read it */
|
||||
|
||||
token = pg_strtok(&length); /* get :indexqual */
|
||||
local_node->indexqual = nodeRead(true); /* now read it */
|
||||
@ -2008,8 +1926,6 @@ parsePlanString(void)
|
||||
return_value = _readOper();
|
||||
else if (length == 5 && strncmp(token, "PARAM", length) == 0)
|
||||
return_value = _readParam();
|
||||
else if (length == 10 && strncmp(token, "RELOPTINFO", length) == 0)
|
||||
return_value = _readRelOptInfo();
|
||||
else if (length == 11 && strncmp(token, "TARGETENTRY", length) == 0)
|
||||
return_value = _readTargetEntry();
|
||||
else if (length == 3 && strncmp(token, "RTE", length) == 0)
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.73 2001/05/08 17:25:28 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.74 2001/05/20 20:28:18 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -35,8 +35,8 @@ static void set_base_rel_pathlists(Query *root);
|
||||
static void set_plain_rel_pathlist(Query *root, RelOptInfo *rel,
|
||||
RangeTblEntry *rte);
|
||||
static void set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
|
||||
RangeTblEntry *rte,
|
||||
List *inheritlist);
|
||||
Index rti, RangeTblEntry *rte,
|
||||
List *inheritlist);
|
||||
static RelOptInfo *make_one_rel_by_joins(Query *root, int levels_needed,
|
||||
List *initial_rels);
|
||||
|
||||
@ -69,7 +69,7 @@ make_one_rel(Query *root)
|
||||
rel = make_fromexpr_rel(root, root->jointree);
|
||||
|
||||
/*
|
||||
* The result should join all the query's rels.
|
||||
* The result should join all the query's base rels.
|
||||
*/
|
||||
Assert(length(rel->relids) == length(root->base_rel_list));
|
||||
|
||||
@ -190,10 +190,11 @@ set_base_rel_pathlists(Query *root)
|
||||
/* Select cheapest path (pretty easy in this case...) */
|
||||
set_cheapest(rel);
|
||||
}
|
||||
else if ((inheritlist = expand_inherted_rtentry(root, rti)) != NIL)
|
||||
else if ((inheritlist = expand_inherted_rtentry(root, rti, true))
|
||||
!= NIL)
|
||||
{
|
||||
/* Relation is root of an inheritance tree, process specially */
|
||||
set_inherited_rel_pathlist(root, rel, rte, inheritlist);
|
||||
set_inherited_rel_pathlist(root, rel, rti, rte, inheritlist);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -210,8 +211,6 @@ set_base_rel_pathlists(Query *root)
|
||||
static void
|
||||
set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte)
|
||||
{
|
||||
List *indices = find_secondary_indexes(rte->relid);
|
||||
|
||||
/* Mark rel with estimated output rows, width, etc */
|
||||
set_baserel_size_estimates(root, rel);
|
||||
|
||||
@ -230,13 +229,9 @@ set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte)
|
||||
create_tidscan_paths(root, rel);
|
||||
|
||||
/* Consider index paths for both simple and OR index clauses */
|
||||
create_index_paths(root, rel, indices);
|
||||
create_index_paths(root, rel);
|
||||
|
||||
/*
|
||||
* Note: create_or_index_paths depends on create_index_paths to have
|
||||
* marked OR restriction clauses with relevant indices; this is why it
|
||||
* doesn't need to be given the list of indices.
|
||||
*/
|
||||
/* create_index_paths must be done before create_or_index_paths */
|
||||
create_or_index_paths(root, rel, rel->baserestrictinfo);
|
||||
|
||||
/* Now find the cheapest of the paths for this rel */
|
||||
@ -248,14 +243,26 @@ set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte)
|
||||
* Build access paths for a inheritance tree rooted at rel
|
||||
*
|
||||
* inheritlist is a list of RT indexes of all tables in the inheritance tree,
|
||||
* including the parent itself. Note we will not come here unless there's
|
||||
* at least one child in addition to the parent.
|
||||
* including a duplicate of the parent itself. Note we will not come here
|
||||
* unless there's at least one child in addition to the parent.
|
||||
*
|
||||
* NOTE: the passed-in rel and RTE will henceforth represent the appended
|
||||
* result of the whole inheritance tree. The members of inheritlist represent
|
||||
* the individual tables --- in particular, the inheritlist member that is a
|
||||
* duplicate of the parent RTE represents the parent table alone.
|
||||
* We will generate plans to scan the individual tables that refer to
|
||||
* the inheritlist RTEs, whereas Vars elsewhere in the plan tree that
|
||||
* refer to the original RTE are taken to refer to the append output.
|
||||
* In particular, this means we have separate RelOptInfos for the parent
|
||||
* table and for the append output, which is a good thing because they're
|
||||
* not the same size.
|
||||
*/
|
||||
static void
|
||||
set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte,
|
||||
set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
|
||||
Index rti, RangeTblEntry *rte,
|
||||
List *inheritlist)
|
||||
{
|
||||
int parentRTindex = lfirsti(rel->relids);
|
||||
int parentRTindex = rti;
|
||||
Oid parentOID = rte->relid;
|
||||
List *subpaths = NIL;
|
||||
List *il;
|
||||
@ -268,7 +275,15 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte,
|
||||
elog(ERROR, "SELECT FOR UPDATE is not supported for inherit queries");
|
||||
|
||||
/*
|
||||
* Recompute size estimates for whole inheritance tree
|
||||
* The executor will check the parent table's access permissions when it
|
||||
* examines the parent's inheritlist entry. There's no need to check
|
||||
* twice, so turn off access check bits in the original RTE.
|
||||
*/
|
||||
rte->checkForRead = false;
|
||||
rte->checkForWrite = false;
|
||||
|
||||
/*
|
||||
* Initialize to compute size estimates for whole inheritance tree
|
||||
*/
|
||||
rel->rows = 0;
|
||||
rel->width = 0;
|
||||
@ -289,21 +304,17 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte,
|
||||
|
||||
/*
|
||||
* Make a RelOptInfo for the child so we can do planning. Do NOT
|
||||
* attach the RelOptInfo to the query's base_rel_list, however.
|
||||
*
|
||||
* NOTE: when childRTindex == parentRTindex, we create a second
|
||||
* RelOptInfo for the same relation. This RelOptInfo will
|
||||
* represent the parent table alone, whereas the original
|
||||
* RelOptInfo represents the union of the inheritance tree
|
||||
* members.
|
||||
* attach the RelOptInfo to the query's base_rel_list, however,
|
||||
* since the child is not part of the main join tree. Instead,
|
||||
* the child RelOptInfo is added to other_rel_list.
|
||||
*/
|
||||
childrel = make_base_rel(root, childRTindex);
|
||||
childrel = build_other_rel(root, childRTindex);
|
||||
|
||||
/*
|
||||
* Copy the parent's targetlist and restriction quals to the
|
||||
* child, with attribute-number adjustment if needed. We don't
|
||||
* child, with attribute-number adjustment as needed. We don't
|
||||
* bother to copy the join quals, since we can't do any joining
|
||||
* here.
|
||||
* of the individual tables.
|
||||
*/
|
||||
childrel->targetlist = (List *)
|
||||
adjust_inherited_attrs((Node *) rel->targetlist,
|
||||
|
@ -8,13 +8,15 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.43 2001/03/23 04:49:53 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.44 2001/05/20 20:28:18 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/cost.h"
|
||||
#include "optimizer/plancat.h"
|
||||
@ -24,6 +26,12 @@
|
||||
#include "utils/lsyscache.h"
|
||||
|
||||
|
||||
/* note that pg_type.h hardwires size of bool as 1 ... duplicate it */
|
||||
#define MAKEBOOLCONST(val,isnull) \
|
||||
((Node *) makeConst(BOOLOID, 1, (Datum) (val), \
|
||||
(isnull), true, false, false))
|
||||
|
||||
|
||||
/*
|
||||
* Data structure for accumulating info about possible range-query
|
||||
* clause pairs in clauselist_selectivity.
|
||||
@ -39,7 +47,7 @@ typedef struct RangeQueryClause
|
||||
} RangeQueryClause;
|
||||
|
||||
static void addRangeClause(RangeQueryClause **rqlist, Node *clause,
|
||||
int flag, bool isLTsel, Selectivity s2);
|
||||
bool varonleft, bool isLTsel, Selectivity s2);
|
||||
static Selectivity clause_selectivity(Query *root,
|
||||
Node *clause,
|
||||
int varRelid);
|
||||
@ -131,35 +139,24 @@ clauselist_selectivity(Query *root,
|
||||
* match what clause_selectivity() would do in the cases it
|
||||
* handles.
|
||||
*/
|
||||
if (varRelid != 0 || NumRelids(clause) == 1)
|
||||
if (is_opclause(clause) &&
|
||||
(varRelid != 0 || NumRelids(clause) == 1))
|
||||
{
|
||||
int relidx;
|
||||
AttrNumber attno;
|
||||
Datum constval;
|
||||
int flag;
|
||||
Expr *expr = (Expr *) clause;
|
||||
|
||||
get_relattval(clause, varRelid,
|
||||
&relidx, &attno, &constval, &flag);
|
||||
if (relidx != 0)
|
||||
if (length(expr->args) == 2)
|
||||
{
|
||||
/* if get_relattval succeeded, it must be an opclause */
|
||||
Var *other;
|
||||
bool varonleft = true;
|
||||
|
||||
other = (flag & SEL_RIGHT) ? get_rightop((Expr *) clause) :
|
||||
get_leftop((Expr *) clause);
|
||||
if (is_pseudo_constant_clause((Node *) other))
|
||||
if (is_pseudo_constant_clause(lsecond(expr->args)) ||
|
||||
(varonleft = false,
|
||||
is_pseudo_constant_clause(lfirst(expr->args))))
|
||||
{
|
||||
Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno;
|
||||
Oid opno = ((Oper *) expr->oper)->opno;
|
||||
RegProcedure oprrest = get_oprrest(opno);
|
||||
|
||||
if (!oprrest)
|
||||
s2 = (Selectivity) 0.5;
|
||||
else
|
||||
s2 = restriction_selectivity(oprrest, opno,
|
||||
getrelid(relidx,
|
||||
root->rtable),
|
||||
attno,
|
||||
constval, flag);
|
||||
s2 = restriction_selectivity(root, opno,
|
||||
expr->args, varRelid);
|
||||
|
||||
/*
|
||||
* If we reach here, we have computed the same result
|
||||
@ -171,10 +168,12 @@ clauselist_selectivity(Query *root,
|
||||
switch (oprrest)
|
||||
{
|
||||
case F_SCALARLTSEL:
|
||||
addRangeClause(&rqlist, clause, flag, true, s2);
|
||||
addRangeClause(&rqlist, clause,
|
||||
varonleft, true, s2);
|
||||
break;
|
||||
case F_SCALARGTSEL:
|
||||
addRangeClause(&rqlist, clause, flag, false, s2);
|
||||
addRangeClause(&rqlist, clause,
|
||||
varonleft, false, s2);
|
||||
break;
|
||||
default:
|
||||
/* Just merge the selectivity in generically */
|
||||
@ -220,7 +219,7 @@ clauselist_selectivity(Query *root,
|
||||
* No data available --- use a default estimate that
|
||||
* is small, but not real small.
|
||||
*/
|
||||
s2 = 0.01;
|
||||
s2 = 0.005;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -259,14 +258,13 @@ clauselist_selectivity(Query *root,
|
||||
*/
|
||||
static void
|
||||
addRangeClause(RangeQueryClause **rqlist, Node *clause,
|
||||
int flag, bool isLTsel, Selectivity s2)
|
||||
bool varonleft, bool isLTsel, Selectivity s2)
|
||||
{
|
||||
RangeQueryClause *rqelem;
|
||||
Node *var;
|
||||
bool is_lobound;
|
||||
|
||||
/* get_relattval sets flag&SEL_RIGHT if the var is on the LEFT. */
|
||||
if (flag & SEL_RIGHT)
|
||||
if (varonleft)
|
||||
{
|
||||
var = (Node *) get_leftop((Expr *) clause);
|
||||
is_lobound = !isLTsel; /* x < something is high bound */
|
||||
@ -405,12 +403,12 @@ clause_selectivity(Query *root,
|
||||
* is equivalent to the clause reln.attribute = 't', so we
|
||||
* compute the selectivity as if that is what we have.
|
||||
*/
|
||||
s1 = restriction_selectivity(F_EQSEL,
|
||||
s1 = restriction_selectivity(root,
|
||||
BooleanEqualOperator,
|
||||
rte->relid,
|
||||
var->varattno,
|
||||
BoolGetDatum(true),
|
||||
SEL_CONSTANT | SEL_RIGHT);
|
||||
makeList2(var,
|
||||
MAKEBOOLCONST(true,
|
||||
false)),
|
||||
varRelid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -486,57 +484,14 @@ clause_selectivity(Query *root,
|
||||
if (is_join_clause)
|
||||
{
|
||||
/* Estimate selectivity for a join clause. */
|
||||
RegProcedure oprjoin = get_oprjoin(opno);
|
||||
|
||||
/*
|
||||
* if the oprjoin procedure is missing for whatever reason,
|
||||
* use a selectivity of 0.5
|
||||
*/
|
||||
if (!oprjoin)
|
||||
s1 = (Selectivity) 0.5;
|
||||
else
|
||||
{
|
||||
int relid1,
|
||||
relid2;
|
||||
AttrNumber attno1,
|
||||
attno2;
|
||||
Oid reloid1,
|
||||
reloid2;
|
||||
|
||||
get_rels_atts(clause, &relid1, &attno1, &relid2, &attno2);
|
||||
reloid1 = relid1 ? getrelid(relid1, root->rtable) : InvalidOid;
|
||||
reloid2 = relid2 ? getrelid(relid2, root->rtable) : InvalidOid;
|
||||
s1 = join_selectivity(oprjoin, opno,
|
||||
reloid1, attno1,
|
||||
reloid2, attno2);
|
||||
}
|
||||
s1 = join_selectivity(root, opno,
|
||||
((Expr *) clause)->args);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Estimate selectivity for a restriction clause. */
|
||||
RegProcedure oprrest = get_oprrest(opno);
|
||||
|
||||
/*
|
||||
* if the oprrest procedure is missing for whatever reason,
|
||||
* use a selectivity of 0.5
|
||||
*/
|
||||
if (!oprrest)
|
||||
s1 = (Selectivity) 0.5;
|
||||
else
|
||||
{
|
||||
int relidx;
|
||||
AttrNumber attno;
|
||||
Datum constval;
|
||||
int flag;
|
||||
Oid reloid;
|
||||
|
||||
get_relattval(clause, varRelid,
|
||||
&relidx, &attno, &constval, &flag);
|
||||
reloid = relidx ? getrelid(relidx, root->rtable) : InvalidOid;
|
||||
s1 = restriction_selectivity(oprrest, opno,
|
||||
reloid, attno,
|
||||
constval, flag);
|
||||
}
|
||||
s1 = restriction_selectivity(root, opno,
|
||||
((Expr *) clause)->args, varRelid);
|
||||
}
|
||||
}
|
||||
else if (is_funcclause(clause))
|
||||
@ -555,7 +510,7 @@ clause_selectivity(Query *root,
|
||||
/*
|
||||
* Just for the moment! FIX ME! - vadim 02/04/98
|
||||
*/
|
||||
s1 = 1.0;
|
||||
s1 = (Selectivity) 0.5;
|
||||
}
|
||||
else if (IsA(clause, RelabelType))
|
||||
{
|
||||
|
@ -42,7 +42,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.73 2001/05/09 23:13:34 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.74 2001/05/20 20:28:18 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -773,7 +773,7 @@ estimate_hash_bucketsize(Query *root, Var *var)
|
||||
if (relid == InvalidOid)
|
||||
return 0.1;
|
||||
|
||||
rel = get_base_rel(root, var->varno);
|
||||
rel = find_base_rel(root, var->varno);
|
||||
|
||||
if (rel->tuples <= 0.0 || rel->rows <= 0.0)
|
||||
return 0.1; /* ensure we can divide below */
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.104 2001/03/23 04:49:53 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.105 2001/05/20 20:28:18 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -127,18 +127,15 @@ static Const *string_to_const(const char *str, Oid datatype);
|
||||
* consideration in nested-loop joins.
|
||||
*
|
||||
* 'rel' is the relation for which we want to generate index paths
|
||||
* 'indices' is a list of available indexes for 'rel'
|
||||
*/
|
||||
void
|
||||
create_index_paths(Query *root,
|
||||
RelOptInfo *rel,
|
||||
List *indices)
|
||||
create_index_paths(Query *root, RelOptInfo *rel)
|
||||
{
|
||||
List *restrictinfo_list = rel->baserestrictinfo;
|
||||
List *joininfo_list = rel->joininfo;
|
||||
List *ilist;
|
||||
|
||||
foreach(ilist, indices)
|
||||
foreach(ilist, rel->indexlist)
|
||||
{
|
||||
IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
|
||||
List *restrictclauses;
|
||||
@ -1435,10 +1432,10 @@ index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
|
||||
|
||||
/*
|
||||
* Note that we are making a pathnode for a single-scan indexscan;
|
||||
* therefore, both indexid and indexqual should be single-element
|
||||
* therefore, both indexinfo and indexqual should be single-element
|
||||
* lists.
|
||||
*/
|
||||
pathnode->indexid = makeListi1(index->indexoid);
|
||||
pathnode->indexinfo = makeList1(index);
|
||||
pathnode->indexqual = makeList1(indexquals);
|
||||
|
||||
/* We don't actually care what order the index scans in ... */
|
||||
@ -2030,7 +2027,6 @@ find_operator(const char *opname, Oid datatype)
|
||||
static Datum
|
||||
string_to_datum(const char *str, Oid datatype)
|
||||
{
|
||||
|
||||
/*
|
||||
* We cheat a little by assuming that textin() will do for bpchar and
|
||||
* varchar constants too...
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.52 2001/03/22 03:59:35 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.53 2001/05/20 20:28:18 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -332,7 +332,7 @@ make_rels_by_clauseless_joins(Query *root,
|
||||
|
||||
/*
|
||||
* make_jointree_rel
|
||||
* Find or build a RelOptInfojoin rel representing a specific
|
||||
* Find or build a RelOptInfo join rel representing a specific
|
||||
* jointree item. For JoinExprs, we only consider the construction
|
||||
* path that corresponds exactly to what the user wrote.
|
||||
*/
|
||||
@ -343,7 +343,7 @@ make_jointree_rel(Query *root, Node *jtnode)
|
||||
{
|
||||
int varno = ((RangeTblRef *) jtnode)->rtindex;
|
||||
|
||||
return get_base_rel(root, varno);
|
||||
return build_base_rel(root, varno);
|
||||
}
|
||||
else if (IsA(jtnode, FromExpr))
|
||||
{
|
||||
@ -402,7 +402,7 @@ make_join_rel(Query *root, RelOptInfo *rel1, RelOptInfo *rel2,
|
||||
* Find or build the join RelOptInfo, and compute the restrictlist
|
||||
* that goes with this particular joining.
|
||||
*/
|
||||
joinrel = get_join_rel(root, rel1, rel2, jointype, &restrictlist);
|
||||
joinrel = build_join_rel(root, rel1, rel2, jointype, &restrictlist);
|
||||
|
||||
/*
|
||||
* Consider paths using each rel as both outer and inner.
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.42 2001/01/24 19:42:58 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.43 2001/05/20 20:28:18 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -26,8 +26,8 @@ static void best_or_subclause_indices(Query *root, RelOptInfo *rel,
|
||||
IndexPath *pathnode);
|
||||
static void best_or_subclause_index(Query *root, RelOptInfo *rel,
|
||||
Expr *subclause, List *indices,
|
||||
IndexOptInfo **retIndexInfo,
|
||||
List **retIndexQual,
|
||||
Oid *retIndexid,
|
||||
Cost *retStartupCost,
|
||||
Cost *retTotalCost);
|
||||
|
||||
@ -122,14 +122,14 @@ create_or_index_paths(Query *root,
|
||||
* of an 'or' clause and the cost of scanning a relation using these
|
||||
* indices. The cost is the sum of the individual index costs, since
|
||||
* the executor will perform a scan for each subclause of the 'or'.
|
||||
* Returns a list of IndexOptInfo nodes, one per scan.
|
||||
*
|
||||
* This routine also creates the indexqual and indexid lists that will
|
||||
* be needed by the executor. The indexqual list has one entry for each
|
||||
* scan of the base rel, which is a sublist of indexqual conditions to
|
||||
* apply in that scan. The implicit semantics are AND across each sublist
|
||||
* of quals, and OR across the toplevel list (note that the executor
|
||||
* takes care not to return any single tuple more than once). The indexid
|
||||
* list gives the OID of the index to be used in each scan.
|
||||
* This routine also creates the indexqual list that will be needed by
|
||||
* the executor. The indexqual list has one entry for each scan of the base
|
||||
* rel, which is a sublist of indexqual conditions to apply in that scan.
|
||||
* The implicit semantics are AND across each sublist of quals, and OR across
|
||||
* the toplevel list (note that the executor takes care not to return any
|
||||
* single tuple more than once).
|
||||
*
|
||||
* 'rel' is the node of the relation on which the indexes are defined
|
||||
* 'subclauses' are the subclauses of the 'or' clause
|
||||
@ -138,9 +138,9 @@ create_or_index_paths(Query *root,
|
||||
* 'pathnode' is the IndexPath node being built.
|
||||
*
|
||||
* Results are returned by setting these fields of the passed pathnode:
|
||||
* 'indexinfo' gets a list of the index IndexOptInfo nodes, one per scan
|
||||
* 'indexqual' gets the constructed indexquals for the path (a list
|
||||
* of sublists of clauses, one sublist per scan of the base rel)
|
||||
* 'indexid' gets a list of the index OIDs for each scan of the rel
|
||||
* 'startup_cost' and 'total_cost' get the complete path costs.
|
||||
*
|
||||
* 'startup_cost' is the startup cost for the first index scan only;
|
||||
@ -161,28 +161,28 @@ best_or_subclause_indices(Query *root,
|
||||
{
|
||||
List *slist;
|
||||
|
||||
pathnode->indexinfo = NIL;
|
||||
pathnode->indexqual = NIL;
|
||||
pathnode->indexid = NIL;
|
||||
pathnode->path.startup_cost = 0;
|
||||
pathnode->path.total_cost = 0;
|
||||
|
||||
foreach(slist, subclauses)
|
||||
{
|
||||
Expr *subclause = lfirst(slist);
|
||||
IndexOptInfo *best_indexinfo;
|
||||
List *best_indexqual;
|
||||
Oid best_indexid;
|
||||
Cost best_startup_cost;
|
||||
Cost best_total_cost;
|
||||
|
||||
best_or_subclause_index(root, rel, subclause, lfirst(indices),
|
||||
&best_indexqual, &best_indexid,
|
||||
&best_indexinfo, &best_indexqual,
|
||||
&best_startup_cost, &best_total_cost);
|
||||
|
||||
Assert(best_indexid != InvalidOid);
|
||||
Assert(best_indexinfo != NULL);
|
||||
|
||||
pathnode->indexinfo = lappend(pathnode->indexinfo, best_indexinfo);
|
||||
pathnode->indexqual = lappend(pathnode->indexqual, best_indexqual);
|
||||
pathnode->indexid = lappendi(pathnode->indexid, best_indexid);
|
||||
if (slist == subclauses)/* first scan? */
|
||||
if (slist == subclauses) /* first scan? */
|
||||
pathnode->path.startup_cost = best_startup_cost;
|
||||
pathnode->path.total_cost += best_total_cost;
|
||||
|
||||
@ -199,8 +199,8 @@ best_or_subclause_indices(Query *root,
|
||||
* 'rel' is the node of the relation on which the index is defined
|
||||
* 'subclause' is the OR subclause being considered
|
||||
* 'indices' is a list of IndexOptInfo nodes that match the subclause
|
||||
* '*retIndexInfo' gets the IndexOptInfo of the best index
|
||||
* '*retIndexQual' gets a list of the indexqual conditions for the best index
|
||||
* '*retIndexid' gets the OID of the best index
|
||||
* '*retStartupCost' gets the startup cost of a scan with that index
|
||||
* '*retTotalCost' gets the total cost of a scan with that index
|
||||
*/
|
||||
@ -209,8 +209,8 @@ best_or_subclause_index(Query *root,
|
||||
RelOptInfo *rel,
|
||||
Expr *subclause,
|
||||
List *indices,
|
||||
IndexOptInfo **retIndexInfo, /* return value */
|
||||
List **retIndexQual, /* return value */
|
||||
Oid *retIndexid, /* return value */
|
||||
Cost *retStartupCost, /* return value */
|
||||
Cost *retTotalCost) /* return value */
|
||||
{
|
||||
@ -218,8 +218,8 @@ best_or_subclause_index(Query *root,
|
||||
List *ilist;
|
||||
|
||||
/* if we don't match anything, return zeros */
|
||||
*retIndexInfo = NULL;
|
||||
*retIndexQual = NIL;
|
||||
*retIndexid = InvalidOid;
|
||||
*retStartupCost = 0;
|
||||
*retTotalCost = 0;
|
||||
|
||||
@ -238,8 +238,8 @@ best_or_subclause_index(Query *root,
|
||||
|
||||
if (first_time || subclause_path.total_cost < *retTotalCost)
|
||||
{
|
||||
*retIndexInfo = index;
|
||||
*retIndexQual = indexqual;
|
||||
*retIndexid = index->indexoid;
|
||||
*retStartupCost = subclause_path.startup_cost;
|
||||
*retTotalCost = subclause_path.total_cost;
|
||||
first_time = false;
|
||||
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.105 2001/05/07 00:43:20 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.106 2001/05/20 20:28:18 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -18,7 +18,6 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "catalog/pg_index.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "nodes/nodeFuncs.h"
|
||||
#include "optimizer/clauses.h"
|
||||
@ -27,6 +26,7 @@
|
||||
#include "optimizer/planmain.h"
|
||||
#include "optimizer/restrictinfo.h"
|
||||
#include "optimizer/tlist.h"
|
||||
#include "optimizer/var.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/syscache.h"
|
||||
@ -56,11 +56,11 @@ static HashJoin *create_hashjoin_plan(HashPath *best_path, List *tlist,
|
||||
Plan *outer_plan, List *outer_tlist,
|
||||
Plan *inner_plan, List *inner_tlist);
|
||||
static List *fix_indxqual_references(List *indexquals, IndexPath *index_path);
|
||||
static List *fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
|
||||
Form_pg_index index);
|
||||
static List *fix_indxqual_sublist(List *indexqual, int baserelid,
|
||||
IndexOptInfo *index);
|
||||
static Node *fix_indxqual_operand(Node *node, int baserelid,
|
||||
Form_pg_index index,
|
||||
Oid *opclass);
|
||||
IndexOptInfo *index,
|
||||
Oid *opclass);
|
||||
static List *switch_outer(List *clauses);
|
||||
static void copy_path_costsize(Plan *dest, Path *src);
|
||||
static void copy_plan_costsize(Plan *dest, Plan *src);
|
||||
@ -365,7 +365,7 @@ create_seqscan_plan(Path *best_path, List *tlist, List *scan_clauses)
|
||||
* The indexqual of the path contains a sublist of implicitly-ANDed qual
|
||||
* conditions for each scan of the index(es); if there is more than one
|
||||
* scan then the retrieved tuple sets are ORed together. The indexqual
|
||||
* and indexid lists must have the same length, ie, the number of scans
|
||||
* and indexinfo lists must have the same length, ie, the number of scans
|
||||
* that will occur. Note it is possible for a qual condition sublist
|
||||
* to be empty --- then no index restrictions will be applied during that
|
||||
* scan.
|
||||
@ -380,9 +380,10 @@ create_indexscan_plan(Query *root,
|
||||
Index baserelid;
|
||||
List *qpqual;
|
||||
List *fixed_indxqual;
|
||||
List *ixid;
|
||||
List *indexids;
|
||||
List *ixinfo;
|
||||
IndexScan *scan_plan;
|
||||
bool lossy = false;
|
||||
bool lossy;
|
||||
|
||||
/* there should be exactly one base rel involved... */
|
||||
Assert(length(best_path->path.parent->relids) == 1);
|
||||
@ -390,25 +391,18 @@ create_indexscan_plan(Query *root,
|
||||
|
||||
baserelid = lfirsti(best_path->path.parent->relids);
|
||||
|
||||
/* check to see if any of the indices are lossy */
|
||||
foreach(ixid, best_path->indexid)
|
||||
/*
|
||||
* Build list of index OIDs, and check to see if any of the indices
|
||||
* are lossy.
|
||||
*/
|
||||
indexids = NIL;
|
||||
lossy = false;
|
||||
foreach(ixinfo, best_path->indexinfo)
|
||||
{
|
||||
HeapTuple indexTuple;
|
||||
Form_pg_index index;
|
||||
IndexOptInfo *index = (IndexOptInfo *) lfirst(ixinfo);
|
||||
|
||||
indexTuple = SearchSysCache(INDEXRELID,
|
||||
ObjectIdGetDatum(lfirsti(ixid)),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(indexTuple))
|
||||
elog(ERROR, "create_plan: index %u not found", lfirsti(ixid));
|
||||
index = (Form_pg_index) GETSTRUCT(indexTuple);
|
||||
if (index->indislossy)
|
||||
{
|
||||
lossy = true;
|
||||
ReleaseSysCache(indexTuple);
|
||||
break;
|
||||
}
|
||||
ReleaseSysCache(indexTuple);
|
||||
indexids = lappendi(indexids, index->indexoid);
|
||||
lossy |= index->lossy;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -471,7 +465,7 @@ create_indexscan_plan(Query *root,
|
||||
scan_plan = make_indexscan(tlist,
|
||||
qpqual,
|
||||
baserelid,
|
||||
best_path->indexid,
|
||||
indexids,
|
||||
fixed_indxqual,
|
||||
indxqual,
|
||||
best_path->indexscandir);
|
||||
@ -895,45 +889,19 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path)
|
||||
{
|
||||
List *fixed_quals = NIL;
|
||||
int baserelid = lfirsti(index_path->path.parent->relids);
|
||||
List *indexids = index_path->indexid;
|
||||
List *ixinfo = index_path->indexinfo;
|
||||
List *i;
|
||||
|
||||
foreach(i, indexquals)
|
||||
{
|
||||
List *indexqual = lfirst(i);
|
||||
Oid indexid = lfirsti(indexids);
|
||||
HeapTuple indexTuple;
|
||||
Oid relam;
|
||||
Form_pg_index index;
|
||||
|
||||
/* Get the relam from the index's pg_class entry */
|
||||
indexTuple = SearchSysCache(RELOID,
|
||||
ObjectIdGetDatum(indexid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(indexTuple))
|
||||
elog(ERROR, "fix_indxqual_references: index %u not found in pg_class",
|
||||
indexid);
|
||||
relam = ((Form_pg_class) GETSTRUCT(indexTuple))->relam;
|
||||
ReleaseSysCache(indexTuple);
|
||||
|
||||
/* Need the index's pg_index entry for other stuff */
|
||||
indexTuple = SearchSysCache(INDEXRELID,
|
||||
ObjectIdGetDatum(indexid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(indexTuple))
|
||||
elog(ERROR, "fix_indxqual_references: index %u not found in pg_index",
|
||||
indexid);
|
||||
index = (Form_pg_index) GETSTRUCT(indexTuple);
|
||||
IndexOptInfo *index = (IndexOptInfo *) lfirst(ixinfo);
|
||||
|
||||
fixed_quals = lappend(fixed_quals,
|
||||
fix_indxqual_sublist(indexqual,
|
||||
baserelid,
|
||||
relam,
|
||||
index));
|
||||
|
||||
ReleaseSysCache(indexTuple);
|
||||
|
||||
indexids = lnext(indexids);
|
||||
ixinfo = lnext(ixinfo);
|
||||
}
|
||||
return fixed_quals;
|
||||
}
|
||||
@ -946,8 +914,7 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path)
|
||||
* of the clause.) Also change the operator if necessary.
|
||||
*/
|
||||
static List *
|
||||
fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
|
||||
Form_pg_index index)
|
||||
fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index)
|
||||
{
|
||||
List *fixed_qual = NIL;
|
||||
List *i;
|
||||
@ -955,26 +922,14 @@ fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
|
||||
foreach(i, indexqual)
|
||||
{
|
||||
Expr *clause = (Expr *) lfirst(i);
|
||||
int relid;
|
||||
AttrNumber attno;
|
||||
Datum constval;
|
||||
int flag;
|
||||
Expr *newclause;
|
||||
List *leftvarnos;
|
||||
Oid opclass,
|
||||
newopno;
|
||||
|
||||
if (!is_opclause((Node *) clause) ||
|
||||
length(clause->args) != 2)
|
||||
if (!is_opclause((Node *) clause) || length(clause->args) != 2)
|
||||
elog(ERROR, "fix_indxqual_sublist: indexqual clause is not binary opclause");
|
||||
|
||||
/*
|
||||
* Which side is the indexkey on?
|
||||
*
|
||||
* get_relattval sets flag&SEL_RIGHT if the indexkey is on the LEFT.
|
||||
*/
|
||||
get_relattval((Node *) clause, baserelid,
|
||||
&relid, &attno, &constval, &flag);
|
||||
|
||||
/*
|
||||
* Make a copy that will become the fixed clause.
|
||||
*
|
||||
@ -984,9 +939,15 @@ fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
|
||||
*/
|
||||
newclause = (Expr *) copyObject((Node *) clause);
|
||||
|
||||
/* If the indexkey is on the right, commute the clause. */
|
||||
if ((flag & SEL_RIGHT) == 0)
|
||||
/*
|
||||
* Check to see if the indexkey is on the right; if so, commute
|
||||
* the clause. The indexkey should be the side that refers to
|
||||
* (only) the base relation.
|
||||
*/
|
||||
leftvarnos = pull_varnos((Node *) lfirst(newclause->args));
|
||||
if (length(leftvarnos) != 1 || lfirsti(leftvarnos) != baserelid)
|
||||
CommuteClause(newclause);
|
||||
freeList(leftvarnos);
|
||||
|
||||
/*
|
||||
* Now, determine which index attribute this is, change the
|
||||
@ -1002,7 +963,7 @@ fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
|
||||
* is merely binary-compatible with the index. This shouldn't
|
||||
* fail, since indxpath.c found it before...
|
||||
*/
|
||||
newopno = indexable_operator(newclause, opclass, relam, true);
|
||||
newopno = indexable_operator(newclause, opclass, index->relam, true);
|
||||
if (newopno == InvalidOid)
|
||||
elog(ERROR, "fix_indxqual_sublist: failed to find substitute op");
|
||||
((Oper *) newclause->oper)->opno = newopno;
|
||||
@ -1013,7 +974,7 @@ fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
|
||||
}
|
||||
|
||||
static Node *
|
||||
fix_indxqual_operand(Node *node, int baserelid, Form_pg_index index,
|
||||
fix_indxqual_operand(Node *node, int baserelid, IndexOptInfo *index,
|
||||
Oid *opclass)
|
||||
{
|
||||
|
||||
@ -1033,27 +994,29 @@ fix_indxqual_operand(Node *node, int baserelid, Form_pg_index index,
|
||||
if (IsA(node, Var))
|
||||
{
|
||||
/* If it's a var, find which index key position it occupies */
|
||||
Assert(index->indproc == InvalidOid);
|
||||
|
||||
if (((Var *) node)->varno == baserelid)
|
||||
{
|
||||
int varatt = ((Var *) node)->varattno;
|
||||
int pos;
|
||||
|
||||
for (pos = 0; pos < INDEX_MAX_KEYS; pos++)
|
||||
for (pos = 0; pos < index->nkeys; pos++)
|
||||
{
|
||||
if (index->indkey[pos] == varatt)
|
||||
if (index->indexkeys[pos] == varatt)
|
||||
{
|
||||
Node *newnode = copyObject(node);
|
||||
|
||||
((Var *) newnode)->varattno = pos + 1;
|
||||
/* return the correct opclass, too */
|
||||
*opclass = index->indclass[pos];
|
||||
*opclass = index->classlist[pos];
|
||||
return newnode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Oops, this Var isn't the indexkey!
|
||||
* Oops, this Var isn't an indexkey!
|
||||
*/
|
||||
elog(ERROR, "fix_indxqual_operand: var is not index attribute");
|
||||
}
|
||||
@ -1063,11 +1026,11 @@ fix_indxqual_operand(Node *node, int baserelid, Form_pg_index index,
|
||||
* Since we currently only support single-column functional indexes,
|
||||
* the returned varattno must be 1.
|
||||
*/
|
||||
Assert(index->indproc != InvalidOid);
|
||||
Assert(is_funcclause(node)); /* not a very thorough check, but easy */
|
||||
|
||||
Assert(is_funcclause(node));/* not a very thorough check, but easy */
|
||||
|
||||
/* indclass[0] is the only class of a functional index */
|
||||
*opclass = index->indclass[0];
|
||||
/* classlist[0] is the only class of a functional index */
|
||||
*opclass = index->classlist[0];
|
||||
|
||||
return (Node *) makeVar(baserelid, 1, exprType(node), -1, 0);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.61 2001/05/14 20:25:00 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.62 2001/05/20 20:28:19 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -73,8 +73,8 @@ build_base_rel_tlists(Query *root, List *tlist)
|
||||
/*
|
||||
* add_vars_to_targetlist
|
||||
* For each variable appearing in the list, add it to the relation's
|
||||
* targetlist if not already present. Rel nodes will also be created
|
||||
* if not already present.
|
||||
* targetlist if not already present. Corresponding base rel nodes
|
||||
* will be created if not already present.
|
||||
*/
|
||||
static void
|
||||
add_vars_to_targetlist(Query *root, List *vars)
|
||||
@ -84,7 +84,7 @@ add_vars_to_targetlist(Query *root, List *vars)
|
||||
foreach(temp, vars)
|
||||
{
|
||||
Var *var = (Var *) lfirst(temp);
|
||||
RelOptInfo *rel = get_base_rel(root, var->varno);
|
||||
RelOptInfo *rel = build_base_rel(root, var->varno);
|
||||
|
||||
add_var_to_tlist(rel, var);
|
||||
}
|
||||
@ -120,8 +120,8 @@ add_missing_rels_to_query(Query *root, Node *jtnode)
|
||||
{
|
||||
int varno = ((RangeTblRef *) jtnode)->rtindex;
|
||||
|
||||
/* This call to get_base_rel does the primary work... */
|
||||
RelOptInfo *rel = get_base_rel(root, varno);
|
||||
/* This call to build_base_rel does the primary work... */
|
||||
RelOptInfo *rel = build_base_rel(root, varno);
|
||||
|
||||
result = makeList1(rel);
|
||||
}
|
||||
@ -299,7 +299,7 @@ mark_baserels_for_outer_join(Query *root, Relids rels, Relids outerrels)
|
||||
foreach(relid, rels)
|
||||
{
|
||||
int relno = lfirsti(relid);
|
||||
RelOptInfo *rel = get_base_rel(root, relno);
|
||||
RelOptInfo *rel = build_base_rel(root, relno);
|
||||
|
||||
/*
|
||||
* Since we do this bottom-up, any outer-rels previously marked
|
||||
@ -422,7 +422,7 @@ distribute_qual_to_rels(Query *root, Node *clause,
|
||||
can_be_equijoin = true;
|
||||
foreach(relid, relids)
|
||||
{
|
||||
RelOptInfo *rel = get_base_rel(root, lfirsti(relid));
|
||||
RelOptInfo *rel = build_base_rel(root, lfirsti(relid));
|
||||
|
||||
if (rel->outerjoinset &&
|
||||
!is_subseti(rel->outerjoinset, relids))
|
||||
@ -454,12 +454,11 @@ distribute_qual_to_rels(Query *root, Node *clause,
|
||||
|
||||
if (length(relids) == 1)
|
||||
{
|
||||
|
||||
/*
|
||||
* There is only one relation participating in 'clause', so
|
||||
* 'clause' is a restriction clause for that relation.
|
||||
*/
|
||||
RelOptInfo *rel = get_base_rel(root, lfirsti(relids));
|
||||
RelOptInfo *rel = build_base_rel(root, lfirsti(relids));
|
||||
|
||||
rel->baserestrictinfo = lappend(rel->baserestrictinfo,
|
||||
restrictinfo);
|
||||
@ -564,7 +563,7 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
|
||||
* Find or make the joininfo node for this combination of rels,
|
||||
* and add the restrictinfo node to it.
|
||||
*/
|
||||
joininfo = find_joininfo_node(get_base_rel(root, cur_relid),
|
||||
joininfo = find_joininfo_node(build_base_rel(root, cur_relid),
|
||||
unjoined_relids);
|
||||
joininfo->jinfo_restrictinfo = lappend(joininfo->jinfo_restrictinfo,
|
||||
restrictinfo);
|
||||
@ -609,8 +608,11 @@ process_implied_equality(Query *root, Node *item1, Node *item2,
|
||||
* If both vars belong to same rel, we need to look at that rel's
|
||||
* baserestrictinfo list. If different rels, each will have a
|
||||
* joininfo node for the other, and we can scan either list.
|
||||
*
|
||||
* All baserel entries should already exist at this point, so use
|
||||
* find_base_rel not build_base_rel.
|
||||
*/
|
||||
rel1 = get_base_rel(root, irel1);
|
||||
rel1 = find_base_rel(root, irel1);
|
||||
if (irel1 == irel2)
|
||||
restrictlist = rel1->baserestrictinfo;
|
||||
else
|
||||
|
@ -14,7 +14,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.64 2001/03/22 03:59:37 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.65 2001/05/20 20:28:19 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -194,6 +194,7 @@ subplanner(Query *root,
|
||||
* construction.
|
||||
*/
|
||||
root->base_rel_list = NIL;
|
||||
root->other_rel_list = NIL;
|
||||
root->join_rel_list = NIL;
|
||||
root->equi_key_list = NIL;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.106 2001/05/07 00:43:21 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.107 2001/05/20 20:28:19 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -206,7 +206,8 @@ subquery_planner(Query *parse, double tuple_fraction)
|
||||
* grouping_planner.
|
||||
*/
|
||||
if (parse->resultRelation &&
|
||||
(lst = expand_inherted_rtentry(parse, parse->resultRelation)) != NIL)
|
||||
(lst = expand_inherted_rtentry(parse, parse->resultRelation, false))
|
||||
!= NIL)
|
||||
plan = inheritance_planner(parse, lst);
|
||||
else
|
||||
plan = grouping_planner(parse, tuple_fraction);
|
||||
|
@ -14,7 +14,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.63 2001/05/07 00:43:22 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.64 2001/05/20 20:28:19 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -515,6 +515,11 @@ find_all_inheritors(Oid parentrel)
|
||||
* whole inheritance set (parent and children).
|
||||
* If not, return NIL.
|
||||
*
|
||||
* When dup_parent is false, the initially given RT index is part of the
|
||||
* returned list (if any). When dup_parent is true, the given RT index
|
||||
* is *not* in the returned list; a duplicate RTE will be made for the
|
||||
* parent table.
|
||||
*
|
||||
* A childless table is never considered to be an inheritance set; therefore
|
||||
* the result will never be a one-element list. It'll be either empty
|
||||
* or have two or more elements.
|
||||
@ -525,7 +530,7 @@ find_all_inheritors(Oid parentrel)
|
||||
* for the case of an inherited UPDATE/DELETE target relation.
|
||||
*/
|
||||
List *
|
||||
expand_inherted_rtentry(Query *parse, Index rti)
|
||||
expand_inherted_rtentry(Query *parse, Index rti, bool dup_parent)
|
||||
{
|
||||
RangeTblEntry *rte = rt_fetch(rti, parse->rtable);
|
||||
Oid parentOID = rte->relid;
|
||||
@ -544,7 +549,6 @@ expand_inherted_rtentry(Query *parse, Index rti)
|
||||
return NIL;
|
||||
/* Scan for all members of inheritance set */
|
||||
inhOIDs = find_all_inheritors(parentOID);
|
||||
|
||||
/*
|
||||
* Check that there's at least one descendant, else treat as no-child
|
||||
* case. This could happen despite above has_subclass() check, if
|
||||
@ -553,15 +557,19 @@ expand_inherted_rtentry(Query *parse, Index rti)
|
||||
if (lnext(inhOIDs) == NIL)
|
||||
return NIL;
|
||||
/* OK, it's an inheritance set; expand it */
|
||||
inhRTIs = makeListi1(rti);
|
||||
if (dup_parent)
|
||||
inhRTIs = NIL;
|
||||
else
|
||||
inhRTIs = makeListi1(rti); /* include original RTE in result */
|
||||
|
||||
foreach(l, inhOIDs)
|
||||
{
|
||||
Oid childOID = (Oid) lfirsti(l);
|
||||
RangeTblEntry *childrte;
|
||||
Index childRTindex;
|
||||
|
||||
/* parent will be in the list too, so ignore it */
|
||||
if (childOID == parentOID)
|
||||
/* parent will be in the list too; skip it if not dup requested */
|
||||
if (childOID == parentOID && !dup_parent)
|
||||
continue;
|
||||
|
||||
/*
|
||||
@ -578,6 +586,7 @@ expand_inherted_rtentry(Query *parse, Index rti)
|
||||
|
||||
inhRTIs = lappendi(inhRTIs, childRTindex);
|
||||
}
|
||||
|
||||
return inhRTIs;
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.84 2001/03/27 17:12:34 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.85 2001/05/20 20:28:19 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -46,7 +46,6 @@ static bool pull_subplans_walker(Node *node, List **listptr);
|
||||
static bool check_subplans_for_ungrouped_vars_walker(Node *node,
|
||||
Query *context);
|
||||
static bool contain_noncachable_functions_walker(Node *node, void *context);
|
||||
static int is_single_func(Node *node);
|
||||
static Node *eval_const_expressions_mutator(Node *node, void *context);
|
||||
static Expr *simplify_op_or_func(Expr *expr, List *args);
|
||||
|
||||
@ -797,202 +796,6 @@ NumRelids(Node *clause)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_relattval
|
||||
* Extract information from a restriction or join clause for
|
||||
* selectivity estimation. The inputs are an expression
|
||||
* and a relation number (which can be 0 if we don't care which
|
||||
* relation is used; that'd normally be the case for restriction
|
||||
* clauses, where the caller already knows that only one relation
|
||||
* is referenced in the clause). The routine checks that the
|
||||
* expression is of the form (var op something) or (something op var)
|
||||
* where the var is an attribute of the specified relation, or
|
||||
* a function of a var of the specified relation. If so, it
|
||||
* returns the following info:
|
||||
* the found relation number (same as targetrelid unless that is 0)
|
||||
* the found var number (or InvalidAttrNumber if a function)
|
||||
* if the "something" is a constant, the value of the constant
|
||||
* flags indicating whether a constant was found, and on which side.
|
||||
* Default values are returned if the expression is too complicated,
|
||||
* specifically 0 for the relid and attno, 0 for the constant value.
|
||||
*
|
||||
* Note that negative attno values are *not* invalid, but represent
|
||||
* system attributes such as OID. It's sufficient to check for relid=0
|
||||
* to determine whether the routine succeeded.
|
||||
*/
|
||||
void
|
||||
get_relattval(Node *clause,
|
||||
int targetrelid,
|
||||
int *relid,
|
||||
AttrNumber *attno,
|
||||
Datum *constval,
|
||||
int *flag)
|
||||
{
|
||||
Var *left,
|
||||
*right,
|
||||
*other;
|
||||
int funcvarno;
|
||||
|
||||
/* Careful; the passed clause might not be a binary operator at all */
|
||||
|
||||
if (!is_opclause(clause))
|
||||
goto default_results;
|
||||
|
||||
left = get_leftop((Expr *) clause);
|
||||
right = get_rightop((Expr *) clause);
|
||||
|
||||
if (!right)
|
||||
goto default_results;
|
||||
|
||||
/* Ignore any binary-compatible relabeling */
|
||||
|
||||
if (IsA(left, RelabelType))
|
||||
left = (Var *) ((RelabelType *) left)->arg;
|
||||
if (IsA(right, RelabelType))
|
||||
right = (Var *) ((RelabelType *) right)->arg;
|
||||
|
||||
/* First look for the var or func */
|
||||
|
||||
if (IsA(left, Var) &&
|
||||
(targetrelid == 0 || targetrelid == left->varno))
|
||||
{
|
||||
*relid = left->varno;
|
||||
*attno = left->varattno;
|
||||
*flag = SEL_RIGHT;
|
||||
}
|
||||
else if (IsA(right, Var) &&
|
||||
(targetrelid == 0 || targetrelid == right->varno))
|
||||
{
|
||||
*relid = right->varno;
|
||||
*attno = right->varattno;
|
||||
*flag = 0;
|
||||
}
|
||||
else if ((funcvarno = is_single_func((Node *) left)) != 0 &&
|
||||
(targetrelid == 0 || targetrelid == funcvarno))
|
||||
{
|
||||
*relid = funcvarno;
|
||||
*attno = InvalidAttrNumber;
|
||||
*flag = SEL_RIGHT;
|
||||
}
|
||||
else if ((funcvarno = is_single_func((Node *) right)) != 0 &&
|
||||
(targetrelid == 0 || targetrelid == funcvarno))
|
||||
{
|
||||
*relid = funcvarno;
|
||||
*attno = InvalidAttrNumber;
|
||||
*flag = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Duh, it's too complicated for me... */
|
||||
default_results:
|
||||
*relid = 0;
|
||||
*attno = 0;
|
||||
*constval = 0;
|
||||
*flag = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* OK, we identified the var or func; now look at the other side */
|
||||
|
||||
other = (*flag == 0) ? left : right;
|
||||
|
||||
if (IsA(other, Const) &&
|
||||
!((Const *) other)->constisnull)
|
||||
{
|
||||
*constval = ((Const *) other)->constvalue;
|
||||
*flag |= SEL_CONSTANT;
|
||||
}
|
||||
else
|
||||
*constval = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* is_single_func
|
||||
* If the given expression is a function of a single relation,
|
||||
* return the relation number; else return 0
|
||||
*/
|
||||
static int
|
||||
is_single_func(Node *node)
|
||||
{
|
||||
if (is_funcclause(node))
|
||||
{
|
||||
List *varnos = pull_varnos(node);
|
||||
|
||||
if (length(varnos) == 1)
|
||||
{
|
||||
int funcvarno = lfirsti(varnos);
|
||||
|
||||
freeList(varnos);
|
||||
return funcvarno;
|
||||
}
|
||||
freeList(varnos);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_rels_atts
|
||||
*
|
||||
* Returns the info
|
||||
* ( relid1 attno1 relid2 attno2 )
|
||||
* for a joinclause.
|
||||
*
|
||||
* If the clause is not of the form (var op var) or if any of the vars
|
||||
* refer to nested attributes, then zeroes are returned.
|
||||
*/
|
||||
void
|
||||
get_rels_atts(Node *clause,
|
||||
int *relid1,
|
||||
AttrNumber *attno1,
|
||||
int *relid2,
|
||||
AttrNumber *attno2)
|
||||
{
|
||||
/* set default values */
|
||||
*relid1 = 0;
|
||||
*attno1 = 0;
|
||||
*relid2 = 0;
|
||||
*attno2 = 0;
|
||||
|
||||
if (is_opclause(clause))
|
||||
{
|
||||
Var *left = get_leftop((Expr *) clause);
|
||||
Var *right = get_rightop((Expr *) clause);
|
||||
|
||||
if (left && right)
|
||||
{
|
||||
int funcvarno;
|
||||
|
||||
/* Ignore any binary-compatible relabeling */
|
||||
if (IsA(left, RelabelType))
|
||||
left = (Var *) ((RelabelType *) left)->arg;
|
||||
if (IsA(right, RelabelType))
|
||||
right = (Var *) ((RelabelType *) right)->arg;
|
||||
|
||||
if (IsA(left, Var))
|
||||
{
|
||||
*relid1 = left->varno;
|
||||
*attno1 = left->varattno;
|
||||
}
|
||||
else if ((funcvarno = is_single_func((Node *) left)) != 0)
|
||||
{
|
||||
*relid1 = funcvarno;
|
||||
*attno1 = InvalidAttrNumber;
|
||||
}
|
||||
|
||||
if (IsA(right, Var))
|
||||
{
|
||||
*relid2 = right->varno;
|
||||
*attno2 = right->varattno;
|
||||
}
|
||||
else if ((funcvarno = is_single_func((Node *) right)) != 0)
|
||||
{
|
||||
*relid2 = funcvarno;
|
||||
*attno2 = InvalidAttrNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------
|
||||
* CommuteClause: commute a binary operator clause
|
||||
*
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.72 2001/05/07 00:43:22 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.73 2001/05/20 20:28:19 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -346,9 +346,9 @@ create_index_path(Query *root,
|
||||
|
||||
/*
|
||||
* We are making a pathnode for a single-scan indexscan; therefore,
|
||||
* both indexid and indexqual should be single-element lists.
|
||||
* both indexinfo and indexqual should be single-element lists.
|
||||
*/
|
||||
pathnode->indexid = makeListi1(index->indexoid);
|
||||
pathnode->indexinfo = makeList1(index);
|
||||
pathnode->indexqual = makeList1(indexquals);
|
||||
|
||||
pathnode->indexscandir = indexscandir;
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.65 2001/05/07 00:43:22 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.66 2001/05/20 20:28:19 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -23,9 +23,12 @@
|
||||
#include "catalog/pg_amop.h"
|
||||
#include "catalog/pg_inherits.h"
|
||||
#include "catalog/pg_index.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/plancat.h"
|
||||
#include "parser/parsetree.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/relcache.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "catalog/catalog.h"
|
||||
@ -33,7 +36,7 @@
|
||||
|
||||
|
||||
/*
|
||||
* relation_info -
|
||||
* get_relation_info -
|
||||
* Retrieves catalog information for a given relation.
|
||||
* Given the Oid of the relation, return the following info:
|
||||
* whether the relation has secondary indices
|
||||
@ -41,8 +44,8 @@
|
||||
* number of tuples
|
||||
*/
|
||||
void
|
||||
relation_info(Oid relationObjectId,
|
||||
bool *hasindex, long *pages, double *tuples)
|
||||
get_relation_info(Oid relationObjectId,
|
||||
bool *hasindex, long *pages, double *tuples)
|
||||
{
|
||||
HeapTuple relationTuple;
|
||||
Form_pg_class relation;
|
||||
@ -51,16 +54,19 @@ relation_info(Oid relationObjectId,
|
||||
ObjectIdGetDatum(relationObjectId),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(relationTuple))
|
||||
elog(ERROR, "relation_info: Relation %u not found",
|
||||
elog(ERROR, "get_relation_info: Relation %u not found",
|
||||
relationObjectId);
|
||||
relation = (Form_pg_class) GETSTRUCT(relationTuple);
|
||||
|
||||
if (IsIgnoringSystemIndexes() && IsSystemRelationName(NameStr(relation->relname)))
|
||||
if (IsIgnoringSystemIndexes() &&
|
||||
IsSystemRelationName(NameStr(relation->relname)))
|
||||
*hasindex = false;
|
||||
else
|
||||
*hasindex = (relation->relhasindex) ? true : false;
|
||||
*hasindex = relation->relhasindex;
|
||||
|
||||
*pages = relation->relpages;
|
||||
*tuples = relation->reltuples;
|
||||
|
||||
ReleaseSysCache(relationTuple);
|
||||
}
|
||||
|
||||
@ -110,8 +116,8 @@ find_secondary_indexes(Oid relationObjectId)
|
||||
info = makeNode(IndexOptInfo);
|
||||
|
||||
/*
|
||||
* Need to make these arrays large enough to be sure there is a
|
||||
* terminating 0 at the end of each one.
|
||||
* Need to make these arrays large enough to be sure there is
|
||||
* room for a terminating 0 at the end of each one.
|
||||
*/
|
||||
info->classlist = (Oid *) palloc(sizeof(Oid) * (INDEX_MAX_KEYS + 1));
|
||||
info->indexkeys = (int *) palloc(sizeof(int) * (INDEX_MAX_KEYS + 1));
|
||||
@ -131,14 +137,26 @@ find_secondary_indexes(Oid relationObjectId)
|
||||
}
|
||||
else
|
||||
info->indpred = NIL;
|
||||
info->unique = index->indisunique;
|
||||
info->lossy = index->indislossy;
|
||||
|
||||
for (i = 0; i < INDEX_MAX_KEYS; i++)
|
||||
info->indexkeys[i] = index->indkey[i];
|
||||
info->indexkeys[INDEX_MAX_KEYS] = 0;
|
||||
for (i = 0; i < INDEX_MAX_KEYS; i++)
|
||||
{
|
||||
if (index->indclass[i] == (Oid) 0)
|
||||
break;
|
||||
info->classlist[i] = index->indclass[i];
|
||||
info->classlist[INDEX_MAX_KEYS] = (Oid) 0;
|
||||
}
|
||||
info->classlist[i] = (Oid) 0;
|
||||
info->ncolumns = i;
|
||||
|
||||
for (i = 0; i < INDEX_MAX_KEYS; i++)
|
||||
{
|
||||
if (index->indkey[i] == 0)
|
||||
break;
|
||||
info->indexkeys[i] = index->indkey[i];
|
||||
}
|
||||
info->indexkeys[i] = 0;
|
||||
info->nkeys = i;
|
||||
|
||||
/* Extract info from the relation descriptor for the index */
|
||||
indexRelation = index_open(index->indexrelid);
|
||||
@ -156,7 +174,7 @@ find_secondary_indexes(Oid relationObjectId)
|
||||
MemSet(info->ordering, 0, sizeof(Oid) * (INDEX_MAX_KEYS + 1));
|
||||
if (amorderstrategy != 0)
|
||||
{
|
||||
for (i = 0; i < INDEX_MAX_KEYS && index->indclass[i]; i++)
|
||||
for (i = 0; i < info->ncolumns; i++)
|
||||
{
|
||||
HeapTuple amopTuple;
|
||||
Form_pg_amop amop;
|
||||
@ -193,30 +211,34 @@ find_secondary_indexes(Oid relationObjectId)
|
||||
/*
|
||||
* restriction_selectivity
|
||||
*
|
||||
* Returns the selectivity of a specified operator.
|
||||
* Returns the selectivity of a specified restriction operator clause.
|
||||
* This code executes registered procedures stored in the
|
||||
* operator relation, by calling the function manager.
|
||||
*
|
||||
* XXX The assumption in the selectivity procedures is that if the
|
||||
* relation OIDs or attribute numbers are 0, then the clause
|
||||
* isn't of the form (op var const).
|
||||
* varRelid is either 0 or a rangetable index. See clause_selectivity()
|
||||
* for details about its meaning.
|
||||
*/
|
||||
Selectivity
|
||||
restriction_selectivity(Oid functionObjectId,
|
||||
Oid operatorObjectId,
|
||||
Oid relationObjectId,
|
||||
AttrNumber attributeNumber,
|
||||
Datum constValue,
|
||||
int constFlag)
|
||||
restriction_selectivity(Query *root,
|
||||
Oid operator,
|
||||
List *args,
|
||||
int varRelid)
|
||||
{
|
||||
RegProcedure oprrest = get_oprrest(operator);
|
||||
float8 result;
|
||||
|
||||
result = DatumGetFloat8(OidFunctionCall5(functionObjectId,
|
||||
ObjectIdGetDatum(operatorObjectId),
|
||||
ObjectIdGetDatum(relationObjectId),
|
||||
Int16GetDatum(attributeNumber),
|
||||
constValue,
|
||||
Int32GetDatum(constFlag)));
|
||||
/*
|
||||
* if the oprrest procedure is missing for whatever reason,
|
||||
* use a selectivity of 0.5
|
||||
*/
|
||||
if (!oprrest)
|
||||
return (Selectivity) 0.5;
|
||||
|
||||
result = DatumGetFloat8(OidFunctionCall4(oprrest,
|
||||
PointerGetDatum(root),
|
||||
ObjectIdGetDatum(operator),
|
||||
PointerGetDatum(args),
|
||||
Int32GetDatum(varRelid)));
|
||||
|
||||
if (result < 0.0 || result > 1.0)
|
||||
elog(ERROR, "restriction_selectivity: bad value %f", result);
|
||||
@ -227,29 +249,29 @@ restriction_selectivity(Oid functionObjectId,
|
||||
/*
|
||||
* join_selectivity
|
||||
*
|
||||
* Returns the selectivity of an operator, given the join clause
|
||||
* information.
|
||||
*
|
||||
* XXX The assumption in the selectivity procedures is that if the
|
||||
* relation OIDs or attribute numbers are 0, then the clause
|
||||
* isn't of the form (op var var).
|
||||
* Returns the selectivity of a specified join operator clause.
|
||||
* This code executes registered procedures stored in the
|
||||
* operator relation, by calling the function manager.
|
||||
*/
|
||||
Selectivity
|
||||
join_selectivity(Oid functionObjectId,
|
||||
Oid operatorObjectId,
|
||||
Oid relationObjectId1,
|
||||
AttrNumber attributeNumber1,
|
||||
Oid relationObjectId2,
|
||||
AttrNumber attributeNumber2)
|
||||
join_selectivity(Query *root,
|
||||
Oid operator,
|
||||
List *args)
|
||||
{
|
||||
RegProcedure oprjoin = get_oprjoin(operator);
|
||||
float8 result;
|
||||
|
||||
result = DatumGetFloat8(OidFunctionCall5(functionObjectId,
|
||||
ObjectIdGetDatum(operatorObjectId),
|
||||
ObjectIdGetDatum(relationObjectId1),
|
||||
Int16GetDatum(attributeNumber1),
|
||||
ObjectIdGetDatum(relationObjectId2),
|
||||
Int16GetDatum(attributeNumber2)));
|
||||
/*
|
||||
* if the oprjoin procedure is missing for whatever reason,
|
||||
* use a selectivity of 0.5
|
||||
*/
|
||||
if (!oprjoin)
|
||||
return (Selectivity) 0.5;
|
||||
|
||||
result = DatumGetFloat8(OidFunctionCall3(oprjoin,
|
||||
PointerGetDatum(root),
|
||||
ObjectIdGetDatum(operator),
|
||||
PointerGetDatum(args)));
|
||||
|
||||
if (result < 0.0 || result > 1.0)
|
||||
elog(ERROR, "join_selectivity: bad value %f", result);
|
||||
@ -330,3 +352,36 @@ has_subclass(Oid relationId)
|
||||
ReleaseSysCache(tuple);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* has_unique_index
|
||||
*
|
||||
* Detect whether there is a unique index on the specified attribute
|
||||
* of the specified relation, thus allowing us to conclude that all
|
||||
* the (non-null) values of the attribute are distinct.
|
||||
*/
|
||||
bool
|
||||
has_unique_index(RelOptInfo *rel, AttrNumber attno)
|
||||
{
|
||||
List *ilist;
|
||||
|
||||
foreach(ilist, rel->indexlist)
|
||||
{
|
||||
IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
|
||||
|
||||
/*
|
||||
* Note: ignore functional, partial, or lossy indexes, since they
|
||||
* don't allow us to conclude that all attr values are distinct.
|
||||
* Also, a multicolumn unique index doesn't allow us to conclude
|
||||
* that just the specified attr is unique.
|
||||
*/
|
||||
if (index->unique &&
|
||||
index->nkeys == 1 &&
|
||||
index->indexkeys[0] == attno &&
|
||||
index->indproc == InvalidOid &&
|
||||
index->indpred == NIL &&
|
||||
!index->lossy)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.32 2001/02/16 00:03:08 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.33 2001/05/20 20:28:19 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -22,6 +22,7 @@
|
||||
#include "parser/parsetree.h"
|
||||
|
||||
|
||||
static RelOptInfo *make_base_rel(Query *root, int relid);
|
||||
static List *new_join_tlist(List *tlist, int first_resdomno);
|
||||
static List *build_joinrel_restrictlist(RelOptInfo *joinrel,
|
||||
RelOptInfo *outer_rel,
|
||||
@ -36,28 +37,35 @@ static void subbuild_joinrel_joinlist(RelOptInfo *joinrel,
|
||||
|
||||
|
||||
/*
|
||||
* get_base_rel
|
||||
* build_base_rel
|
||||
* Returns relation entry corresponding to 'relid', creating a new one
|
||||
* if necessary. This is for base relations.
|
||||
*/
|
||||
RelOptInfo *
|
||||
get_base_rel(Query *root, int relid)
|
||||
build_base_rel(Query *root, int relid)
|
||||
{
|
||||
List *baserels;
|
||||
List *rels;
|
||||
RelOptInfo *rel;
|
||||
|
||||
foreach(baserels, root->base_rel_list)
|
||||
/* Already made? */
|
||||
foreach(rels, root->base_rel_list)
|
||||
{
|
||||
rel = (RelOptInfo *) lfirst(baserels);
|
||||
rel = (RelOptInfo *) lfirst(rels);
|
||||
|
||||
/*
|
||||
* We know length(rel->relids) == 1 for all members of
|
||||
* base_rel_list
|
||||
*/
|
||||
/* length(rel->relids) == 1 for all members of base_rel_list */
|
||||
if (lfirsti(rel->relids) == relid)
|
||||
return rel;
|
||||
}
|
||||
|
||||
/* It should not exist as an "other" rel */
|
||||
foreach(rels, root->other_rel_list)
|
||||
{
|
||||
rel = (RelOptInfo *) lfirst(rels);
|
||||
|
||||
if (lfirsti(rel->relids) == relid)
|
||||
elog(ERROR, "build_base_rel: rel already exists as 'other' rel");
|
||||
}
|
||||
|
||||
/* No existing RelOptInfo for this base rel, so make a new one */
|
||||
rel = make_base_rel(root, relid);
|
||||
|
||||
@ -67,17 +75,53 @@ get_base_rel(Query *root, int relid)
|
||||
return rel;
|
||||
}
|
||||
|
||||
/*
|
||||
* build_other_rel
|
||||
* Returns relation entry corresponding to 'relid', creating a new one
|
||||
* if necessary. This is for 'other' relations, which are just like
|
||||
* base relations except that they live in a different list.
|
||||
*/
|
||||
RelOptInfo *
|
||||
build_other_rel(Query *root, int relid)
|
||||
{
|
||||
List *rels;
|
||||
RelOptInfo *rel;
|
||||
|
||||
/* Already made? */
|
||||
foreach(rels, root->other_rel_list)
|
||||
{
|
||||
rel = (RelOptInfo *) lfirst(rels);
|
||||
|
||||
/* length(rel->relids) == 1 for all members of other_rel_list */
|
||||
if (lfirsti(rel->relids) == relid)
|
||||
return rel;
|
||||
}
|
||||
|
||||
/* It should not exist as a base rel */
|
||||
foreach(rels, root->base_rel_list)
|
||||
{
|
||||
rel = (RelOptInfo *) lfirst(rels);
|
||||
|
||||
if (lfirsti(rel->relids) == relid)
|
||||
elog(ERROR, "build_other_rel: rel already exists as base rel");
|
||||
}
|
||||
|
||||
/* No existing RelOptInfo for this other rel, so make a new one */
|
||||
rel = make_base_rel(root, relid);
|
||||
|
||||
/* and add it to the list */
|
||||
root->other_rel_list = lcons(rel, root->other_rel_list);
|
||||
|
||||
return rel;
|
||||
}
|
||||
|
||||
/*
|
||||
* make_base_rel
|
||||
* Construct a base-relation RelOptInfo for the specified rangetable index.
|
||||
*
|
||||
* This is split out of get_base_rel so that inheritance-tree processing can
|
||||
* construct baserel nodes for child tables. We need a RelOptInfo so we can
|
||||
* plan a suitable access path for each child table, but we do NOT want to
|
||||
* enter the child nodes into base_rel_list. In most contexts, get_base_rel
|
||||
* should be called instead.
|
||||
* Common code for build_base_rel and build_other_rel.
|
||||
*/
|
||||
RelOptInfo *
|
||||
static RelOptInfo *
|
||||
make_base_rel(Query *root, int relid)
|
||||
{
|
||||
RelOptInfo *rel = makeNode(RelOptInfo);
|
||||
@ -92,7 +136,7 @@ make_base_rel(Query *root, int relid)
|
||||
rel->cheapest_total_path = NULL;
|
||||
rel->pruneable = true;
|
||||
rel->issubquery = false;
|
||||
rel->indexed = false;
|
||||
rel->indexlist = NIL;
|
||||
rel->pages = 0;
|
||||
rel->tuples = 0;
|
||||
rel->subplan = NULL;
|
||||
@ -108,8 +152,12 @@ make_base_rel(Query *root, int relid)
|
||||
if (relationObjectId != InvalidOid)
|
||||
{
|
||||
/* Plain relation --- retrieve statistics from the system catalogs */
|
||||
relation_info(relationObjectId,
|
||||
&rel->indexed, &rel->pages, &rel->tuples);
|
||||
bool indexed;
|
||||
|
||||
get_relation_info(relationObjectId,
|
||||
&indexed, &rel->pages, &rel->tuples);
|
||||
if (indexed)
|
||||
rel->indexlist = find_secondary_indexes(relationObjectId);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -120,13 +168,46 @@ make_base_rel(Query *root, int relid)
|
||||
return rel;
|
||||
}
|
||||
|
||||
/*
|
||||
* find_base_rel
|
||||
* Find a base or other relation entry, which must already exist
|
||||
* (since we'd have no idea which list to add it to).
|
||||
*/
|
||||
RelOptInfo *
|
||||
find_base_rel(Query *root, int relid)
|
||||
{
|
||||
List *rels;
|
||||
RelOptInfo *rel;
|
||||
|
||||
foreach(rels, root->base_rel_list)
|
||||
{
|
||||
rel = (RelOptInfo *) lfirst(rels);
|
||||
|
||||
/* length(rel->relids) == 1 for all members of base_rel_list */
|
||||
if (lfirsti(rel->relids) == relid)
|
||||
return rel;
|
||||
}
|
||||
|
||||
foreach(rels, root->other_rel_list)
|
||||
{
|
||||
rel = (RelOptInfo *) lfirst(rels);
|
||||
|
||||
if (lfirsti(rel->relids) == relid)
|
||||
return rel;
|
||||
}
|
||||
|
||||
elog(ERROR, "find_base_rel: no relation entry for relid %d", relid);
|
||||
|
||||
return NULL; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
/*
|
||||
* find_join_rel
|
||||
* Returns relation entry corresponding to 'relids' (a list of RT indexes),
|
||||
* or NULL if none exists. This is for join relations.
|
||||
*
|
||||
* Note: there is probably no good reason for this to be called from
|
||||
* anywhere except get_join_rel, but keep it as a separate routine
|
||||
* anywhere except build_join_rel, but keep it as a separate routine
|
||||
* just in case.
|
||||
*/
|
||||
static RelOptInfo *
|
||||
@ -146,7 +227,7 @@ find_join_rel(Query *root, Relids relids)
|
||||
}
|
||||
|
||||
/*
|
||||
* get_join_rel
|
||||
* build_join_rel
|
||||
* Returns relation entry corresponding to the union of two given rels,
|
||||
* creating a new relation entry if none already exists.
|
||||
*
|
||||
@ -161,11 +242,11 @@ find_join_rel(Query *root, Relids relids)
|
||||
* duplicated calculation of the restrictlist...
|
||||
*/
|
||||
RelOptInfo *
|
||||
get_join_rel(Query *root,
|
||||
RelOptInfo *outer_rel,
|
||||
RelOptInfo *inner_rel,
|
||||
JoinType jointype,
|
||||
List **restrictlist_ptr)
|
||||
build_join_rel(Query *root,
|
||||
RelOptInfo *outer_rel,
|
||||
RelOptInfo *inner_rel,
|
||||
JoinType jointype,
|
||||
List **restrictlist_ptr)
|
||||
{
|
||||
List *joinrelids;
|
||||
RelOptInfo *joinrel;
|
||||
@ -212,7 +293,7 @@ get_join_rel(Query *root,
|
||||
joinrel->cheapest_total_path = NULL;
|
||||
joinrel->pruneable = true;
|
||||
joinrel->issubquery = false;
|
||||
joinrel->indexed = false;
|
||||
joinrel->indexlist = NIL;
|
||||
joinrel->pages = 0;
|
||||
joinrel->tuples = 0;
|
||||
joinrel->subplan = NULL;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -37,7 +37,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: catversion.h,v 1.78 2001/05/15 03:49:35 momjian Exp $
|
||||
* $Id: catversion.h,v 1.79 2001/05/20 20:28:19 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -53,6 +53,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 200105145
|
||||
#define CATALOG_VERSION_NO 200105191
|
||||
|
||||
#endif
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pg_proc.h,v 1.185 2001/05/09 23:13:35 tgl Exp $
|
||||
* $Id: pg_proc.h,v 1.186 2001/05/20 20:28:19 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* The script catalog/genbki.sh reads this file and generates .bki
|
||||
@ -219,21 +219,21 @@ DESCR("btree cost estimator");
|
||||
|
||||
DATA(insert OID = 100 ( int8fac PGUID 12 f t t t 1 f 20 "20" 100 0 0 100 int8fac - ));
|
||||
DESCR("factorial");
|
||||
DATA(insert OID = 101 ( eqsel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 eqsel - ));
|
||||
DATA(insert OID = 101 ( eqsel PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100 eqsel - ));
|
||||
DESCR("restriction selectivity of = and related operators");
|
||||
DATA(insert OID = 102 ( neqsel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 neqsel - ));
|
||||
DATA(insert OID = 102 ( neqsel PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100 neqsel - ));
|
||||
DESCR("restriction selectivity of <> and related operators");
|
||||
DATA(insert OID = 103 ( scalarltsel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 scalarltsel - ));
|
||||
DATA(insert OID = 103 ( scalarltsel PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100 scalarltsel - ));
|
||||
DESCR("restriction selectivity of < and related operators on scalar datatypes");
|
||||
DATA(insert OID = 104 ( scalargtsel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 scalargtsel - ));
|
||||
DATA(insert OID = 104 ( scalargtsel PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100 scalargtsel - ));
|
||||
DESCR("restriction selectivity of > and related operators on scalar datatypes");
|
||||
DATA(insert OID = 105 ( eqjoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 eqjoinsel - ));
|
||||
DATA(insert OID = 105 ( eqjoinsel PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100 eqjoinsel - ));
|
||||
DESCR("join selectivity of = and related operators");
|
||||
DATA(insert OID = 106 ( neqjoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 neqjoinsel - ));
|
||||
DATA(insert OID = 106 ( neqjoinsel PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100 neqjoinsel - ));
|
||||
DESCR("join selectivity of <> and related operators");
|
||||
DATA(insert OID = 107 ( scalarltjoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 scalarltjoinsel - ));
|
||||
DATA(insert OID = 107 ( scalarltjoinsel PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100 scalarltjoinsel - ));
|
||||
DESCR("join selectivity of < and related operators on scalar datatypes");
|
||||
DATA(insert OID = 108 ( scalargtjoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 scalargtjoinsel - ));
|
||||
DATA(insert OID = 108 ( scalargtjoinsel PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100 scalargtjoinsel - ));
|
||||
DESCR("join selectivity of > and related operators on scalar datatypes");
|
||||
|
||||
DATA(insert OID = 112 ( text PGUID 12 f t t t 1 f 25 "23" 100 0 0 100 int4_text - ));
|
||||
@ -292,9 +292,9 @@ DATA(insert OID = 137 ( on_ppath PGUID 12 f t t t 2 f 16 "600 602" 100 0 0
|
||||
DESCR("contained in");
|
||||
DATA(insert OID = 138 ( box_center PGUID 12 f t t t 1 f 600 "603" 100 0 0 100 box_center - ));
|
||||
DESCR("center of");
|
||||
DATA(insert OID = 139 ( areasel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 areasel - ));
|
||||
DATA(insert OID = 139 ( areasel PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100 areasel - ));
|
||||
DESCR("restriction selectivity for area-comparison operators");
|
||||
DATA(insert OID = 140 ( areajoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 areajoinsel - ));
|
||||
DATA(insert OID = 140 ( areajoinsel PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100 areajoinsel - ));
|
||||
DESCR("join selectivity for area-comparison operators");
|
||||
DATA(insert OID = 141 ( int4mul PGUID 12 f t t t 2 f 23 "23 23" 100 0 0 100 int4mul - ));
|
||||
DESCR("multiply");
|
||||
@ -1562,13 +1562,13 @@ DESCR("current transaction time");
|
||||
|
||||
/* OIDS 1300 - 1399 */
|
||||
|
||||
DATA(insert OID = 1300 ( positionsel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 positionsel - ));
|
||||
DATA(insert OID = 1300 ( positionsel PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100 positionsel - ));
|
||||
DESCR("restriction selectivity for position-comparison operators");
|
||||
DATA(insert OID = 1301 ( positionjoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 positionjoinsel - ));
|
||||
DATA(insert OID = 1301 ( positionjoinsel PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100 positionjoinsel - ));
|
||||
DESCR("join selectivity for position-comparison operators");
|
||||
DATA(insert OID = 1302 ( contsel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 contsel - ));
|
||||
DATA(insert OID = 1302 ( contsel PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100 contsel - ));
|
||||
DESCR("restriction selectivity for containment comparison operators");
|
||||
DATA(insert OID = 1303 ( contjoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 contjoinsel - ));
|
||||
DATA(insert OID = 1303 ( contjoinsel PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100 contjoinsel - ));
|
||||
DESCR("join selectivity for containment comparison operators");
|
||||
|
||||
DATA(insert OID = 1304 ( overlaps PGUID 12 f t t f 4 f 16 "1184 1184 1184 1184" 100 0 0 100 overlaps_timestamp - ));
|
||||
@ -2465,37 +2465,37 @@ DATA(insert OID = 1799 ( oidout PGUID 12 f t t t 1 f 23 "0" 100 0 0 100 oid
|
||||
DESCR("(internal)");
|
||||
|
||||
/* Selectivity estimators for LIKE and related operators */
|
||||
DATA(insert OID = 1814 ( iclikesel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 iclikesel - ));
|
||||
DATA(insert OID = 1814 ( iclikesel PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100 iclikesel - ));
|
||||
DESCR("restriction selectivity of ILIKE");
|
||||
DATA(insert OID = 1815 ( icnlikesel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 icnlikesel - ));
|
||||
DATA(insert OID = 1815 ( icnlikesel PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100 icnlikesel - ));
|
||||
DESCR("restriction selectivity of NOT ILIKE");
|
||||
DATA(insert OID = 1816 ( iclikejoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 iclikejoinsel - ));
|
||||
DATA(insert OID = 1816 ( iclikejoinsel PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100 iclikejoinsel - ));
|
||||
DESCR("join selectivity of ILIKE");
|
||||
DATA(insert OID = 1817 ( icnlikejoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 icnlikejoinsel - ));
|
||||
DATA(insert OID = 1817 ( icnlikejoinsel PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100 icnlikejoinsel - ));
|
||||
DESCR("join selectivity of NOT ILIKE");
|
||||
DATA(insert OID = 1818 ( regexeqsel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 regexeqsel - ));
|
||||
DATA(insert OID = 1818 ( regexeqsel PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100 regexeqsel - ));
|
||||
DESCR("restriction selectivity of regex match");
|
||||
DATA(insert OID = 1819 ( likesel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 likesel - ));
|
||||
DATA(insert OID = 1819 ( likesel PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100 likesel - ));
|
||||
DESCR("restriction selectivity of LIKE");
|
||||
DATA(insert OID = 1820 ( icregexeqsel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 icregexeqsel - ));
|
||||
DATA(insert OID = 1820 ( icregexeqsel PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100 icregexeqsel - ));
|
||||
DESCR("restriction selectivity of case-insensitive regex match");
|
||||
DATA(insert OID = 1821 ( regexnesel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 regexnesel - ));
|
||||
DATA(insert OID = 1821 ( regexnesel PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100 regexnesel - ));
|
||||
DESCR("restriction selectivity of regex non-match");
|
||||
DATA(insert OID = 1822 ( nlikesel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 nlikesel - ));
|
||||
DATA(insert OID = 1822 ( nlikesel PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100 nlikesel - ));
|
||||
DESCR("restriction selectivity of NOT LIKE");
|
||||
DATA(insert OID = 1823 ( icregexnesel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 icregexnesel - ));
|
||||
DATA(insert OID = 1823 ( icregexnesel PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100 icregexnesel - ));
|
||||
DESCR("restriction selectivity of case-insensitive regex non-match");
|
||||
DATA(insert OID = 1824 ( regexeqjoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 regexeqjoinsel - ));
|
||||
DATA(insert OID = 1824 ( regexeqjoinsel PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100 regexeqjoinsel - ));
|
||||
DESCR("join selectivity of regex match");
|
||||
DATA(insert OID = 1825 ( likejoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 likejoinsel - ));
|
||||
DATA(insert OID = 1825 ( likejoinsel PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100 likejoinsel - ));
|
||||
DESCR("join selectivity of LIKE");
|
||||
DATA(insert OID = 1826 ( icregexeqjoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 icregexeqjoinsel - ));
|
||||
DATA(insert OID = 1826 ( icregexeqjoinsel PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100 icregexeqjoinsel - ));
|
||||
DESCR("join selectivity of case-insensitive regex match");
|
||||
DATA(insert OID = 1827 ( regexnejoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 regexnejoinsel - ));
|
||||
DATA(insert OID = 1827 ( regexnejoinsel PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100 regexnejoinsel - ));
|
||||
DESCR("join selectivity of regex non-match");
|
||||
DATA(insert OID = 1828 ( nlikejoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 nlikejoinsel - ));
|
||||
DATA(insert OID = 1828 ( nlikejoinsel PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100 nlikejoinsel - ));
|
||||
DESCR("join selectivity of NOT LIKE");
|
||||
DATA(insert OID = 1829 ( icregexnejoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 icregexnejoinsel - ));
|
||||
DATA(insert OID = 1829 ( icregexnejoinsel PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100 icregexnejoinsel - ));
|
||||
DESCR("join selectivity of case-insensitive regex non-match");
|
||||
|
||||
/* Aggregate-related functions */
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: parsenodes.h,v 1.127 2001/05/07 00:43:25 tgl Exp $
|
||||
* $Id: parsenodes.h,v 1.128 2001/05/20 20:28:20 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -83,6 +83,7 @@ typedef struct Query
|
||||
|
||||
/* internal to planner */
|
||||
List *base_rel_list; /* list of base-relation RelOptInfos */
|
||||
List *other_rel_list; /* list of other 1-relation RelOptInfos */
|
||||
List *join_rel_list; /* list of join-relation RelOptInfos */
|
||||
List *equi_key_list; /* list of lists of equijoined
|
||||
* PathKeyItems */
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: relation.h,v 1.55 2001/05/07 00:43:26 tgl Exp $
|
||||
* $Id: relation.h,v 1.56 2001/05/20 20:28:20 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -72,8 +72,8 @@ typedef enum CostSelector
|
||||
* * If the relation is a base relation it will have these fields set:
|
||||
*
|
||||
* issubquery - true if baserel is a subquery RTE rather than a table
|
||||
* indexed - true if the relation has secondary indices (always false
|
||||
* if it's a subquery)
|
||||
* indexlist - list of IndexOptInfo nodes for relation's indexes
|
||||
* (always NIL if it's a subquery)
|
||||
* pages - number of disk pages in relation (zero if a subquery)
|
||||
* tuples - number of tuples in relation (not considering restrictions)
|
||||
* subplan - plan for subquery (NULL if it's a plain table)
|
||||
@ -150,7 +150,7 @@ typedef struct RelOptInfo
|
||||
|
||||
/* information about a base rel (not set for join rels!) */
|
||||
bool issubquery;
|
||||
bool indexed;
|
||||
List *indexlist;
|
||||
long pages;
|
||||
double tuples;
|
||||
struct Plan *subplan;
|
||||
@ -178,20 +178,30 @@ typedef struct RelOptInfo
|
||||
* and indexes, but that created confusion without actually doing anything
|
||||
* useful. So now we have a separate IndexOptInfo struct for indexes.
|
||||
*
|
||||
* indexoid - OID of the index relation itself
|
||||
* pages - number of disk pages in index
|
||||
* tuples - number of index tuples in index
|
||||
* indexoid - OID of the index relation itself
|
||||
* pages - number of disk pages in index
|
||||
* tuples - number of index tuples in index
|
||||
* ncolumns - number of columns in index
|
||||
* nkeys - number of keys used by index (input columns)
|
||||
* classlist - List of PG_AMOPCLASS OIDs for the index
|
||||
* indexkeys - List of base-relation attribute numbers that are index keys
|
||||
* ordering - List of PG_OPERATOR OIDs which order the indexscan result
|
||||
* relam - the OID of the pg_am of the index
|
||||
* ordering - List of PG_OPERATOR OIDs which order the indexscan result
|
||||
* relam - the OID of the pg_am of the index
|
||||
* amcostestimate - OID of the relam's cost estimator
|
||||
* indproc - OID of the function if a functional index, else 0
|
||||
* indpred - index predicate if a partial index, else NULL
|
||||
* unique - true if index is unique
|
||||
* lossy - true if index is lossy (may return non-matching tuples)
|
||||
*
|
||||
* NB. the last element of the arrays classlist, indexkeys and ordering
|
||||
* is always 0.
|
||||
* ncolumns and nkeys are the same except for a functional index,
|
||||
* wherein ncolumns is 1 (the single function output) while nkeys
|
||||
* is the number of table columns passed to the function. classlist[]
|
||||
* and ordering[] have ncolumns entries, while indexkeys[] has nkeys
|
||||
* entries.
|
||||
*
|
||||
* Note: for historical reasons, the arrays classlist, indexkeys and
|
||||
* ordering have an extra entry that is always zero. Some code scans
|
||||
* until it sees a zero rather than looking at ncolumns or nkeys.
|
||||
*/
|
||||
|
||||
typedef struct IndexOptInfo
|
||||
@ -205,15 +215,18 @@ typedef struct IndexOptInfo
|
||||
double tuples;
|
||||
|
||||
/* index descriptor information */
|
||||
Oid *classlist; /* classes of AM operators */
|
||||
int *indexkeys; /* keys over which we're indexing */
|
||||
Oid *ordering; /* OIDs of sort operators for each key */
|
||||
int ncolumns; /* number of columns in index */
|
||||
int nkeys; /* number of keys used by index */
|
||||
Oid *classlist; /* AM operator classes for columns */
|
||||
int *indexkeys; /* column numbers of index's keys */
|
||||
Oid *ordering; /* OIDs of sort operators for each column */
|
||||
Oid relam; /* OID of the access method (in pg_am) */
|
||||
|
||||
RegProcedure amcostestimate;/* OID of the access method's cost fcn */
|
||||
|
||||
Oid indproc; /* if a functional index */
|
||||
List *indpred; /* if a partial index */
|
||||
bool unique; /* if a unique index */
|
||||
bool lossy; /* if a lossy index */
|
||||
} IndexOptInfo;
|
||||
|
||||
@ -275,7 +288,7 @@ typedef struct Path
|
||||
* tuples matched during any scan. (The executor is smart enough not to return
|
||||
* the same tuple more than once, even if it is matched in multiple scans.)
|
||||
*
|
||||
* 'indexid' is a list of index relation OIDs, one per scan to be performed.
|
||||
* 'indexinfo' is a list of IndexOptInfo nodes, one per scan to be performed.
|
||||
*
|
||||
* 'indexqual' is a list of index qualifications, also one per scan.
|
||||
* Each entry in 'indexqual' is a sublist of qualification expressions with
|
||||
@ -313,7 +326,7 @@ typedef struct Path
|
||||
typedef struct IndexPath
|
||||
{
|
||||
Path path;
|
||||
List *indexid;
|
||||
List *indexinfo;
|
||||
List *indexqual;
|
||||
ScanDirection indexscandir;
|
||||
Relids joinrelids; /* other rels mentioned in indexqual */
|
||||
@ -533,7 +546,7 @@ typedef struct RestrictInfo
|
||||
typedef struct JoinInfo
|
||||
{
|
||||
NodeTag type;
|
||||
Relids unjoined_relids;/* some rels not yet part of my RelOptInfo */
|
||||
Relids unjoined_relids; /* some rels not yet part of my RelOptInfo */
|
||||
List *jinfo_restrictinfo; /* relevant RestrictInfos */
|
||||
} JoinInfo;
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: clauses.h,v 1.43 2001/03/22 04:00:53 momjian Exp $
|
||||
* $Id: clauses.h,v 1.44 2001/05/20 20:28:20 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -16,14 +16,6 @@
|
||||
|
||||
#include "nodes/relation.h"
|
||||
|
||||
/*
|
||||
* Flag bits returned by get_relattval().
|
||||
* These are used in selectivity-estimation routines, too.
|
||||
*/
|
||||
#define SEL_CONSTANT 1 /* operator's non-var arg is a constant */
|
||||
#define SEL_RIGHT 2 /* operator's non-var arg is on the right */
|
||||
|
||||
|
||||
extern Expr *make_clause(int type, Node *oper, List *args);
|
||||
|
||||
extern bool is_opclause(Node *clause);
|
||||
@ -61,11 +53,6 @@ extern List *pull_constant_clauses(List *quals, List **constantQual);
|
||||
|
||||
extern void clause_get_relids_vars(Node *clause, Relids *relids, List **vars);
|
||||
extern int NumRelids(Node *clause);
|
||||
extern void get_relattval(Node *clause, int targetrelid,
|
||||
int *relid, AttrNumber *attno,
|
||||
Datum *constval, int *flag);
|
||||
extern void get_rels_atts(Node *clause, int *relid1,
|
||||
AttrNumber *attno1, int *relid2, AttrNumber *attno2);
|
||||
extern void CommuteClause(Expr *clause);
|
||||
|
||||
extern Node *eval_const_expressions(Node *node);
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pathnode.h,v 1.36 2001/05/07 00:43:26 tgl Exp $
|
||||
* $Id: pathnode.h,v 1.37 2001/05/20 20:28:20 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -64,9 +64,10 @@ extern HashPath *create_hashjoin_path(RelOptInfo *joinrel,
|
||||
/*
|
||||
* prototypes for relnode.c
|
||||
*/
|
||||
extern RelOptInfo *get_base_rel(Query *root, int relid);
|
||||
extern RelOptInfo *make_base_rel(Query *root, int relid);
|
||||
extern RelOptInfo *get_join_rel(Query *root,
|
||||
extern RelOptInfo *build_base_rel(Query *root, int relid);
|
||||
extern RelOptInfo *build_other_rel(Query *root, int relid);
|
||||
extern RelOptInfo *find_base_rel(Query *root, int relid);
|
||||
extern RelOptInfo *build_join_rel(Query *root,
|
||||
RelOptInfo *outer_rel,
|
||||
RelOptInfo *inner_rel,
|
||||
JoinType jointype,
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: paths.h,v 1.52 2001/03/22 04:00:54 momjian Exp $
|
||||
* $Id: paths.h,v 1.53 2001/05/20 20:28:20 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -35,7 +35,7 @@ extern RelOptInfo *make_fromexpr_rel(Query *root, FromExpr *from);
|
||||
* indxpath.c
|
||||
* routines to generate index paths
|
||||
*/
|
||||
extern void create_index_paths(Query *root, RelOptInfo *rel, List *indices);
|
||||
extern void create_index_paths(Query *root, RelOptInfo *rel);
|
||||
extern Oid indexable_operator(Expr *clause, Oid opclass, Oid relam,
|
||||
bool indexkey_on_left);
|
||||
extern List *extract_or_indexqual_conditions(RelOptInfo *rel,
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: plancat.h,v 1.22 2001/03/22 04:00:55 momjian Exp $
|
||||
* $Id: plancat.h,v 1.23 2001/05/20 20:28:20 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -17,7 +17,7 @@
|
||||
#include "nodes/relation.h"
|
||||
|
||||
|
||||
extern void relation_info(Oid relationObjectId,
|
||||
extern void get_relation_info(Oid relationObjectId,
|
||||
bool *hasindex, long *pages, double *tuples);
|
||||
|
||||
extern List *find_secondary_indexes(Oid relationObjectId);
|
||||
@ -26,15 +26,15 @@ extern List *find_inheritance_children(Oid inhparent);
|
||||
|
||||
extern bool has_subclass(Oid relationId);
|
||||
|
||||
extern Selectivity restriction_selectivity(Oid functionObjectId,
|
||||
Oid operatorObjectId,
|
||||
Oid relationObjectId,
|
||||
AttrNumber attributeNumber,
|
||||
Datum constValue,
|
||||
int constFlag);
|
||||
extern bool has_unique_index(RelOptInfo *rel, AttrNumber attno);
|
||||
|
||||
extern Selectivity join_selectivity(Oid functionObjectId, Oid operatorObjectId,
|
||||
Oid relationObjectId1, AttrNumber attributeNumber1,
|
||||
Oid relationObjectId2, AttrNumber attributeNumber2);
|
||||
extern Selectivity restriction_selectivity(Query *root,
|
||||
Oid operator,
|
||||
List *args,
|
||||
int varRelid);
|
||||
|
||||
extern Selectivity join_selectivity(Query *root,
|
||||
Oid operator,
|
||||
List *args);
|
||||
|
||||
#endif /* PLANCAT_H */
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: prep.h,v 1.27 2001/03/22 04:00:55 momjian Exp $
|
||||
* $Id: prep.h,v 1.28 2001/05/20 20:28:20 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -35,7 +35,9 @@ extern List *preprocess_targetlist(List *tlist, int command_type,
|
||||
extern Plan *plan_set_operations(Query *parse);
|
||||
|
||||
extern List *find_all_inheritors(Oid parentrel);
|
||||
extern List *expand_inherted_rtentry(Query *parse, Index rti);
|
||||
|
||||
extern List *expand_inherted_rtentry(Query *parse, Index rti,
|
||||
bool dup_parent);
|
||||
|
||||
extern Node *adjust_inherited_attrs(Node *node,
|
||||
Index old_rt_index, Oid old_relid,
|
||||
|
@ -418,16 +418,15 @@ WHERE p1.oprcode = p2.oid AND
|
||||
-- If oprrest is set, the operator must return boolean,
|
||||
-- and it must link to a proc with the right signature
|
||||
-- to be a restriction selectivity estimator.
|
||||
-- The proc signature we want is: float8 proc(oid, oid, int2, <any>, int4)
|
||||
-- The proc signature we want is: float8 proc(opaque, oid, opaque, int4)
|
||||
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
|
||||
FROM pg_operator AS p1, pg_proc AS p2
|
||||
WHERE p1.oprrest = p2.oid AND
|
||||
(p1.oprresult != 16 OR
|
||||
p2.prorettype != 701 OR p2.proretset OR
|
||||
p2.pronargs != 5 OR
|
||||
p2.proargtypes[0] != 26 OR p2.proargtypes[1] != 26 OR
|
||||
p2.proargtypes[2] != 21 OR p2.proargtypes[3] != 0 OR
|
||||
p2.proargtypes[4] != 23);
|
||||
p2.pronargs != 4 OR
|
||||
p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 26 OR
|
||||
p2.proargtypes[2] != 0 OR p2.proargtypes[3] != 23);
|
||||
oid | oprname | oid | proname
|
||||
-----+---------+-----+---------
|
||||
(0 rows)
|
||||
@ -435,16 +434,15 @@ WHERE p1.oprrest = p2.oid AND
|
||||
-- If oprjoin is set, the operator must be a binary boolean op,
|
||||
-- and it must link to a proc with the right signature
|
||||
-- to be a join selectivity estimator.
|
||||
-- The proc signature we want is: float8 proc(oid, oid, int2, oid, int2)
|
||||
-- The proc signature we want is: float8 proc(opaque, oid, opaque)
|
||||
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
|
||||
FROM pg_operator AS p1, pg_proc AS p2
|
||||
WHERE p1.oprjoin = p2.oid AND
|
||||
(p1.oprkind != 'b' OR p1.oprresult != 16 OR
|
||||
p2.prorettype != 701 OR p2.proretset OR
|
||||
p2.pronargs != 5 OR
|
||||
p2.proargtypes[0] != 26 OR p2.proargtypes[1] != 26 OR
|
||||
p2.proargtypes[2] != 21 OR p2.proargtypes[3] != 26 OR
|
||||
p2.proargtypes[4] != 21);
|
||||
p2.pronargs != 3 OR
|
||||
p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 26 OR
|
||||
p2.proargtypes[2] != 0);
|
||||
oid | oprname | oid | proname
|
||||
-----+---------+-----+---------
|
||||
(0 rows)
|
||||
|
@ -349,32 +349,30 @@ WHERE p1.oprcode = p2.oid AND
|
||||
-- If oprrest is set, the operator must return boolean,
|
||||
-- and it must link to a proc with the right signature
|
||||
-- to be a restriction selectivity estimator.
|
||||
-- The proc signature we want is: float8 proc(oid, oid, int2, <any>, int4)
|
||||
-- The proc signature we want is: float8 proc(opaque, oid, opaque, int4)
|
||||
|
||||
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
|
||||
FROM pg_operator AS p1, pg_proc AS p2
|
||||
WHERE p1.oprrest = p2.oid AND
|
||||
(p1.oprresult != 16 OR
|
||||
p2.prorettype != 701 OR p2.proretset OR
|
||||
p2.pronargs != 5 OR
|
||||
p2.proargtypes[0] != 26 OR p2.proargtypes[1] != 26 OR
|
||||
p2.proargtypes[2] != 21 OR p2.proargtypes[3] != 0 OR
|
||||
p2.proargtypes[4] != 23);
|
||||
p2.pronargs != 4 OR
|
||||
p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 26 OR
|
||||
p2.proargtypes[2] != 0 OR p2.proargtypes[3] != 23);
|
||||
|
||||
-- If oprjoin is set, the operator must be a binary boolean op,
|
||||
-- and it must link to a proc with the right signature
|
||||
-- to be a join selectivity estimator.
|
||||
-- The proc signature we want is: float8 proc(oid, oid, int2, oid, int2)
|
||||
-- The proc signature we want is: float8 proc(opaque, oid, opaque)
|
||||
|
||||
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
|
||||
FROM pg_operator AS p1, pg_proc AS p2
|
||||
WHERE p1.oprjoin = p2.oid AND
|
||||
(p1.oprkind != 'b' OR p1.oprresult != 16 OR
|
||||
p2.prorettype != 701 OR p2.proretset OR
|
||||
p2.pronargs != 5 OR
|
||||
p2.proargtypes[0] != 26 OR p2.proargtypes[1] != 26 OR
|
||||
p2.proargtypes[2] != 21 OR p2.proargtypes[3] != 26 OR
|
||||
p2.proargtypes[4] != 21);
|
||||
p2.pronargs != 3 OR
|
||||
p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 26 OR
|
||||
p2.proargtypes[2] != 0);
|
||||
|
||||
-- **************** pg_aggregate ****************
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user