Fix up gincostestimate for new extractQuery API.

The only reason this wasn't crashing while testing the core anyarray
operators was that it was disabled for those cases because of passing the
wrong type information to get_opfamily_proc :-(.  So fix that too, and make
it insist on finding the support proc --- in hindsight, silently doing
nothing is not as sane a coping mechanism as all that.
This commit is contained in:
Tom Lane 2011-01-08 20:13:33 -05:00
parent 833a2b57bc
commit 4d1b76e49e

View File

@ -6281,7 +6281,6 @@ gincostestimate(PG_FUNCTION_ARGS)
Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(7); Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(7);
double *indexCorrelation = (double *) PG_GETARG_POINTER(8); double *indexCorrelation = (double *) PG_GETARG_POINTER(8);
ListCell *l; ListCell *l;
int32 nfullscan = 0;
List *selectivityQuals; List *selectivityQuals;
double numPages = index->pages, double numPages = index->pages,
numTuples = index->tuples; numTuples = index->tuples;
@ -6289,6 +6288,7 @@ gincostestimate(PG_FUNCTION_ARGS)
numDataPages, numDataPages,
numPendingPages, numPendingPages,
numEntries; numEntries;
bool haveFullScan = false;
double partialEntriesInQuals = 0.0; double partialEntriesInQuals = 0.0;
double searchEntriesInQuals = 0.0; double searchEntriesInQuals = 0.0;
double exactEntriesInQuals = 0.0; double exactEntriesInQuals = 0.0;
@ -6394,6 +6394,8 @@ gincostestimate(PG_FUNCTION_ARGS)
int32 nentries = 0; int32 nentries = 0;
bool *partial_matches = NULL; bool *partial_matches = NULL;
Pointer *extra_data = NULL; Pointer *extra_data = NULL;
bool *nullFlags = NULL;
int32 searchMode = GIN_SEARCH_MODE_DEFAULT;
int indexcol; int indexcol;
Assert(IsA(rinfo, RestrictInfo)); Assert(IsA(rinfo, RestrictInfo));
@ -6414,7 +6416,7 @@ gincostestimate(PG_FUNCTION_ARGS)
} }
else else
{ {
elog(ERROR, "Could not match index to operand"); elog(ERROR, "could not match index to operand");
operand = NULL; /* keep compiler quiet */ operand = NULL; /* keep compiler quiet */
} }
@ -6443,42 +6445,43 @@ gincostestimate(PG_FUNCTION_ARGS)
/* /*
* Get the operator's strategy number and declared input data types * Get the operator's strategy number and declared input data types
* within the index opfamily. * within the index opfamily. (We don't need the latter, but we
* use get_op_opfamily_properties because it will throw error if
* it fails to find a matching pg_amop entry.)
*/ */
get_op_opfamily_properties(clause_op, index->opfamily[indexcol], false, get_op_opfamily_properties(clause_op, index->opfamily[indexcol], false,
&strategy_op, &lefttype, &righttype); &strategy_op, &lefttype, &righttype);
/* /*
* GIN (like GiST) always has lefttype == righttype in pg_amproc * GIN always uses the "default" support functions, which are those
* and they are equal to type Oid on which index was created/designed * with lefttype == righttype == the opclass' opcintype (see
* IndexSupportInitialize in relcache.c).
*/ */
extractProcOid = get_opfamily_proc(index->opfamily[indexcol], extractProcOid = get_opfamily_proc(index->opfamily[indexcol],
lefttype, lefttype, index->opcintype[indexcol],
index->opcintype[indexcol],
GIN_EXTRACTQUERY_PROC); GIN_EXTRACTQUERY_PROC);
if (!OidIsValid(extractProcOid)) if (!OidIsValid(extractProcOid))
{ {
/* probably shouldn't happen, but cope sanely if so */ /* should not happen; throw same error as index_getprocinfo */
searchEntriesInQuals++; elog(ERROR, "missing support function %d for attribute %d of index \"%s\"",
continue; GIN_EXTRACTQUERY_PROC, indexcol+1,
get_rel_name(index->indexoid));
} }
OidFunctionCall5(extractProcOid, OidFunctionCall7(extractProcOid,
((Const*)operand)->constvalue, ((Const*) operand)->constvalue,
PointerGetDatum(&nentries), PointerGetDatum(&nentries),
UInt16GetDatum(strategy_op), UInt16GetDatum(strategy_op),
PointerGetDatum(&partial_matches), PointerGetDatum(&partial_matches),
PointerGetDatum(&extra_data)); PointerGetDatum(&extra_data),
PointerGetDatum(&nullFlags),
PointerGetDatum(&searchMode));
if (nentries == 0) if (nentries <= 0 && searchMode == GIN_SEARCH_MODE_DEFAULT)
{ {
nfullscan++; /* No match is possible */
}
else if (nentries < 0)
{
/*
* GIN_EXTRACTQUERY_PROC guarantees that nothing will be found
*/
*indexStartupCost = 0; *indexStartupCost = 0;
*indexTotalCost = 0; *indexTotalCost = 0;
*indexSelectivity = 0; *indexSelectivity = 0;
@ -6486,7 +6489,7 @@ gincostestimate(PG_FUNCTION_ARGS)
} }
else else
{ {
int i; int32 i;
for (i=0; i<nentries; i++) for (i=0; i<nentries; i++)
{ {
@ -6503,10 +6506,28 @@ gincostestimate(PG_FUNCTION_ARGS)
searchEntriesInQuals++; searchEntriesInQuals++;
} }
} }
if (searchMode == GIN_SEARCH_MODE_INCLUDE_EMPTY)
{
/* Treat "include empty" like an exact-match item */
exactEntriesInQuals++;
searchEntriesInQuals++;
}
else if (searchMode != GIN_SEARCH_MODE_DEFAULT)
{
/* It's GIN_SEARCH_MODE_ALL */
haveFullScan = true;
}
} }
if (nfullscan == list_length(indexQuals)) if (haveFullScan || indexQuals == NIL)
{
/*
* Full index scan will be required. We treat this as if every key in
* the index had been listed in the query; is that reasonable?
*/
searchEntriesInQuals = numEntries; searchEntriesInQuals = numEntries;
}
/* Will we have more than one iteration of a nestloop scan? */ /* Will we have more than one iteration of a nestloop scan? */
if (outer_rel != NULL && outer_rel->rows > 1) if (outer_rel != NULL && outer_rel->rows > 1)