diff options
| author | Bruce Momjian | 2006-04-26 22:33:36 +0000 |
|---|---|---|
| committer | Bruce Momjian | 2006-04-26 22:33:36 +0000 |
| commit | 59d61409cd72a2e6688f588d17a73c1bc665df26 (patch) | |
| tree | 574bd45e91dd90f28477c44019c53223bb0f5c89 /contrib | |
| parent | cae5671945cef31f8635909ec8a35a73e4656bbc (diff) | |
Move ltree parentsel() selectivity function into /contrib/ltree.
Diffstat (limited to 'contrib')
| -rw-r--r-- | contrib/ltree/expected/ltree.out | 12 | ||||
| -rw-r--r-- | contrib/ltree/ltree.sql.in | 5 | ||||
| -rw-r--r-- | contrib/ltree/ltree_op.c | 188 |
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); +} |
