diff options
author | Teodor Sigaev <teodor@sigaev.ru> | 2007-01-31 15:09:45 +0000 |
---|---|---|
committer | Teodor Sigaev <teodor@sigaev.ru> | 2007-01-31 15:09:45 +0000 |
commit | d4c6da152782b580b24cd8b4054eb1b7fb72c5a0 (patch) | |
tree | 23db426588b5ff2a39981393a3cc4b48397b4294 /src/backend/utils/adt/selfuncs.c | |
parent | 147a3ce149088c913b152e7d37bb92f61bb068dd (diff) | |
download | postgresql-d4c6da152782b580b24cd8b4054eb1b7fb72c5a0.tar.gz postgresql-d4c6da152782b580b24cd8b4054eb1b7fb72c5a0.zip |
Allow GIN's extractQuery method to signal that nothing can satisfy the query.
In this case extractQuery should returns -1 as nentries. This changes
prototype of extractQuery method to use int32* instead of uint32* for
nentries argument.
Based on that gincostestimate may see two corner cases: nothing will be found
or seqscan should be used.
Per proposal at http://archives.postgresql.org/pgsql-hackers/2007-01/msg01581.php
PS tsearch_core patch should be sightly modified to support changes, but I'm
waiting a verdict about reviewing of tsearch_core patch.
Diffstat (limited to 'src/backend/utils/adt/selfuncs.c')
-rw-r--r-- | src/backend/utils/adt/selfuncs.c | 116 |
1 files changed, 115 insertions, 1 deletions
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 0780e52a896..e035557ff2c 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.223 2007/01/28 02:53:34 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.224 2007/01/31 15:09:45 teodor Exp $ * *------------------------------------------------------------------------- */ @@ -76,6 +76,7 @@ #include <ctype.h> #include <math.h> +#include "access/gin.h" #include "catalog/pg_opfamily.h" #include "catalog/pg_statistic.h" #include "catalog/pg_type.h" @@ -5286,7 +5287,120 @@ gincostestimate(PG_FUNCTION_ARGS) Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(5); Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(6); double *indexCorrelation = (double *) PG_GETARG_POINTER(7); + ListCell *l; + int32 nfullscan = 0; + + /* + * GIN doesn't support full index scan. + * If quals require full index scan then we should + * return cost big as possible to forbid full index scan. + */ + + foreach(l, indexQuals) + { + RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); + Expr *clause; + Node *leftop, + *rightop, + *operand; + Oid extractProcOid; + Oid clause_op; + int strategy_op; + Oid lefttype, + righttype; + bool recheck; + int32 nentries; + + /* + * For each clause it's needed to check operand + * for values to search in GIN. So, we should find + * extractQuery method to get values from operand + */ + + Assert(IsA(rinfo, RestrictInfo)); + clause = rinfo->clause; + Assert( IsA(clause, OpExpr) ); + leftop = get_leftop(clause); + rightop = get_rightop(clause); + clause_op = ((OpExpr *) clause)->opno; + + if (match_index_to_operand(leftop, 0 /* GiN has only one column */, index)) + { + operand = rightop; + } + else if (match_index_to_operand(rightop, 0, index)) + { + operand = leftop; + clause_op = get_commutator(clause_op); + } + + if ( IsA(operand, RelabelType) ) + operand = (Node *) ((RelabelType *) operand)->arg; + + /* + * It's impossible to call extractQuery method for not yet + * known operand (taken from table, for example). In this + * case we can't do anything useful... + */ + if ( !IsA(operand, Const) ) + continue; + + if (!op_in_opfamily(clause_op, index->opfamily[0])) + continue; + + /* + * lefttype is a type of index column, righttype is a + * type of operand (query) + */ + get_op_opfamily_properties( clause_op, index->opfamily[0], + &strategy_op, &lefttype, &righttype, &recheck); + + /* + * GIN (as GiST) always has lefttype == righttype in pg_amproc + * and they are equal to type Oid on which index was created/designed + */ + extractProcOid = get_opfamily_proc( index->opfamily[0], + lefttype, lefttype, + GIN_EXTRACTQUERY_PROC ); + + if ( !OidIsValid(extractProcOid) ) + continue; /* should not be */ + + OidFunctionCall3( extractProcOid, + ((Const*)operand)->constvalue, + PointerGetDatum(&nentries), + UInt16GetDatum(strategy_op)); + + if ( nentries == 0 ) + nfullscan++; + else if ( nentries < 0 ) + { + /* + * GIN_EXTRACTQUERY_PROC guarantees that nothing will be found + */ + *indexStartupCost = 0; + *indexTotalCost = 0; + *indexSelectivity = 0; + *indexCorrelation = 0; + PG_RETURN_VOID(); + } + } + + if ( nfullscan == list_length(indexQuals) ) + { + /* + * All quals are void and require full scan. So + * set max possible cost to prevent index scan. + */ + *indexStartupCost = disable_cost; + *indexTotalCost = disable_cost; + *indexSelectivity = 1.0; + *indexCorrelation = 0; + + PG_RETURN_VOID(); + } + genericcostestimate(root, index, indexQuals, outer_rel, 0.0, indexStartupCost, indexTotalCost, indexSelectivity, indexCorrelation); |