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;