LCOV - code coverage report
Current view: top level - src/backend/access/gin - ginlogic.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 42 58 72.4 %
Date: 2019-11-15 23:07:02 Functions: 4 7 57.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * ginlogic.c
       4             :  *    routines for performing binary- and ternary-logic consistent checks.
       5             :  *
       6             :  * A GIN operator class can provide a boolean or ternary consistent
       7             :  * function, or both.  This file provides both boolean and ternary
       8             :  * interfaces to the rest of the GIN code, even if only one of them is
       9             :  * implemented by the opclass.
      10             :  *
      11             :  * Providing a boolean interface when the opclass implements only the
      12             :  * ternary function is straightforward - just call the ternary function
      13             :  * with the check-array as is, and map the GIN_TRUE, GIN_FALSE, GIN_MAYBE
      14             :  * return codes to TRUE, FALSE and TRUE+recheck, respectively.  Providing
      15             :  * a ternary interface when the opclass only implements a boolean function
      16             :  * is implemented by calling the boolean function many times, with all the
      17             :  * MAYBE arguments set to all combinations of TRUE and FALSE (up to a
      18             :  * certain number of MAYBE arguments).
      19             :  *
      20             :  * (A boolean function is enough to determine if an item matches, but a
      21             :  * GIN scan can apply various optimizations if it can determine that an
      22             :  * item matches or doesn't match, even if it doesn't know if some of the
      23             :  * keys are present or not.  That's what the ternary consistent function
      24             :  * is used for.)
      25             :  *
      26             :  *
      27             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
      28             :  * Portions Copyright (c) 1994, Regents of the University of California
      29             :  *
      30             :  * IDENTIFICATION
      31             :  *          src/backend/access/gin/ginlogic.c
      32             :  *-------------------------------------------------------------------------
      33             :  */
      34             : 
      35             : #include "postgres.h"
      36             : 
      37             : #include "access/gin_private.h"
      38             : #include "access/reloptions.h"
      39             : #include "catalog/pg_collation.h"
      40             : #include "catalog/pg_type.h"
      41             : #include "miscadmin.h"
      42             : #include "storage/indexfsm.h"
      43             : #include "storage/lmgr.h"
      44             : 
      45             : 
      46             : /*
      47             :  * Maximum number of MAYBE inputs that shimTriConsistentFn will try to
      48             :  * resolve by calling all combinations.
      49             :  */
      50             : #define MAX_MAYBE_ENTRIES   4
      51             : 
      52             : /*
      53             :  * Dummy consistent functions for an EVERYTHING key.  Just claim it matches.
      54             :  */
      55             : static bool
      56           0 : trueConsistentFn(GinScanKey key)
      57             : {
      58           0 :     key->recheckCurItem = false;
      59           0 :     return true;
      60             : }
      61             : static GinTernaryValue
      62           0 : trueTriConsistentFn(GinScanKey key)
      63             : {
      64           0 :     return GIN_TRUE;
      65             : }
      66             : 
      67             : /*
      68             :  * A helper function for calling a regular, binary logic, consistent function.
      69             :  */
      70             : static bool
      71       36590 : directBoolConsistentFn(GinScanKey key)
      72             : {
      73             :     /*
      74             :      * Initialize recheckCurItem in case the consistentFn doesn't know it
      75             :      * should set it.  The safe assumption in that case is to force recheck.
      76             :      */
      77       36590 :     key->recheckCurItem = true;
      78             : 
      79       36590 :     return DatumGetBool(FunctionCall8Coll(key->consistentFmgrInfo,
      80             :                                           key->collation,
      81             :                                           PointerGetDatum(key->entryRes),
      82             :                                           UInt16GetDatum(key->strategy),
      83             :                                           key->query,
      84             :                                           UInt32GetDatum(key->nuserentries),
      85             :                                           PointerGetDatum(key->extra_data),
      86             :                                           PointerGetDatum(&key->recheckCurItem),
      87             :                                           PointerGetDatum(key->queryValues),
      88             :                                           PointerGetDatum(key->queryCategories)));
      89             : }
      90             : 
      91             : /*
      92             :  * A helper function for calling a native ternary logic consistent function.
      93             :  */
      94             : static GinTernaryValue
      95      443556 : directTriConsistentFn(GinScanKey key)
      96             : {
      97      443556 :     return DatumGetGinTernaryValue(FunctionCall7Coll(
      98             :                                                      key->triConsistentFmgrInfo,
      99             :                                                      key->collation,
     100             :                                                      PointerGetDatum(key->entryRes),
     101             :                                                      UInt16GetDatum(key->strategy),
     102             :                                                      key->query,
     103             :                                                      UInt32GetDatum(key->nuserentries),
     104             :                                                      PointerGetDatum(key->extra_data),
     105             :                                                      PointerGetDatum(key->queryValues),
     106             :                                                      PointerGetDatum(key->queryCategories)));
     107             : }
     108             : 
     109             : /*
     110             :  * This function implements a binary logic consistency check, using a ternary
     111             :  * logic consistent function provided by the opclass. GIN_MAYBE return value
     112             :  * is interpreted as true with recheck flag.
     113             :  */
     114             : static bool
     115           0 : shimBoolConsistentFn(GinScanKey key)
     116             : {
     117             :     GinTernaryValue result;
     118             : 
     119           0 :     result = DatumGetGinTernaryValue(FunctionCall7Coll(
     120             :                                                        key->triConsistentFmgrInfo,
     121             :                                                        key->collation,
     122             :                                                        PointerGetDatum(key->entryRes),
     123             :                                                        UInt16GetDatum(key->strategy),
     124             :                                                        key->query,
     125             :                                                        UInt32GetDatum(key->nuserentries),
     126             :                                                        PointerGetDatum(key->extra_data),
     127             :                                                        PointerGetDatum(key->queryValues),
     128             :                                                        PointerGetDatum(key->queryCategories)));
     129           0 :     if (result == GIN_MAYBE)
     130             :     {
     131           0 :         key->recheckCurItem = true;
     132           0 :         return true;
     133             :     }
     134             :     else
     135             :     {
     136           0 :         key->recheckCurItem = false;
     137           0 :         return result;
     138             :     }
     139             : }
     140             : 
     141             : /*
     142             :  * This function implements a tri-state consistency check, using a boolean
     143             :  * consistent function provided by the opclass.
     144             :  *
     145             :  * Our strategy is to call consistentFn with MAYBE inputs replaced with every
     146             :  * combination of TRUE/FALSE. If consistentFn returns the same value for every
     147             :  * combination, that's the overall result. Otherwise, return MAYBE. Testing
     148             :  * every combination is O(n^2), so this is only feasible for a small number of
     149             :  * MAYBE inputs.
     150             :  *
     151             :  * NB: This function modifies the key->entryRes array!
     152             :  */
     153             : static GinTernaryValue
     154       36482 : shimTriConsistentFn(GinScanKey key)
     155             : {
     156             :     int         nmaybe;
     157             :     int         maybeEntries[MAX_MAYBE_ENTRIES];
     158             :     int         i;
     159             :     bool        boolResult;
     160       36482 :     bool        recheck = false;
     161             :     GinTernaryValue curResult;
     162             : 
     163             :     /*
     164             :      * Count how many MAYBE inputs there are, and store their indexes in
     165             :      * maybeEntries. If there are too many MAYBE inputs, it's not feasible to
     166             :      * test all combinations, so give up and return MAYBE.
     167             :      */
     168       36482 :     nmaybe = 0;
     169      140974 :     for (i = 0; i < key->nentries; i++)
     170             :     {
     171      104492 :         if (key->entryRes[i] == GIN_MAYBE)
     172             :         {
     173          70 :             if (nmaybe >= MAX_MAYBE_ENTRIES)
     174           0 :                 return GIN_MAYBE;
     175          70 :             maybeEntries[nmaybe++] = i;
     176             :         }
     177             :     }
     178             : 
     179             :     /*
     180             :      * If none of the inputs were MAYBE, so we can just call consistent
     181             :      * function as is.
     182             :      */
     183       36482 :     if (nmaybe == 0)
     184       36434 :         return directBoolConsistentFn(key);
     185             : 
     186             :     /* First call consistent function with all the maybe-inputs set FALSE */
     187         118 :     for (i = 0; i < nmaybe; i++)
     188          70 :         key->entryRes[maybeEntries[i]] = GIN_FALSE;
     189          48 :     curResult = directBoolConsistentFn(key);
     190             : 
     191             :     for (;;)
     192             :     {
     193             :         /* Twiddle the entries for next combination. */
     194         296 :         for (i = 0; i < nmaybe; i++)
     195             :         {
     196         172 :             if (key->entryRes[maybeEntries[i]] == GIN_FALSE)
     197             :             {
     198          92 :                 key->entryRes[maybeEntries[i]] = GIN_TRUE;
     199          92 :                 break;
     200             :             }
     201             :             else
     202          80 :                 key->entryRes[maybeEntries[i]] = GIN_FALSE;
     203             :         }
     204         132 :         if (i == nmaybe)
     205          40 :             break;
     206             : 
     207          92 :         boolResult = directBoolConsistentFn(key);
     208          92 :         recheck |= key->recheckCurItem;
     209             : 
     210          92 :         if (curResult != boolResult)
     211           8 :             return GIN_MAYBE;
     212             :     }
     213             : 
     214             :     /* TRUE with recheck is taken to mean MAYBE */
     215          40 :     if (curResult == GIN_TRUE && recheck)
     216           6 :         curResult = GIN_MAYBE;
     217             : 
     218          40 :     return curResult;
     219             : }
     220             : 
     221             : /*
     222             :  * Set up the implementation of the consistent functions for a scan key.
     223             :  */
     224             : void
     225        1010 : ginInitConsistentFunction(GinState *ginstate, GinScanKey key)
     226             : {
     227        1010 :     if (key->searchMode == GIN_SEARCH_MODE_EVERYTHING)
     228             :     {
     229           0 :         key->boolConsistentFn = trueConsistentFn;
     230           0 :         key->triConsistentFn = trueTriConsistentFn;
     231             :     }
     232             :     else
     233             :     {
     234        1010 :         key->consistentFmgrInfo = &ginstate->consistentFn[key->attnum - 1];
     235        1010 :         key->triConsistentFmgrInfo = &ginstate->triConsistentFn[key->attnum - 1];
     236        1010 :         key->collation = ginstate->supportCollation[key->attnum - 1];
     237             : 
     238        1010 :         if (OidIsValid(ginstate->consistentFn[key->attnum - 1].fn_oid))
     239        1010 :             key->boolConsistentFn = directBoolConsistentFn;
     240             :         else
     241           0 :             key->boolConsistentFn = shimBoolConsistentFn;
     242             : 
     243        1010 :         if (OidIsValid(ginstate->triConsistentFn[key->attnum - 1].fn_oid))
     244         674 :             key->triConsistentFn = directTriConsistentFn;
     245             :         else
     246         336 :             key->triConsistentFn = shimTriConsistentFn;
     247             :     }
     248        1010 : }

Generated by: LCOV version 1.13