Fix up gincostestimate for new extractQuery API.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 9 Jan 2011 01:13:33 +0000 (20:13 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 9 Jan 2011 01:26:13 +0000 (20:26 -0500)
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.

src/backend/utils/adt/selfuncs.c

index 05100cdc8a48c6ffd064d464ced880bb311d71b7..7e3ff864c83f48cddeb8ccc64227a882257842bd 100644 (file)
@@ -6281,7 +6281,6 @@ gincostestimate(PG_FUNCTION_ARGS)
    Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(7);
    double     *indexCorrelation = (double *) PG_GETARG_POINTER(8);
    ListCell       *l;
-   int32          nfullscan = 0;
    List           *selectivityQuals;
    double         numPages = index->pages,
                   numTuples = index->tuples;
@@ -6289,6 +6288,7 @@ gincostestimate(PG_FUNCTION_ARGS)
                   numDataPages,
                   numPendingPages,
                   numEntries;
+   bool           haveFullScan = false;
    double         partialEntriesInQuals = 0.0;
    double         searchEntriesInQuals = 0.0;
    double         exactEntriesInQuals = 0.0;
@@ -6394,6 +6394,8 @@ gincostestimate(PG_FUNCTION_ARGS)
        int32           nentries = 0;
        bool            *partial_matches = NULL;
        Pointer         *extra_data = NULL;
+       bool           *nullFlags = NULL;
+       int32           searchMode = GIN_SEARCH_MODE_DEFAULT;
        int             indexcol;
 
        Assert(IsA(rinfo, RestrictInfo));
@@ -6414,7 +6416,7 @@ gincostestimate(PG_FUNCTION_ARGS)
        }
        else
        {
-           elog(ERROR, "Could not match index to operand");
+           elog(ERROR, "could not match index to operand");
            operand = NULL; /* keep compiler quiet */
        }
 
@@ -6443,42 +6445,43 @@ gincostestimate(PG_FUNCTION_ARGS)
 
        /*
         * 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,
                                   &strategy_op, &lefttype, &righttype);
 
        /*
-        * GIN (like GiST) always has lefttype == righttype in pg_amproc
-        * and they are equal to type Oid on which index was created/designed
+        * GIN always uses the "default" support functions, which are those
+        * with lefttype == righttype == the opclass' opcintype (see
+        * IndexSupportInitialize in relcache.c).
         */
        extractProcOid = get_opfamily_proc(index->opfamily[indexcol],
-                                          lefttype, lefttype,
+                                          index->opcintype[indexcol],
+                                          index->opcintype[indexcol],
                                           GIN_EXTRACTQUERY_PROC);
 
        if (!OidIsValid(extractProcOid))
        {
-           /* probably shouldn't happen, but cope sanely if so */
-           searchEntriesInQuals++;
-           continue;
+           /* should not happen; throw same error as index_getprocinfo */
+           elog(ERROR, "missing support function %d for attribute %d of index \"%s\"",
+                GIN_EXTRACTQUERY_PROC, indexcol+1,
+                get_rel_name(index->indexoid));
        }
 
-       OidFunctionCall5(extractProcOid,
-                        ((Const*)operand)->constvalue,
+       OidFunctionCall7(extractProcOid,
+                        ((Const*) operand)->constvalue,
                         PointerGetDatum(&nentries),
                         UInt16GetDatum(strategy_op),
                         PointerGetDatum(&partial_matches),
-                        PointerGetDatum(&extra_data));
+                        PointerGetDatum(&extra_data),
+                        PointerGetDatum(&nullFlags),
+                        PointerGetDatum(&searchMode));
 
-       if (nentries == 0)
-       {
-           nfullscan++;
-       }
-       else if (nentries < 0)
+       if (nentries <= 0 && searchMode == GIN_SEARCH_MODE_DEFAULT)
        {
-           /*
-            * GIN_EXTRACTQUERY_PROC guarantees that nothing will be found
-            */
+           /* No match is possible */
            *indexStartupCost = 0;
            *indexTotalCost = 0;
            *indexSelectivity = 0;
@@ -6486,7 +6489,7 @@ gincostestimate(PG_FUNCTION_ARGS)
        }
        else
        {
-           int     i;
+           int32   i;
 
            for (i=0; i<nentries; i++)
            {
@@ -6503,10 +6506,28 @@ gincostestimate(PG_FUNCTION_ARGS)
                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;
+   }
 
    /* Will we have more than one iteration of a nestloop scan? */
    if (outer_rel != NULL && outer_rel->rows > 1)