diff --git a/contrib/bloom/blutils.c b/contrib/bloom/blutils.c index 6836129c90..a29330afcd 100644 --- a/contrib/bloom/blutils.c +++ b/contrib/bloom/blutils.c @@ -137,6 +137,7 @@ blhandler(PG_FUNCTION_ARGS) amroutine->amvacuumcleanup = blvacuumcleanup; amroutine->amcanreturn = NULL; amroutine->amcostestimate = blcostestimate; + amroutine->amgettreeheight = NULL; amroutine->amoptions = bloptions; amroutine->amproperty = NULL; amroutine->ambuildphasename = NULL; diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml index e3c1539a1e..dc7d14b60d 100644 --- a/doc/src/sgml/indexam.sgml +++ b/doc/src/sgml/indexam.sgml @@ -146,6 +146,7 @@ typedef struct IndexAmRoutine amvacuumcleanup_function amvacuumcleanup; amcanreturn_function amcanreturn; /* can be NULL */ amcostestimate_function amcostestimate; + amgettreeheight_function amgettreeheight; /* can be NULL */ amoptions_function amoptions; amproperty_function amproperty; /* can be NULL */ ambuildphasename_function ambuildphasename; /* can be NULL */ @@ -480,6 +481,21 @@ amcostestimate (PlannerInfo *root, +int +amgettreeheight (Relation rel); + + Compute the height of a tree-shaped index. This information is supplied to + the amcostestimate function in + path->indexinfo->tree_height and can be used to support + the cost estimation. The result is not used anywhere else, so this + function can actually be used to compute any kind of data (that fits into + an integer) about the index that the cost estimation function might want to + know. If the computation is expensive, it could be useful to cache the + result as part of RelationData.rd_amcache. + + + + bytea * amoptions (ArrayType *reloptions, bool validate); diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6467bed604..94a8bd0701 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -279,6 +279,7 @@ brinhandler(PG_FUNCTION_ARGS) amroutine->amvacuumcleanup = brinvacuumcleanup; amroutine->amcanreturn = NULL; amroutine->amcostestimate = brincostestimate; + amroutine->amgettreeheight = NULL; amroutine->amoptions = brinoptions; amroutine->amproperty = NULL; amroutine->ambuildphasename = NULL; diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c index 5747ae6a4c..830d67fbc2 100644 --- a/src/backend/access/gin/ginutil.c +++ b/src/backend/access/gin/ginutil.c @@ -69,6 +69,7 @@ ginhandler(PG_FUNCTION_ARGS) amroutine->amvacuumcleanup = ginvacuumcleanup; amroutine->amcanreturn = NULL; amroutine->amcostestimate = gincostestimate; + amroutine->amgettreeheight = NULL; amroutine->amoptions = ginoptions; amroutine->amproperty = NULL; amroutine->ambuildphasename = NULL; diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index ed4ffa63a7..2d7a0687d4 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -91,6 +91,7 @@ gisthandler(PG_FUNCTION_ARGS) amroutine->amvacuumcleanup = gistvacuumcleanup; amroutine->amcanreturn = gistcanreturn; amroutine->amcostestimate = gistcostestimate; + amroutine->amgettreeheight = NULL; amroutine->amoptions = gistoptions; amroutine->amproperty = gistproperty; amroutine->ambuildphasename = NULL; diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c index 01d06b7c32..a783b9b4e2 100644 --- a/src/backend/access/hash/hash.c +++ b/src/backend/access/hash/hash.c @@ -89,6 +89,7 @@ hashhandler(PG_FUNCTION_ARGS) amroutine->amvacuumcleanup = hashvacuumcleanup; amroutine->amcanreturn = NULL; amroutine->amcostestimate = hashcostestimate; + amroutine->amgettreeheight = NULL; amroutine->amoptions = hashoptions; amroutine->amproperty = NULL; amroutine->ambuildphasename = NULL; diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 686a3206f7..8cfaab949b 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -133,6 +133,7 @@ bthandler(PG_FUNCTION_ARGS) amroutine->amvacuumcleanup = btvacuumcleanup; amroutine->amcanreturn = btcanreturn; amroutine->amcostestimate = btcostestimate; + amroutine->amgettreeheight = btgettreeheight; amroutine->amoptions = btoptions; amroutine->amproperty = btproperty; amroutine->ambuildphasename = btbuildphasename; @@ -1445,3 +1446,12 @@ btcanreturn(Relation index, int attno) { return true; } + +/* + * btgettreeheight() -- Compute tree height for use by btcostestimate(). + */ +int +btgettreeheight(Relation rel) +{ + return _bt_getrootheight(rel); +} diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c index 76b80146ff..72b7661971 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -76,6 +76,7 @@ spghandler(PG_FUNCTION_ARGS) amroutine->amvacuumcleanup = spgvacuumcleanup; amroutine->amcanreturn = spgcanreturn; amroutine->amcostestimate = spgcostestimate; + amroutine->amgettreeheight = NULL; amroutine->amoptions = spgoptions; amroutine->amproperty = spgproperty; amroutine->ambuildphasename = NULL; diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 78a3cfafde..82f031f4cf 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -241,7 +241,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, Oid indexoid = lfirst_oid(l); Relation indexRelation; Form_pg_index index; - IndexAmRoutine *amroutine; + IndexAmRoutine *amroutine = NULL; IndexOptInfo *info; int ncolumns, nkeycolumns; @@ -485,13 +485,12 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, info->tuples = rel->tuples; } - if (info->relam == BTREE_AM_OID) + /* + * Get tree height while we have the index open + */ + if (amroutine->amgettreeheight) { - /* - * For btrees, get tree height while we have the index - * open - */ - info->tree_height = _bt_getrootheight(indexRelation); + info->tree_height = amroutine->amgettreeheight(indexRelation); } else { diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h index f25c9d58a7..c51de742ea 100644 --- a/src/include/access/amapi.h +++ b/src/include/access/amapi.h @@ -140,6 +140,13 @@ typedef void (*amcostestimate_function) (struct PlannerInfo *root, double *indexCorrelation, double *indexPages); +/* estimate height of a tree-structured index + * + * XXX This just computes a value that is later used by amcostestimate. This + * API could be expanded to support passing more values if the need arises. + */ +typedef int (*amgettreeheight_function) (Relation rel); + /* parse index reloptions */ typedef bytea *(*amoptions_function) (Datum reloptions, bool validate); @@ -272,6 +279,7 @@ typedef struct IndexAmRoutine amvacuumcleanup_function amvacuumcleanup; amcanreturn_function amcanreturn; /* can be NULL */ amcostestimate_function amcostestimate; + amgettreeheight_function amgettreeheight; /* can be NULL */ amoptions_function amoptions; amproperty_function amproperty; /* can be NULL */ ambuildphasename_function ambuildphasename; /* can be NULL */ diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index 9af9b3ecdc..d64300fb97 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -1186,6 +1186,7 @@ extern IndexBulkDeleteResult *btbulkdelete(IndexVacuumInfo *info, extern IndexBulkDeleteResult *btvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats); extern bool btcanreturn(Relation index, int attno); +extern int btgettreeheight(Relation rel); /* * prototypes for internal functions in nbtree.c diff --git a/src/test/modules/dummy_index_am/dummy_index_am.c b/src/test/modules/dummy_index_am/dummy_index_am.c index 0b47711606..2841cf2eb4 100644 --- a/src/test/modules/dummy_index_am/dummy_index_am.c +++ b/src/test/modules/dummy_index_am/dummy_index_am.c @@ -308,6 +308,7 @@ dihandler(PG_FUNCTION_ARGS) amroutine->amvacuumcleanup = divacuumcleanup; amroutine->amcanreturn = NULL; amroutine->amcostestimate = dicostestimate; + amroutine->amgettreeheight = NULL; amroutine->amoptions = dioptions; amroutine->amproperty = NULL; amroutine->ambuildphasename = NULL;