diff --git a/doc/src/sgml/indexcost.sgml b/doc/src/sgml/indexcost.sgml index 9c781f97fc..482a2e199e 100644 --- a/doc/src/sgml/indexcost.sgml +++ b/doc/src/sgml/indexcost.sgml @@ -1,5 +1,5 @@ @@ -57,7 +57,8 @@ amcostestimate (Query *root, List *indexQuals, Cost *indexStartupCost, Cost *indexTotalCost, - Selectivity *indexSelectivity); + Selectivity *indexSelectivity, + double *indexCorrelation); The first four parameters are inputs: @@ -103,7 +104,7 @@ amcostestimate (Query *root, - The last three parameters are pass-by-reference outputs: + The last four parameters are pass-by-reference outputs: @@ -132,6 +133,16 @@ amcostestimate (Query *root, + + + *indexCorrelation + + + Set to correlation coefficient between index scan order and + underlying table's order + + + @@ -172,6 +183,13 @@ amcostestimate (Query *root, tuples that actually pass the given qual conditions. + + The indexCorrelation should be set to the correlation (ranging between + -1.0 and 1.0) between the index order and the table order. This is used + to adjust the estimate for the cost of fetching tuples from the main + table. + + Cost Estimation @@ -224,6 +242,14 @@ amcostestimate (Query *root, + + + + Estimate the index correlation. For a simple ordered index on a single + field, this can be retrieved from pg_statistic. If the correlation + is not known, the conservative estimate is zero (no correlation). + + @@ -237,8 +263,8 @@ amcostestimate (Query *root, prorettype = 0 -pronargs = 7 -proargtypes = 0 0 0 0 0 0 0 +pronargs = 8 +proargtypes = 0 0 0 0 0 0 0 0 We use zero ("opaque") for all the arguments since none of them have types diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 7dfe834b77..dddca240e9 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -31,17 +31,18 @@ * result by interpolating between startup_cost and total_cost. In detail: * actual_cost = startup_cost + * (total_cost - startup_cost) * tuples_to_fetch / path->parent->rows; - * Note that a relation's rows count (and, by extension, a Plan's plan_rows) - * are set without regard to any LIMIT, so that this equation works properly. - * (Also, these routines guarantee not to set the rows count to zero, so there - * will be no zero divide.) The LIMIT is applied as a separate Plan node. + * Note that a base relation's rows count (and, by extension, plan_rows for + * plan nodes below the LIMIT node) are set without regard to any LIMIT, so + * that this equation works properly. (Also, these routines guarantee not to + * set the rows count to zero, so there will be no zero divide.) The LIMIT is + * applied as a top-level plan node. * * * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.72 2001/05/09 00:35:09 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.73 2001/05/09 23:13:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -205,12 +206,18 @@ cost_index(Path *path, Query *root, { Cost startup_cost = 0; Cost run_cost = 0; - Cost cpu_per_tuple; Cost indexStartupCost; Cost indexTotalCost; Selectivity indexSelectivity; + double indexCorrelation, + csquared; + Cost min_IO_cost, + max_IO_cost; + Cost cpu_per_tuple; double tuples_fetched; double pages_fetched; + double T, + b; /* Should only be applied to base relations */ Assert(IsA(baserel, RelOptInfo) &&IsA(index, IndexOptInfo)); @@ -224,38 +231,52 @@ cost_index(Path *path, Query *root, * Call index-access-method-specific code to estimate the processing * cost for scanning the index, as well as the selectivity of the * index (ie, the fraction of main-table tuples we will have to - * retrieve). + * retrieve) and its correlation to the main-table tuple order. */ - OidFunctionCall7(index->amcostestimate, + OidFunctionCall8(index->amcostestimate, PointerGetDatum(root), PointerGetDatum(baserel), PointerGetDatum(index), PointerGetDatum(indexQuals), PointerGetDatum(&indexStartupCost), PointerGetDatum(&indexTotalCost), - PointerGetDatum(&indexSelectivity)); + PointerGetDatum(&indexSelectivity), + PointerGetDatum(&indexCorrelation)); /* all costs for touching index itself included here */ startup_cost += indexStartupCost; run_cost += indexTotalCost - indexStartupCost; - /* + /*---------- * Estimate number of main-table tuples and pages fetched. * - * If the number of tuples is much smaller than the number of pages in - * the relation, each tuple will cost a separate nonsequential fetch. - * If it is comparable or larger, then probably we will be able to - * avoid some fetches. We use a growth rate of log(#tuples/#pages + - * 1) --- probably totally bogus, but intuitively it gives the right - * shape of curve at least. + * When the index ordering is uncorrelated with the table ordering, + * we use an approximation proposed by Mackert and Lohman, "Index Scans + * Using a Finite LRU Buffer: A Validated I/O Model", ACM Transactions + * on Database Systems, Vol. 14, No. 3, September 1989, Pages 401-424. + * The Mackert and Lohman approximation is that the number of pages + * fetched is + * PF = + * min(2TNs/(2T+Ns), T) when T <= b + * 2TNs/(2T+Ns) when T > b and Ns <= 2Tb/(2T-b) + * b + (Ns - 2Tb/(2T-b))*(T-b)/T when T > b and Ns > 2Tb/(2T-b) + * where + * T = # pages in table + * N = # tuples in table + * s = selectivity = fraction of table to be scanned + * b = # buffer pages available (we include kernel space here) * - * XXX if the relation has recently been "clustered" using this index, - * then in fact the target tuples will be highly nonuniformly - * distributed, and we will be seriously overestimating the scan cost! - * Currently we have no way to know whether the relation has been - * clustered, nor how much it's been modified since the last - * clustering, so we ignore this effect. Would be nice to do better - * someday. + * When the index ordering is exactly correlated with the table ordering + * (just after a CLUSTER, for example), the number of pages fetched should + * be just sT. What's more, these will be sequential fetches, not the + * random fetches that occur in the uncorrelated case. So, depending on + * the extent of correlation, we should estimate the actual I/O cost + * somewhere between s * T * 1.0 and PF * random_cost. We currently + * interpolate linearly between these two endpoints based on the + * correlation squared (XXX is that appropriate?). + * + * In any case the number of tuples fetched is Ns. + *---------- */ tuples_fetched = indexSelectivity * baserel->tuples; @@ -263,24 +284,56 @@ cost_index(Path *path, Query *root, if (tuples_fetched < 1.0) tuples_fetched = 1.0; - if (baserel->pages > 0) - pages_fetched = ceil(baserel->pages * - log(tuples_fetched / baserel->pages + 1.0)); + /* This part is the Mackert and Lohman formula */ + + T = (baserel->pages > 1) ? (double) baserel->pages : 1.0; + b = (effective_cache_size > 1) ? effective_cache_size : 1.0; + + if (T <= b) + { + pages_fetched = + (2.0 * T * tuples_fetched) / (2.0 * T + tuples_fetched); + if (pages_fetched > T) + pages_fetched = T; + } else - pages_fetched = tuples_fetched; + { + double lim; + + lim = (2.0 * T * b) / (2.0 * T - b); + if (tuples_fetched <= lim) + { + pages_fetched = + (2.0 * T * tuples_fetched) / (2.0 * T + tuples_fetched); + } + else + { + pages_fetched = + b + (tuples_fetched - lim) * (T - b) / T; + } + } /* - * Now estimate one nonsequential access per page fetched, plus - * appropriate CPU costs per tuple. + * min_IO_cost corresponds to the perfectly correlated case (csquared=1), + * max_IO_cost to the perfectly uncorrelated case (csquared=0). Note + * that we just charge random_page_cost per page in the uncorrelated + * case, rather than using cost_nonsequential_access, since we've already + * accounted for caching effects by using the Mackert model. */ - - /* disk costs for main table */ - run_cost += pages_fetched * cost_nonsequential_access(baserel->pages); - - /* CPU costs */ - cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost; + min_IO_cost = ceil(indexSelectivity * T); + max_IO_cost = pages_fetched * random_page_cost; /* + * Now interpolate based on estimated index order correlation + * to get total disk I/O cost for main table accesses. + */ + csquared = indexCorrelation * indexCorrelation; + + run_cost += max_IO_cost + csquared * (min_IO_cost - max_IO_cost); + + /* + * Estimate CPU costs per tuple. + * * Normally the indexquals will be removed from the list of * restriction clauses that we have to evaluate as qpquals, so we * should subtract their costs from baserestrictcost. For a lossy @@ -290,6 +343,8 @@ cost_index(Path *path, Query *root, * Rather than work out exactly how much to subtract, we don't * subtract anything in that case either. */ + cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost; + if (!index->lossy && !is_injoin) cpu_per_tuple -= cost_qual_eval(indexQuals); diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index 30f02de5c7..9b620c80f5 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.31 2001/04/18 20:42:55 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.32 2001/05/09 23:13:35 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -28,8 +28,9 @@ typedef struct typedef struct { int varno; + int varattno; int sublevels_up; -} contain_whole_tuple_var_context; +} contain_var_reference_context; typedef struct { @@ -39,8 +40,8 @@ typedef struct static bool pull_varnos_walker(Node *node, pull_varnos_context *context); -static bool contain_whole_tuple_var_walker(Node *node, - contain_whole_tuple_var_context *context); +static bool contain_var_reference_walker(Node *node, + contain_var_reference_context *context); static bool contain_var_clause_walker(Node *node, void *context); static bool pull_var_clause_walker(Node *node, pull_var_clause_context *context); @@ -129,10 +130,10 @@ pull_varnos_walker(Node *node, pull_varnos_context *context) /* - * contain_whole_tuple_var + * contain_var_reference * - * Detect whether a parsetree contains any references to the whole - * tuple of a given rtable entry (ie, a Var with varattno = 0). + * Detect whether a parsetree contains any references to a specified + * attribute of a specified rtable entry. * * NOTE: this is used on not-yet-planned expressions. It may therefore find * bare SubLinks, and if so it needs to recurse into them to look for uplevel @@ -140,11 +141,12 @@ pull_varnos_walker(Node *node, pull_varnos_context *context) * SubPlan, we only need to look at the parameters passed to the subplan. */ bool -contain_whole_tuple_var(Node *node, int varno, int levelsup) +contain_var_reference(Node *node, int varno, int varattno, int levelsup) { - contain_whole_tuple_var_context context; + contain_var_reference_context context; context.varno = varno; + context.varattno = varattno; context.sublevels_up = levelsup; /* @@ -154,15 +156,15 @@ contain_whole_tuple_var(Node *node, int varno, int levelsup) */ if (node && IsA(node, Query)) return query_tree_walker((Query *) node, - contain_whole_tuple_var_walker, + contain_var_reference_walker, (void *) &context, true); else - return contain_whole_tuple_var_walker(node, &context); + return contain_var_reference_walker(node, &context); } static bool -contain_whole_tuple_var_walker(Node *node, - contain_whole_tuple_var_context *context) +contain_var_reference_walker(Node *node, + contain_var_reference_context *context) { if (node == NULL) return false; @@ -171,8 +173,8 @@ contain_whole_tuple_var_walker(Node *node, Var *var = (Var *) node; if (var->varno == context->varno && - var->varlevelsup == context->sublevels_up && - var->varattno == InvalidAttrNumber) + var->varattno == context->varattno && + var->varlevelsup == context->sublevels_up) return true; return false; } @@ -187,11 +189,11 @@ contain_whole_tuple_var_walker(Node *node, */ Expr *expr = (Expr *) node; - if (contain_whole_tuple_var_walker((Node *) ((SubPlan *) expr->oper)->sublink->oper, - context)) + if (contain_var_reference_walker((Node *) ((SubPlan *) expr->oper)->sublink->oper, + context)) return true; - if (contain_whole_tuple_var_walker((Node *) expr->args, - context)) + if (contain_var_reference_walker((Node *) expr->args, + context)) return true; return false; } @@ -202,16 +204,29 @@ contain_whole_tuple_var_walker(Node *node, context->sublevels_up++; result = query_tree_walker((Query *) node, - contain_whole_tuple_var_walker, + contain_var_reference_walker, (void *) context, true); context->sublevels_up--; return result; } - return expression_tree_walker(node, contain_whole_tuple_var_walker, + return expression_tree_walker(node, contain_var_reference_walker, (void *) context); } +/* + * contain_whole_tuple_var + * + * Detect whether a parsetree contains any references to the whole + * tuple of a given rtable entry (ie, a Var with varattno = 0). + */ +bool +contain_whole_tuple_var(Node *node, int varno, int levelsup) +{ + return contain_var_reference(node, varno, InvalidAttrNumber, levelsup); +} + + /* * contain_var_clause * Recursively scan a clause to discover whether it contains any Var nodes diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 41ba82db7b..d7633dc47d 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.88 2001/05/07 00:43:23 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.89 2001/05/09 23:13:35 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -39,6 +39,7 @@ #include "optimizer/cost.h" #include "parser/parse_func.h" #include "parser/parse_oper.h" +#include "parser/parsetree.h" #include "utils/builtins.h" #include "utils/date.h" #include "utils/int8.h" @@ -818,7 +819,6 @@ eqjoinsel(PG_FUNCTION_ARGS) { #ifdef NOT_USED /* see neqjoinsel() before removing me! */ Oid opid = PG_GETARG_OID(0); - #endif Oid relid1 = PG_GETARG_OID(1); AttrNumber attno1 = PG_GETARG_INT16(2); @@ -2230,16 +2230,14 @@ string_to_datum(const char *str, Oid datatype) *------------------------------------------------------------------------- */ -static Datum -genericcostestimate(PG_FUNCTION_ARGS) +static void +genericcostestimate(Query *root, RelOptInfo *rel, + IndexOptInfo *index, List *indexQuals, + Cost *indexStartupCost, + Cost *indexTotalCost, + Selectivity *indexSelectivity, + double *indexCorrelation) { - Query *root = (Query *) PG_GETARG_POINTER(0); - RelOptInfo *rel = (RelOptInfo *) PG_GETARG_POINTER(1); - IndexOptInfo *index = (IndexOptInfo *) PG_GETARG_POINTER(2); - List *indexQuals = (List *) PG_GETARG_POINTER(3); - Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(4); - Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(5); - Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(6); double numIndexTuples; double numIndexPages; @@ -2275,33 +2273,134 @@ genericcostestimate(PG_FUNCTION_ARGS) *indexTotalCost = numIndexPages + (cpu_index_tuple_cost + cost_qual_eval(indexQuals)) * numIndexTuples; - PG_RETURN_VOID(); + /* + * Generic assumption about index correlation: there isn't any. + */ + *indexCorrelation = 0.0; } -/* - * For first cut, just use generic function for all index types. - */ Datum btcostestimate(PG_FUNCTION_ARGS) { - return genericcostestimate(fcinfo); + Query *root = (Query *) PG_GETARG_POINTER(0); + RelOptInfo *rel = (RelOptInfo *) PG_GETARG_POINTER(1); + IndexOptInfo *index = (IndexOptInfo *) PG_GETARG_POINTER(2); + List *indexQuals = (List *) PG_GETARG_POINTER(3); + Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(4); + Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(5); + Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(6); + double *indexCorrelation = (double *) PG_GETARG_POINTER(7); + + genericcostestimate(root, rel, index, indexQuals, + indexStartupCost, indexTotalCost, + indexSelectivity, indexCorrelation); + + /* + * If it's a functional index, leave the default zero-correlation + * estimate in place. If not, and if we can get an estimate for + * the first variable's ordering correlation C from pg_statistic, + * estimate the index correlation as C / number-of-columns. + * (The idea here is that multiple columns dilute the importance + * of the first column's ordering, but don't negate it entirely.) + */ + if (index->indproc == InvalidOid) + { + Oid relid; + HeapTuple tuple; + + relid = getrelid(lfirsti(rel->relids), root->rtable); + Assert(relid != InvalidOid); + tuple = SearchSysCache(STATRELATT, + ObjectIdGetDatum(relid), + Int16GetDatum(index->indexkeys[0]), + 0, 0); + if (HeapTupleIsValid(tuple)) + { + Oid typid; + int32 typmod; + float4 *numbers; + int nnumbers; + + get_atttypetypmod(relid, index->indexkeys[0], + &typid, &typmod); + if (get_attstatsslot(tuple, typid, typmod, + STATISTIC_KIND_CORRELATION, + index->ordering[0], + NULL, NULL, &numbers, &nnumbers)) + { + double varCorrelation; + int nKeys; + + Assert(nnumbers == 1); + varCorrelation = numbers[0]; + for (nKeys = 1; index->indexkeys[nKeys] != 0; nKeys++) + /*skip*/; + + *indexCorrelation = varCorrelation / nKeys; + + free_attstatsslot(typid, NULL, 0, numbers, nnumbers); + } + ReleaseSysCache(tuple); + } + } + + PG_RETURN_VOID(); } Datum rtcostestimate(PG_FUNCTION_ARGS) { - return genericcostestimate(fcinfo); + Query *root = (Query *) PG_GETARG_POINTER(0); + RelOptInfo *rel = (RelOptInfo *) PG_GETARG_POINTER(1); + IndexOptInfo *index = (IndexOptInfo *) PG_GETARG_POINTER(2); + List *indexQuals = (List *) PG_GETARG_POINTER(3); + Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(4); + Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(5); + Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(6); + double *indexCorrelation = (double *) PG_GETARG_POINTER(7); + + genericcostestimate(root, rel, index, indexQuals, + indexStartupCost, indexTotalCost, + indexSelectivity, indexCorrelation); + + PG_RETURN_VOID(); } Datum hashcostestimate(PG_FUNCTION_ARGS) { - return genericcostestimate(fcinfo); + Query *root = (Query *) PG_GETARG_POINTER(0); + RelOptInfo *rel = (RelOptInfo *) PG_GETARG_POINTER(1); + IndexOptInfo *index = (IndexOptInfo *) PG_GETARG_POINTER(2); + List *indexQuals = (List *) PG_GETARG_POINTER(3); + Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(4); + Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(5); + Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(6); + double *indexCorrelation = (double *) PG_GETARG_POINTER(7); + + genericcostestimate(root, rel, index, indexQuals, + indexStartupCost, indexTotalCost, + indexSelectivity, indexCorrelation); + + PG_RETURN_VOID(); } Datum gistcostestimate(PG_FUNCTION_ARGS) { - return genericcostestimate(fcinfo); + Query *root = (Query *) PG_GETARG_POINTER(0); + RelOptInfo *rel = (RelOptInfo *) PG_GETARG_POINTER(1); + IndexOptInfo *index = (IndexOptInfo *) PG_GETARG_POINTER(2); + List *indexQuals = (List *) PG_GETARG_POINTER(3); + Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(4); + Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(5); + Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(6); + double *indexCorrelation = (double *) PG_GETARG_POINTER(7); + + genericcostestimate(root, rel, index, indexQuals, + indexStartupCost, indexTotalCost, + indexSelectivity, indexCorrelation); + + PG_RETURN_VOID(); } diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index ee15a940cc..573c21afd8 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.54 2001/05/09 00:35:09 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.55 2001/05/09 23:13:35 tgl Exp $ * * NOTES * Eventually, the index information should go through here, too. @@ -185,6 +185,36 @@ get_atttypmod(Oid relid, AttrNumber attnum) return -1; } +/* + * get_atttypetypmod + * + * A two-fer: given the relation id and the attribute number, + * fetch both type OID and atttypmod in a single cache lookup. + * + * Unlike the otherwise-similar get_atttype/get_atttypmod, this routine + * raises an error if it can't obtain the information. + */ +void +get_atttypetypmod(Oid relid, AttrNumber attnum, + Oid *typid, int32 *typmod) +{ + HeapTuple tp; + Form_pg_attribute att_tup; + + tp = SearchSysCache(ATTNUM, + ObjectIdGetDatum(relid), + Int16GetDatum(attnum), + 0, 0); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for relation %u attribute %d", + relid, attnum); + att_tup = (Form_pg_attribute) GETSTRUCT(tp); + + *typid = att_tup->atttypid; + *typmod = att_tup->atttypmod; + ReleaseSysCache(tp); +} + /* ---------- INDEX CACHE ---------- */ /* watch this space... diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index d03d472043..7d7acf96f7 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.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: pg_proc.h,v 1.184 2001/03/22 04:00:39 momjian Exp $ + * $Id: pg_proc.h,v 1.185 2001/05/09 23:13:35 tgl Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -210,9 +210,9 @@ DESCR("not equal"); DATA(insert OID = 89 ( version PGUID 12 f t f t 0 f 25 "" 100 0 0 100 pgsql_version - )); DESCR("PostgreSQL version string"); -DATA(insert OID = 1265 ( rtcostestimate PGUID 12 f t f t 7 f 0 "0 0 0 0 0 0 0" 100 0 0 100 rtcostestimate - )); +DATA(insert OID = 1265 ( rtcostestimate PGUID 12 f t f t 8 f 0 "0 0 0 0 0 0 0 0" 100 0 0 100 rtcostestimate - )); DESCR("r-tree cost estimator"); -DATA(insert OID = 1268 ( btcostestimate PGUID 12 f t f t 7 f 0 "0 0 0 0 0 0 0" 100 0 0 100 btcostestimate - )); +DATA(insert OID = 1268 ( btcostestimate PGUID 12 f t f t 8 f 0 "0 0 0 0 0 0 0 0" 100 0 0 100 btcostestimate - )); DESCR("btree cost estimator"); /* OIDS 100 - 199 */ @@ -789,7 +789,7 @@ DESCR("convert name to char()"); DATA(insert OID = 409 ( name PGUID 12 f t t t 1 f 19 "1042" 100 0 0 100 bpchar_name - )); DESCR("convert char() to name"); -DATA(insert OID = 438 ( hashcostestimate PGUID 12 f t f t 7 f 0 "0 0 0 0 0 0 0" 100 0 0 100 hashcostestimate - )); +DATA(insert OID = 438 ( hashcostestimate PGUID 12 f t f t 8 f 0 "0 0 0 0 0 0 0 0" 100 0 0 100 hashcostestimate - )); DESCR("hash index cost estimator"); DATA(insert OID = 440 ( hashgettuple PGUID 12 f t f t 2 f 23 "0 0" 100 0 0 100 hashgettuple - )); @@ -1014,7 +1014,7 @@ DESCR("larger of two"); DATA(insert OID = 771 ( int2smaller PGUID 12 f t t t 2 f 21 "21 21" 100 0 0 100 int2smaller - )); DESCR("smaller of two"); -DATA(insert OID = 772 ( gistcostestimate PGUID 12 f t f t 7 f 0 "0 0 0 0 0 0 0" 100 0 0 100 gistcostestimate - )); +DATA(insert OID = 772 ( gistcostestimate PGUID 12 f t f t 8 f 0 "0 0 0 0 0 0 0 0" 100 0 0 100 gistcostestimate - )); DESCR("gist cost estimator"); DATA(insert OID = 774 ( gistgettuple PGUID 12 f t f t 2 f 23 "0 0" 100 0 0 100 gistgettuple - )); DESCR("gist(internal)"); diff --git a/src/include/optimizer/var.h b/src/include/optimizer/var.h index 45048133eb..4cad677c7c 100644 --- a/src/include/optimizer/var.h +++ b/src/include/optimizer/var.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: var.h,v 1.13 2001/04/18 20:42:55 tgl Exp $ + * $Id: var.h,v 1.14 2001/05/09 23:13:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,6 +17,8 @@ #include "nodes/primnodes.h" extern List *pull_varnos(Node *node); +extern bool contain_var_reference(Node *node, int varno, int varattno, + int levelsup); extern bool contain_whole_tuple_var(Node *node, int varno, int levelsup); extern bool contain_var_clause(Node *node); extern List *pull_var_clause(Node *node, bool includeUpperVars); diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index 3f18a4aea6..719f68a873 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: lsyscache.h,v 1.32 2001/05/09 00:35:09 tgl Exp $ + * $Id: lsyscache.h,v 1.33 2001/05/09 23:13:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,8 @@ extern AttrNumber get_attnum(Oid relid, char *attname); extern Oid get_atttype(Oid relid, AttrNumber attnum); extern bool get_attisset(Oid relid, char *attname); extern int32 get_atttypmod(Oid relid, AttrNumber attnum); +extern void get_atttypetypmod(Oid relid, AttrNumber attnum, + Oid *typid, int32 *typmod); extern RegProcedure get_opcode(Oid opno); extern char *get_opname(Oid opno); extern bool op_mergejoinable(Oid opno, Oid ltype, Oid rtype,