Index: src/backend/utils/adt/selfuncs.c
===================================================================
RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/backend/utils/adt/selfuncs.c,v
retrieving revision 1.250
diff -c -r1.250 selfuncs.c
*** src/backend/utils/adt/selfuncs.c	7 Jul 2008 20:24:55 -0000	1.250
--- src/backend/utils/adt/selfuncs.c	6 Aug 2008 22:24:08 -0000
***************
*** 103,108 ****
--- 103,111 ----
  #include "utils/selfuncs.h"
  #include "utils/syscache.h"
  
+ /* Hook for plugins to get control when we ask for stats */
+ get_relation_stats_hook_type get_relation_stats_hook = NULL;
+ release_relation_stats_hook_type release_relation_stats_hook = NULL;
  
  static double var_eq_const(VariableStatData *vardata, Oid operator,
  			 Datum constval, bool constisnull,
***************
*** 3769,3775 ****
  		}
  		else if (rte->rtekind == RTE_RELATION)
  		{
! 			vardata->statsTuple = SearchSysCache(STATRELATT,
  												 ObjectIdGetDatum(rte->relid),
  												 Int16GetDatum(var->varattno),
  												 0, 0);
--- 3772,3786 ----
  		}
  		else if (rte->rtekind == RTE_RELATION)
  		{
! 			if (get_relation_stats_hook)
! 				vardata->statsTuple = (*get_relation_stats_hook) 
! 												(rte->relid, 
! 												 var->varattno);
! 
! 			if (vardata->statsTuple)
! 				vardata->free_using_plugin = true;				
! 			else
! 				vardata->statsTuple = SearchSysCache(STATRELATT,
  												 ObjectIdGetDatum(rte->relid),
  												 Int16GetDatum(var->varattno),
  												 0, 0);
***************
*** 3889,3898 ****
  							index->indpred == NIL)
  							vardata->isunique = true;
  						/* Has it got stats? */
! 						vardata->statsTuple = SearchSysCache(STATRELATT,
  										   ObjectIdGetDatum(index->indexoid),
! 													  Int16GetDatum(pos + 1),
! 															 0, 0);
  						if (vardata->statsTuple)
  							break;
  					}
--- 3900,3918 ----
  							index->indpred == NIL)
  							vardata->isunique = true;
  						/* Has it got stats? */
! 						if (get_relation_stats_hook)
! 						{
! 							vardata->statsTuple = (*get_relation_stats_hook) 
! 													(index->indexoid, 
! 													 pos + 1);
! 							vardata->free_using_plugin = true;				
! 						}
! 
! 						if (!vardata->statsTuple)
! 							vardata->statsTuple = SearchSysCache(STATRELATT,
  										   ObjectIdGetDatum(index->indexoid),
! 													  	 Int16GetDatum(pos + 1),
! 														 0, 0);
  						if (vardata->statsTuple)
  							break;
  					}
***************
*** 5323,5329 ****
  	double	   *indexCorrelation = (double *) PG_GETARG_POINTER(7);
  	Oid			relid;
  	AttrNumber	colnum;
! 	HeapTuple	tuple;
  	double		numIndexTuples;
  	List	   *indexBoundQuals;
  	int			indexcol;
--- 5343,5349 ----
  	double	   *indexCorrelation = (double *) PG_GETARG_POINTER(7);
  	Oid			relid;
  	AttrNumber	colnum;
! 	HeapTuple	tuple = NULL;
  	double		numIndexTuples;
  	List	   *indexBoundQuals;
  	int			indexcol;
***************
*** 5332,5337 ****
--- 5352,5358 ----
  	bool		found_null_op;
  	double		num_sa_scans;
  	ListCell   *l;
+ 	bool		free_using_plugin = false;
  
  	/*
  	 * For a btree scan, only leading '=' quals plus inequality quals for the
***************
*** 5527,5536 ****
  		colnum = 1;
  	}
  
! 	tuple = SearchSysCache(STATRELATT,
! 						   ObjectIdGetDatum(relid),
! 						   Int16GetDatum(colnum),
! 						   0, 0);
  
  	if (HeapTupleIsValid(tuple))
  	{
--- 5548,5563 ----
  		colnum = 1;
  	}
  
! 	if (get_relation_stats_hook)
! 		tuple = (*get_relation_stats_hook) (relid, colnum);
! 
! 	if (tuple)
! 		free_using_plugin = true;				
! 	else
! 		tuple = SearchSysCache(STATRELATT,
! 							ObjectIdGetDatum(relid),
! 							Int16GetDatum(colnum),
! 							0, 0);
  
  	if (HeapTupleIsValid(tuple))
  	{
***************
*** 5571,5577 ****
  
  			free_attstatsslot(InvalidOid, NULL, 0, numbers, nnumbers);
  		}
! 		ReleaseSysCache(tuple);
  	}
  
  	PG_RETURN_VOID();
--- 5598,5605 ----
  
  			free_attstatsslot(InvalidOid, NULL, 0, numbers, nnumbers);
  		}
! 
! 		ReleaseStatsTuple(tuple, free_using_plugin);
  	}
  
  	PG_RETURN_VOID();
Index: src/backend/utils/cache/lsyscache.c
===================================================================
RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/backend/utils/cache/lsyscache.c,v
retrieving revision 1.157
diff -c -r1.157 lsyscache.c
*** src/backend/utils/cache/lsyscache.c	13 Apr 2008 20:51:21 -0000	1.157
--- src/backend/utils/cache/lsyscache.c	6 Aug 2008 17:45:35 -0000
***************
*** 27,32 ****
--- 27,33 ----
  #include "catalog/pg_proc.h"
  #include "catalog/pg_statistic.h"
  #include "catalog/pg_type.h"
+ #include "optimizer/plancat.h"
  #include "miscadmin.h"
  #include "nodes/makefuncs.h"
  #include "utils/array.h"
***************
*** 35,40 ****
--- 36,43 ----
  #include "utils/lsyscache.h"
  #include "utils/syscache.h"
  
+ /* Hook for plugins to get control in get_attavgwidth() */
+ get_attavgwidth_hook_type get_attavgwidth_hook = NULL;
  
  /*				---------- AMOP CACHES ----------						 */
  
***************
*** 2451,2466 ****
   *
   *	  Given the table and attribute number of a column, get the average
   *	  width of entries in the column.  Return zero if no data available.
   */
  int32
  get_attavgwidth(Oid relid, AttrNumber attnum)
  {
  	HeapTuple	tp;
  
  	tp = SearchSysCache(STATRELATT,
! 						ObjectIdGetDatum(relid),
! 						Int16GetDatum(attnum),
! 						0, 0);
  	if (HeapTupleIsValid(tp))
  	{
  		int32		stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
--- 2454,2483 ----
   *
   *	  Given the table and attribute number of a column, get the average
   *	  width of entries in the column.  Return zero if no data available.
+  *
+  *	  Calling a hook at this point looks somewhat strange, but is required
+  * 	  because the optimizer handles inheritance relations by calling for
+  *	  the avg width later in the planner than get_relation_info_hook().
+  *	  So the APIs and call points of hooks must match the optimizer.
   */
  int32
  get_attavgwidth(Oid relid, AttrNumber attnum)
  {
  	HeapTuple	tp;
+ 	int32		stawidth;
+ 
+ 	if (get_attavgwidth_hook)
+ 	{
+ 		stawidth = (*get_attavgwidth_hook) (relid, attnum);
+ 		if (stawidth > 0)
+ 			return stawidth;
+ 	}
  
  	tp = SearchSysCache(STATRELATT,
! 					ObjectIdGetDatum(relid),
! 					Int16GetDatum(attnum),
! 					0, 0);
! 
  	if (HeapTupleIsValid(tp))
  	{
  		int32		stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
Index: src/include/optimizer/plancat.h
===================================================================
RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/include/optimizer/plancat.h,v
retrieving revision 1.50
diff -c -r1.50 plancat.h
*** src/include/optimizer/plancat.h	19 Jun 2008 00:46:06 -0000	1.50
--- src/include/optimizer/plancat.h	6 Aug 2008 21:51:09 -0000
***************
*** 14,19 ****
--- 14,20 ----
  #ifndef PLANCAT_H
  #define PLANCAT_H
  
+ #include "access/htup.h"
  #include "nodes/relation.h"
  #include "utils/relcache.h"
  
***************
*** 24,29 ****
--- 25,41 ----
  														 RelOptInfo *rel);
  extern PGDLLIMPORT get_relation_info_hook_type get_relation_info_hook;
  
+ /* Hooks for plugins to get control in lsyscache.c and selfuncs.c */
+ typedef HeapTuple (*get_relation_stats_hook_type) (Oid relid, AttrNumber attnum);
+ extern PGDLLIMPORT get_relation_stats_hook_type get_relation_stats_hook;
+ 
+ typedef void (*release_relation_stats_hook_type) (HeapTuple statstup);
+ extern PGDLLIMPORT release_relation_stats_hook_type release_relation_stats_hook;
+ 
+ typedef int32 (*get_attavgwidth_hook_type) (Oid relid, AttrNumber attnum);
+ extern PGDLLIMPORT get_attavgwidth_hook_type get_attavgwidth_hook;
+ 
+ 
  
  extern void get_relation_info(PlannerInfo *root, Oid relationObjectId,
  				  bool inhparent, RelOptInfo *rel);
Index: src/include/utils/selfuncs.h
===================================================================
RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/include/utils/selfuncs.h,v
retrieving revision 1.44
diff -c -r1.44 selfuncs.h
*** src/include/utils/selfuncs.h	9 Mar 2008 00:32:09 -0000	1.44
--- src/include/utils/selfuncs.h	6 Aug 2008 21:53:53 -0000
***************
*** 74,85 ****
  	Oid			atttype;		/* type to pass to get_attstatsslot */
  	int32		atttypmod;		/* typmod to pass to get_attstatsslot */
  	bool		isunique;		/* true if matched to a unique index */
  } VariableStatData;
  
  #define ReleaseVariableStats(vardata)  \
  	do { \
  		if (HeapTupleIsValid((vardata).statsTuple)) \
! 			ReleaseSysCache((vardata).statsTuple); \
  	} while(0)
  
  
--- 74,112 ----
  	Oid			atttype;		/* type to pass to get_attstatsslot */
  	int32		atttypmod;		/* typmod to pass to get_attstatsslot */
  	bool		isunique;		/* true if matched to a unique index */
+ 	bool		free_using_plugin;
  } VariableStatData;
  
+ #define ReleaseStatsTuple(tuple, free_using_plugin)  \
+ 	do { \
+ 		if (HeapTupleIsValid(tuple)) \
+ 		{ \
+ 			if (free_using_plugin) \
+ 			{ \
+ 				if (release_relation_stats_hook) \
+ 					(* release_relation_stats_hook)(tuple); \
+ 				else \
+ 					elog(ERROR, "unable to release variable stats correctly"); \
+ 			} \
+ 			else \
+ 				ReleaseSysCache(tuple); \
+ 		} \
+ 	} while(0)
+ 
  #define ReleaseVariableStats(vardata)  \
  	do { \
  		if (HeapTupleIsValid((vardata).statsTuple)) \
! 		{ \
! 			if ((vardata).free_using_plugin) \
! 			{ \
! 				if (release_relation_stats_hook) \
! 					(* release_relation_stats_hook)((vardata).statsTuple); \
! 				else \
! 					elog(ERROR, "unable to release variable stats correctly"); \
! 			} \
! 			else \
! 				ReleaseSysCache((vardata).statsTuple); \
! 		} \
  	} while(0)
  
  
