summaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
authorBruce Momjian2006-04-26 22:33:36 +0000
committerBruce Momjian2006-04-26 22:33:36 +0000
commit59d61409cd72a2e6688f588d17a73c1bc665df26 (patch)
tree574bd45e91dd90f28477c44019c53223bb0f5c89 /contrib
parentcae5671945cef31f8635909ec8a35a73e4656bbc (diff)
Move ltree parentsel() selectivity function into /contrib/ltree.
Diffstat (limited to 'contrib')
-rw-r--r--contrib/ltree/expected/ltree.out12
-rw-r--r--contrib/ltree/ltree.sql.in5
-rw-r--r--contrib/ltree/ltree_op.c188
3 files changed, 198 insertions, 7 deletions
diff --git a/contrib/ltree/expected/ltree.out b/contrib/ltree/expected/ltree.out
index 3ce1ecf2937..2546490d220 100644
--- a/contrib/ltree/expected/ltree.out
+++ b/contrib/ltree/expected/ltree.out
@@ -2,15 +2,15 @@
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
+psql:ltree.sql:304: 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
+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:415: NOTICE: argument type ltxtquery is only a shell
-psql:ltree.sql:477: NOTICE: type "ltree_gist" is not yet defined
+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:482: NOTICE: argument type ltree_gist is only a shell
+psql:ltree.sql:487: NOTICE: argument type ltree_gist is only a shell
SELECT ''::ltree;
ltree
-------
diff --git a/contrib/ltree/ltree.sql.in b/contrib/ltree/ltree.sql.in
index bdb8bdf52cb..df32c0c501c 100644
--- a/contrib/ltree/ltree.sql.in
+++ b/contrib/ltree/ltree.sql.in
@@ -225,6 +225,11 @@ RETURNS ltree
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,
diff --git a/contrib/ltree/ltree_op.c b/contrib/ltree/ltree_op.c
index ec2d0fbf5de..6b894861dd4 100644
--- a/contrib/ltree/ltree_op.c
+++ b/contrib/ltree/ltree_op.c
@@ -1,12 +1,19 @@
/*
* op function for ltree
* Teodor Sigaev <teodor@stack.net>
- * $PostgreSQL: pgsql/contrib/ltree/ltree_op.c,v 1.9 2006/03/11 04:38:29 momjian Exp $
+ * $PostgreSQL: pgsql/contrib/ltree/ltree_op.c,v 1.10 2006/04/26 22:32:36 momjian Exp $
*/
#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,6 +51,7 @@ Datum ltree_textadd(PG_FUNCTION_ARGS);
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,3 +559,181 @@ ltree2text(PG_FUNCTION_ARGS)
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);
+}