Matteo Beccati wrote:
> Bruce Momjian ha scritto:
> > Your patch has been added to the PostgreSQL unapplied patches list at:
> >
> > http://momjian.postgresql.org/cgi-bin/pgpatches
> >
> > It will be applied as soon as one of the PostgreSQL committers reviews
> > and approves it.
>
> Great. I would just like to remind that Tom said:
>
> > I'd be willing to consider exporting those functions from selfuncs.c.
>
> so that the selector function could be moved to contrib/ltree, which is
> its natural place.
>
> It could also be noted that a similar feature could be useful outside
> ltree: I guess there are plenty of cases when scanning statistics would
> give a better result than using a constant selectivity.
I have done as you and Tom suggested, moving parentsel into
/contrib/ltree. Patch attached and applied, catalog version attached.
--
Bruce Momjian http://candle.pha.pa.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
Index: contrib/ltree/ltree.sql.in
===================================================================
RCS file: /cvsroot/pgsql/contrib/ltree/ltree.sql.in,v
retrieving revision 1.11
diff -c -c -r1.11 ltree.sql.in
*** contrib/ltree/ltree.sql.in 26 Apr 2006 18:28:29 -0000 1.11
--- contrib/ltree/ltree.sql.in 26 Apr 2006 22:28:48 -0000
***************
*** 225,230 ****
--- 225,235 ----
AS 'MODULE_PATHNAME'
LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
+ CREATE FUNCTION ltreeparentsel(internal, oid, internal, integer)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
+
CREATE OPERATOR @> (
LEFTARG = ltree,
RIGHTARG = ltree,
Index: contrib/ltree/ltree_op.c
===================================================================
RCS file: /cvsroot/pgsql/contrib/ltree/ltree_op.c,v
retrieving revision 1.9
diff -c -c -r1.9 ltree_op.c
*** contrib/ltree/ltree_op.c 11 Mar 2006 04:38:29 -0000 1.9
--- contrib/ltree/ltree_op.c 26 Apr 2006 22:28:49 -0000
***************
*** 7,12 ****
--- 7,19 ----
#include "ltree.h"
#include <ctype.h>
+ #include "access/heapam.h"
+ #include "catalog/pg_statistic.h"
+ #include "nodes/relation.h"
+ #include "utils/lsyscache.h"
+ #include "utils/selfuncs.h"
+ #include "utils/syscache.h"
+
/* compare functions */
PG_FUNCTION_INFO_V1(ltree_cmp);
PG_FUNCTION_INFO_V1(ltree_lt);
***************
*** 44,49 ****
--- 51,57 ----
Datum lca(PG_FUNCTION_ARGS);
Datum ltree2text(PG_FUNCTION_ARGS);
Datum text2ltree(PG_FUNCTION_ARGS);
+ Datum ltreeparentsel(PG_FUNCTION_ARGS);
int
ltree_compare(const ltree * a, const ltree * b)
***************
*** 551,553 ****
--- 559,739 ----
PG_RETURN_POINTER(out);
}
+
+
+ #define DEFAULT_PARENT_SEL 0.001
+
+ /*
+ * ltreeparentsel - Selectivity of parent relationship for ltree data types.
+ */
+ Datum
+ ltreeparentsel(PG_FUNCTION_ARGS)
+ {
+ PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
+ Oid operator = PG_GETARG_OID(1);
+ List *args = (List *) PG_GETARG_POINTER(2);
+ int varRelid = PG_GETARG_INT32(3);
+ VariableStatData vardata;
+ Node *other;
+ bool varonleft;
+ Datum *values;
+ int nvalues;
+ float4 *numbers;
+ int nnumbers;
+ double selec = 0.0;
+
+ /*
+ * If expression is not variable <@ something or something <@ variable,
+ * then punt and return a default estimate.
+ */
+ if (!get_restriction_variable(root, args, varRelid,
+ &vardata, &other, &varonleft))
+ PG_RETURN_FLOAT8(DEFAULT_PARENT_SEL);
+
+ /*
+ * If the something is a NULL constant, assume operator is strict and
+ * return zero, ie, operator will never return TRUE.
+ */
+ if (IsA(other, Const) &&
+ ((Const *) other)->constisnull)
+ {
+ ReleaseVariableStats(vardata);
+ PG_RETURN_FLOAT8(0.0);
+ }
+
+ if (HeapTupleIsValid(vardata.statsTuple))
+ {
+ Form_pg_statistic stats;
+ double mcvsum = 0.0;
+ double mcvsel = 0.0;
+ double hissel = 0.0;
+
+ stats = (Form_pg_statistic) GETSTRUCT(vardata.statsTuple);
+
+ if (IsA(other, Const))
+ {
+ /* Variable is being compared to a known non-null constant */
+ Datum constval = ((Const *) other)->constvalue;
+ bool match = false;
+ int i;
+
+ /*
+ * Is the constant "<@" to any of the column's most common values?
+ */
+ if (get_attstatsslot(vardata.statsTuple,
+ vardata.atttype, vardata.atttypmod,
+ STATISTIC_KIND_MCV, InvalidOid,
+ &values, &nvalues,
+ &numbers, &nnumbers))
+ {
+ FmgrInfo contproc;
+
+ fmgr_info(get_opcode(operator), &contproc);
+
+ for (i = 0; i < nvalues; i++)
+ {
+ /* be careful to apply operator right way 'round */
+ if (varonleft)
+ match = DatumGetBool(FunctionCall2(&contproc,
+ values[i],
+ constval));
+ else
+ match = DatumGetBool(FunctionCall2(&contproc,
+ constval,
+ values[i]));
+
+ /* calculate total selectivity of all most-common-values */
+ mcvsum += numbers[i];
+
+ /* calculate selectivity of matching most-common-values */
+ if (match)
+ mcvsel += numbers[i];
+ }
+ }
+ else
+ {
+ /* no most-common-values info available */
+ values = NULL;
+ numbers = NULL;
+ i = nvalues = nnumbers = 0;
+ }
+
+ free_attstatsslot(vardata.atttype, values, nvalues, NULL, 0);
+
+ /*
+ * Is the constant "<@" to any of the column's histogram values?
+ */
+ if (get_attstatsslot(vardata.statsTuple,
+ vardata.atttype, vardata.atttypmod,
+ STATISTIC_KIND_HISTOGRAM, InvalidOid,
+ &values, &nvalues,
+ NULL, NULL))
+ {
+ FmgrInfo contproc;
+
+ fmgr_info(get_opcode(operator), &contproc);
+
+ for (i = 0; i < nvalues; i++)
+ {
+ /* be careful to apply operator right way 'round */
+ if (varonleft)
+ match = DatumGetBool(FunctionCall2(&contproc,
+ values[i],
+ constval));
+ else
+ match = DatumGetBool(FunctionCall2(&contproc,
+ constval,
+ values[i]));
+ /* count matching histogram values */
+ if (match)
+ hissel++;
+ }
+
+ if (hissel > 0.0)
+ {
+ /*
+ * some matching values found inside histogram, divide
+ * matching entries number by total histogram entries to
+ * get the histogram related selectivity
+ */
+ hissel /= nvalues;
+ }
+ }
+ else
+ {
+ /* no histogram info available */
+ values = NULL;
+ i = nvalues = 0;
+ }
+
+ free_attstatsslot(vardata.atttype, values, nvalues,
+ NULL, 0);
+
+
+ /*
+ * calculate selectivity based on MCV and histogram result
+ * histogram selectivity needs to be scaled down if there are any
+ * most-common-values
+ */
+ selec = mcvsel + hissel * (1.0 - mcvsum);
+
+ /*
+ * don't return 0.0 selectivity unless all table values are inside
+ * mcv
+ */
+ if (selec == 0.0 && mcvsum != 1.0)
+ selec = DEFAULT_PARENT_SEL;
+ }
+ else
+ selec = DEFAULT_PARENT_SEL;
+ }
+ else
+ selec = DEFAULT_PARENT_SEL;
+
+ ReleaseVariableStats(vardata);
+
+ /* result should be in range, but make sure... */
+ CLAMP_PROBABILITY(selec);
+
+ PG_RETURN_FLOAT8((float8) selec);
+ }
Index: contrib/ltree/expected/ltree.out
===================================================================
RCS file: /cvsroot/pgsql/contrib/ltree/expected/ltree.out,v
retrieving revision 1.12
diff -c -c -r1.12 ltree.out
*** contrib/ltree/expected/ltree.out 21 Aug 2004 00:26:54 -0000 1.12
--- contrib/ltree/expected/ltree.out 26 Apr 2006 22:28:56 -0000
***************
*** 2,16 ****
psql:ltree.sql:7: NOTICE: type "ltree" is not yet defined
DETAIL: Creating a shell type definition.
psql:ltree.sql:12: NOTICE: argument type ltree is only a shell
! psql:ltree.sql:299: NOTICE: type "lquery" is not yet defined
DETAIL: Creating a shell type definition.
! psql:ltree.sql:304: NOTICE: argument type lquery is only a shell
! psql:ltree.sql:410: NOTICE: type "ltxtquery" is not yet defined
DETAIL: Creating a shell type definition.
! psql:ltree.sql:415: NOTICE: argument type ltxtquery is only a shell
! psql:ltree.sql:477: NOTICE: type "ltree_gist" is not yet defined
DETAIL: Creating a shell type definition.
! psql:ltree.sql:482: NOTICE: argument type ltree_gist is only a shell
SELECT ''::ltree;
ltree
-------
--- 2,16 ----
psql:ltree.sql:7: NOTICE: type "ltree" is not yet defined
DETAIL: Creating a shell type definition.
psql:ltree.sql:12: NOTICE: argument type ltree is only a shell
! psql:ltree.sql:304: NOTICE: type "lquery" is not yet defined
DETAIL: Creating a shell type definition.
! psql:ltree.sql:309: NOTICE: argument type lquery is only a shell
! psql:ltree.sql:415: NOTICE: type "ltxtquery" is not yet defined
DETAIL: Creating a shell type definition.
! psql:ltree.sql:420: NOTICE: argument type ltxtquery is only a shell
! psql:ltree.sql:482: NOTICE: type "ltree_gist" is not yet defined
DETAIL: Creating a shell type definition.
! psql:ltree.sql:487: NOTICE: argument type ltree_gist is only a shell
SELECT ''::ltree;
ltree
-------
Index: src/backend/utils/adt/geo_selfuncs.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/geo_selfuncs.c,v
retrieving revision 1.28
diff -c -c -r1.28 geo_selfuncs.c
*** src/backend/utils/adt/geo_selfuncs.c 26 Apr 2006 18:28:29 -0000 1.28
--- src/backend/utils/adt/geo_selfuncs.c 26 Apr 2006 22:29:04 -0000
***************
*** 9,15 ****
*
*
* IDENTIFICATION
! * $PostgreSQL: pgsql/src/backend/utils/adt/geo_selfuncs.c,v 1.28 2006/04/26 18:28:29 momjian Exp $
*
* XXX These are totally bogus. Perhaps someone will make them do
* something reasonable, someday.
--- 9,15 ----
*
*
* IDENTIFICATION
! * $PostgreSQL: pgsql/src/backend/utils/adt/geo_selfuncs.c,v 1.27 2006/03/05 15:58:42 momjian Exp $
*
* XXX These are totally bogus. Perhaps someone will make them do
* something reasonable, someday.
***************
*** 20,25 ****
--- 20,26 ----
#include "utils/geo_decls.h"
+
/*
* Selectivity functions for geometric operators. These are bogus -- unless
* we know the actual key distribution in the index, we can't make a good
***************
*** 92,95 ****
{
PG_RETURN_FLOAT8(0.001);
}
-
--- 93,95 ----
Index: src/backend/utils/adt/selfuncs.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v
retrieving revision 1.200
diff -c -c -r1.200 selfuncs.c
*** src/backend/utils/adt/selfuncs.c 26 Apr 2006 18:28:29 -0000 1.200
--- src/backend/utils/adt/selfuncs.c 26 Apr 2006 22:29:13 -0000
***************
*** 15,21 ****
*
*
* IDENTIFICATION
! * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.200 2006/04/26 18:28:29 momjian Exp $
*
*-------------------------------------------------------------------------
*/
--- 15,21 ----
*
*
* IDENTIFICATION
! * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.199 2006/04/20 17:50:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
***************
*** 111,136 ****
#include "utils/syscache.h"
- /* Return data from examine_variable and friends */
- typedef struct
- {
- Node *var; /* the Var or expression tree */
- RelOptInfo *rel; /* Relation, or NULL if not identifiable */
- HeapTuple statsTuple; /* pg_statistic tuple, or NULL if none */
- /* NB: if statsTuple!=NULL, it must be freed when caller is done */
- Oid vartype; /* exposed type of expression */
- 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)
-
-
static double mcv_selectivity(VariableStatData *vardata, FmgrInfo *opproc,
Datum constval, double *sumcommonp);
static double ineq_histogram_selectivity(VariableStatData *vardata,
--- 111,116 ----
***************
*** 158,166 ****
int rangelo, int rangehi);
static char *convert_string_datum(Datum value, Oid typid);
static double convert_timevalue_to_scalar(Datum value, Oid typid);
- static bool get_restriction_variable(PlannerInfo *root, List *args, int varRelid,
- VariableStatData *vardata, Node **other,
- bool *varonleft);
static void get_join_variables(PlannerInfo *root, List *args,
VariableStatData *vardata1,
VariableStatData *vardata2);
--- 138,143 ----
***************
*** 3172,3178 ****
* Note: if there are Vars on both sides of the clause, we must fail, because
* callers are expecting that the other side will act like a pseudoconstant.
*/
! static bool
get_restriction_variable(PlannerInfo *root, List *args, int varRelid,
VariableStatData *vardata, Node **other,
bool *varonleft)
--- 3149,3155 ----
* Note: if there are Vars on both sides of the clause, we must fail, because
* callers are expecting that the other side will act like a pseudoconstant.
*/
! bool
get_restriction_variable(PlannerInfo *root, List *args, int varRelid,
VariableStatData *vardata, Node **other,
bool *varonleft)
***************
*** 4852,5033 ****
PG_RETURN_VOID();
}
-
-
- #define DEFAULT_PARENT_SEL 0.001
-
- /*
- * parentsel - Selectivity of parent relationship for ltree data types.
- */
- Datum
- parentsel(PG_FUNCTION_ARGS)
- {
- PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
- Oid operator = PG_GETARG_OID(1);
- List *args = (List *) PG_GETARG_POINTER(2);
- int varRelid = PG_GETARG_INT32(3);
- VariableStatData vardata;
- Node *other;
- bool varonleft;
- Datum *values;
- int nvalues;
- float4 *numbers;
- int nnumbers;
- double selec = 0.0;
-
- /*
- * If expression is not variable <@ something or something <@ variable,
- * then punt and return a default estimate.
- */
- if (!get_restriction_variable(root, args, varRelid,
- &vardata, &other, &varonleft))
- PG_RETURN_FLOAT8(DEFAULT_PARENT_SEL);
-
- /*
- * If the something is a NULL constant, assume operator is strict and
- * return zero, ie, operator will never return TRUE.
- */
- if (IsA(other, Const) &&
- ((Const *) other)->constisnull)
- {
- ReleaseVariableStats(vardata);
- PG_RETURN_FLOAT8(0.0);
- }
-
- if (HeapTupleIsValid(vardata.statsTuple))
- {
- Form_pg_statistic stats;
- double mcvsum = 0.0;
- double mcvsel = 0.0;
- double hissel = 0.0;
-
- stats = (Form_pg_statistic) GETSTRUCT(vardata.statsTuple);
-
- if (IsA(other, Const))
- {
- /* Variable is being compared to a known non-null constant */
- Datum constval = ((Const *) other)->constvalue;
- bool match = false;
- int i;
-
- /*
- * Is the constant "<@" to any of the column's most common values?
- */
- if (get_attstatsslot(vardata.statsTuple,
- vardata.atttype, vardata.atttypmod,
- STATISTIC_KIND_MCV, InvalidOid,
- &values, &nvalues,
- &numbers, &nnumbers))
- {
- FmgrInfo contproc;
-
- fmgr_info(get_opcode(operator), &contproc);
-
- for (i = 0; i < nvalues; i++)
- {
- /* be careful to apply operator right way 'round */
- if (varonleft)
- match = DatumGetBool(FunctionCall2(&contproc,
- values[i],
- constval));
- else
- match = DatumGetBool(FunctionCall2(&contproc,
- constval,
- values[i]));
-
- /* calculate total selectivity of all most-common-values */
- mcvsum += numbers[i];
-
- /* calculate selectivity of matching most-common-values */
- if (match)
- mcvsel += numbers[i];
- }
- }
- else
- {
- /* no most-common-values info available */
- values = NULL;
- numbers = NULL;
- i = nvalues = nnumbers = 0;
- }
-
- free_attstatsslot(vardata.atttype, values, nvalues, NULL, 0);
-
- /*
- * Is the constant "<@" to any of the column's histogram values?
- */
- if (get_attstatsslot(vardata.statsTuple,
- vardata.atttype, vardata.atttypmod,
- STATISTIC_KIND_HISTOGRAM, InvalidOid,
- &values, &nvalues,
- NULL, NULL))
- {
- FmgrInfo contproc;
-
- fmgr_info(get_opcode(operator), &contproc);
-
- for (i = 0; i < nvalues; i++)
- {
- /* be careful to apply operator right way 'round */
- if (varonleft)
- match = DatumGetBool(FunctionCall2(&contproc,
- values[i],
- constval));
- else
- match = DatumGetBool(FunctionCall2(&contproc,
- constval,
- values[i]));
- /* count matching histogram values */
- if (match)
- hissel++;
- }
-
- if (hissel > 0.0)
- {
- /*
- * some matching values found inside histogram, divide
- * matching entries number by total histogram entries to
- * get the histogram related selectivity
- */
- hissel /= nvalues;
- }
- }
- else
- {
- /* no histogram info available */
- values = NULL;
- i = nvalues = 0;
- }
-
- free_attstatsslot(vardata.atttype, values, nvalues,
- NULL, 0);
-
-
- /*
- * calculate selectivity based on MCV and histogram result
- * histogram selectivity needs to be scaled down if there are any
- * most-common-values
- */
- selec = mcvsel + hissel * (1.0 - mcvsum);
-
- /*
- * don't return 0.0 selectivity unless all table values are inside
- * mcv
- */
- if (selec == 0.0 && mcvsum != 1.0)
- selec = DEFAULT_PARENT_SEL;
- }
- else
- selec = DEFAULT_PARENT_SEL;
- }
- else
- selec = DEFAULT_PARENT_SEL;
-
- ReleaseVariableStats(vardata);
-
- /* result should be in range, but make sure... */
- CLAMP_PROBABILITY(selec);
-
- PG_RETURN_FLOAT8((float8) selec);
- }
-
--- 4829,4831 ----
Index: src/include/catalog/catversion.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/catalog/catversion.h,v
retrieving revision 1.325
diff -c -c -r1.325 catversion.h
*** src/include/catalog/catversion.h 26 Apr 2006 18:30:10 -0000 1.325
--- src/include/catalog/catversion.h 26 Apr 2006 22:29:15 -0000
***************
*** 53,58 ****
*/
/* yyyymmddN */
! #define CATALOG_VERSION_NO 200604261
#endif
--- 53,58 ----
*/
/* yyyymmddN */
! #define CATALOG_VERSION_NO 200604262
#endif
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/catalog/pg_proc.h,v
retrieving revision 1.407
diff -c -c -r1.407 pg_proc.h
*** src/include/catalog/pg_proc.h 26 Apr 2006 18:28:30 -0000 1.407
--- src/include/catalog/pg_proc.h 26 Apr 2006 22:29:33 -0000
***************
*** 7,13 ****
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
! * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.407 2006/04/26 18:28:30 momjian Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
--- 7,13 ----
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
! * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.406 2006/04/25 00:25:20 momjian Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
***************
*** 3812,3819 ****
DESCR("GiST support");
DATA(insert OID = 2592 ( gist_circle_compress PGNSP PGUID 12 f f t f i 1 2281 "2281" _null_ _null_ _null_
gist_circle_compress- _null_ ));
DESCR("GiST support");
- DATA(insert OID = 2599 ( parentsel PGNSP PGUID 12 f f t f s 4 701 "2281 26 2281 23" _null_ _null_
_null_parentsel - _null_ ));
- DESCR("enhanced restriction selectivity for ltree isparent comparison operators");
/*
--- 3812,3817 ----
Index: src/include/utils/selfuncs.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/utils/selfuncs.h,v
retrieving revision 1.29
diff -c -c -r1.29 selfuncs.h
*** src/include/utils/selfuncs.h 26 Apr 2006 18:28:34 -0000 1.29
--- src/include/utils/selfuncs.h 26 Apr 2006 22:29:33 -0000
***************
*** 8,14 ****
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
! * $PostgreSQL: pgsql/src/include/utils/selfuncs.h,v 1.29 2006/04/26 18:28:34 momjian Exp $
*
*-------------------------------------------------------------------------
*/
--- 8,14 ----
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
! * $PostgreSQL: pgsql/src/include/utils/selfuncs.h,v 1.28 2006/03/05 15:59:07 momjian Exp $
*
*-------------------------------------------------------------------------
*/
***************
*** 16,21 ****
--- 16,22 ----
#define SELFUNCS_H
#include "fmgr.h"
+ #include "access/htup.h"
#include "nodes/relation.h"
***************
*** 62,67 ****
--- 63,88 ----
} while (0)
+ /* Return data from examine_variable and friends */
+ typedef struct
+ {
+ Node *var; /* the Var or expression tree */
+ RelOptInfo *rel; /* Relation, or NULL if not identifiable */
+ HeapTuple statsTuple; /* pg_statistic tuple, or NULL if none */
+ /* NB: if statsTuple!=NULL, it must be freed when caller is done */
+ Oid vartype; /* exposed type of expression */
+ 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)
+
+
typedef enum
{
Pattern_Type_Like, Pattern_Type_Like_IC,
***************
*** 133,139 ****
extern Datum btcostestimate(PG_FUNCTION_ARGS);
extern Datum hashcostestimate(PG_FUNCTION_ARGS);
extern Datum gistcostestimate(PG_FUNCTION_ARGS);
!
! extern Datum parentsel(PG_FUNCTION_ARGS);
#endif /* SELFUNCS_H */
--- 154,161 ----
extern Datum btcostestimate(PG_FUNCTION_ARGS);
extern Datum hashcostestimate(PG_FUNCTION_ARGS);
extern Datum gistcostestimate(PG_FUNCTION_ARGS);
! extern bool get_restriction_variable(PlannerInfo *root, List *args, int varRelid,
! VariableStatData *vardata, Node **other,
! bool *varonleft);
#endif /* SELFUNCS_H */