LCOV - code coverage report
Current view: top level - src/backend/access/gin - ginlogic.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 53 74 71.6 %
Date: 2024-03-28 09:11:01 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-2024, 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             : 
      39             : 
      40             : /*
      41             :  * Maximum number of MAYBE inputs that shimTriConsistentFn will try to
      42             :  * resolve by calling all combinations.
      43             :  */
      44             : #define MAX_MAYBE_ENTRIES   4
      45             : 
      46             : /*
      47             :  * Dummy consistent functions for an EVERYTHING key.  Just claim it matches.
      48             :  */
      49             : static bool
      50           0 : trueConsistentFn(GinScanKey key)
      51             : {
      52           0 :     key->recheckCurItem = false;
      53           0 :     return true;
      54             : }
      55             : static GinTernaryValue
      56           0 : trueTriConsistentFn(GinScanKey key)
      57             : {
      58           0 :     return GIN_TRUE;
      59             : }
      60             : 
      61             : /*
      62             :  * A helper function for calling a regular, binary logic, consistent function.
      63             :  */
      64             : static bool
      65       37454 : directBoolConsistentFn(GinScanKey key)
      66             : {
      67             :     /*
      68             :      * Initialize recheckCurItem in case the consistentFn doesn't know it
      69             :      * should set it.  The safe assumption in that case is to force recheck.
      70             :      */
      71       37454 :     key->recheckCurItem = true;
      72             : 
      73       74908 :     return DatumGetBool(FunctionCall8Coll(key->consistentFmgrInfo,
      74             :                                           key->collation,
      75       37454 :                                           PointerGetDatum(key->entryRes),
      76       37454 :                                           UInt16GetDatum(key->strategy),
      77             :                                           key->query,
      78             :                                           UInt32GetDatum(key->nuserentries),
      79       37454 :                                           PointerGetDatum(key->extra_data),
      80       37454 :                                           PointerGetDatum(&key->recheckCurItem),
      81       37454 :                                           PointerGetDatum(key->queryValues),
      82       37454 :                                           PointerGetDatum(key->queryCategories)));
      83             : }
      84             : 
      85             : /*
      86             :  * A helper function for calling a native ternary logic consistent function.
      87             :  */
      88             : static GinTernaryValue
      89      965780 : directTriConsistentFn(GinScanKey key)
      90             : {
      91     1931560 :     return DatumGetGinTernaryValue(FunctionCall7Coll(key->triConsistentFmgrInfo,
      92             :                                                      key->collation,
      93      965780 :                                                      PointerGetDatum(key->entryRes),
      94      965780 :                                                      UInt16GetDatum(key->strategy),
      95             :                                                      key->query,
      96             :                                                      UInt32GetDatum(key->nuserentries),
      97      965780 :                                                      PointerGetDatum(key->extra_data),
      98      965780 :                                                      PointerGetDatum(key->queryValues),
      99      965780 :                                                      PointerGetDatum(key->queryCategories)));
     100             : }
     101             : 
     102             : /*
     103             :  * This function implements a binary logic consistency check, using a ternary
     104             :  * logic consistent function provided by the opclass. GIN_MAYBE return value
     105             :  * is interpreted as true with recheck flag.
     106             :  */
     107             : static bool
     108           0 : shimBoolConsistentFn(GinScanKey key)
     109             : {
     110             :     GinTernaryValue result;
     111             : 
     112           0 :     result = DatumGetGinTernaryValue(FunctionCall7Coll(key->triConsistentFmgrInfo,
     113             :                                                        key->collation,
     114           0 :                                                        PointerGetDatum(key->entryRes),
     115           0 :                                                        UInt16GetDatum(key->strategy),
     116             :                                                        key->query,
     117             :                                                        UInt32GetDatum(key->nuserentries),
     118           0 :                                                        PointerGetDatum(key->extra_data),
     119           0 :                                                        PointerGetDatum(key->queryValues),
     120           0 :                                                        PointerGetDatum(key->queryCategories)));
     121           0 :     if (result == GIN_MAYBE)
     122             :     {
     123           0 :         key->recheckCurItem = true;
     124           0 :         return true;
     125             :     }
     126             :     else
     127             :     {
     128           0 :         key->recheckCurItem = false;
     129           0 :         return result;
     130             :     }
     131             : }
     132             : 
     133             : /*
     134             :  * This function implements a tri-state consistency check, using a boolean
     135             :  * consistent function provided by the opclass.
     136             :  *
     137             :  * Our strategy is to call consistentFn with MAYBE inputs replaced with every
     138             :  * combination of TRUE/FALSE. If consistentFn returns the same value for every
     139             :  * combination, that's the overall result. Otherwise, return MAYBE. Testing
     140             :  * every combination is O(n^2), so this is only feasible for a small number of
     141             :  * MAYBE inputs.
     142             :  *
     143             :  * NB: This function modifies the key->entryRes array!
     144             :  */
     145             : static GinTernaryValue
     146       36512 : shimTriConsistentFn(GinScanKey key)
     147             : {
     148             :     int         nmaybe;
     149             :     int         maybeEntries[MAX_MAYBE_ENTRIES];
     150             :     int         i;
     151             :     bool        boolResult;
     152       36512 :     bool        recheck = false;
     153             :     GinTernaryValue curResult;
     154             : 
     155             :     /*
     156             :      * Count how many MAYBE inputs there are, and store their indexes in
     157             :      * maybeEntries. If there are too many MAYBE inputs, it's not feasible to
     158             :      * test all combinations, so give up and return MAYBE.
     159             :      */
     160       36512 :     nmaybe = 0;
     161      141042 :     for (i = 0; i < key->nentries; i++)
     162             :     {
     163      104530 :         if (key->entryRes[i] == GIN_MAYBE)
     164             :         {
     165          70 :             if (nmaybe >= MAX_MAYBE_ENTRIES)
     166           0 :                 return GIN_MAYBE;
     167          70 :             maybeEntries[nmaybe++] = i;
     168             :         }
     169             :     }
     170             : 
     171             :     /*
     172             :      * If none of the inputs were MAYBE, so we can just call consistent
     173             :      * function as is.
     174             :      */
     175       36512 :     if (nmaybe == 0)
     176       36464 :         return directBoolConsistentFn(key);
     177             : 
     178             :     /* First call consistent function with all the maybe-inputs set FALSE */
     179         118 :     for (i = 0; i < nmaybe; i++)
     180          70 :         key->entryRes[maybeEntries[i]] = GIN_FALSE;
     181          48 :     curResult = directBoolConsistentFn(key);
     182             : 
     183             :     for (;;)
     184             :     {
     185             :         /* Twiddle the entries for next combination. */
     186         212 :         for (i = 0; i < nmaybe; i++)
     187             :         {
     188         172 :             if (key->entryRes[maybeEntries[i]] == GIN_FALSE)
     189             :             {
     190          92 :                 key->entryRes[maybeEntries[i]] = GIN_TRUE;
     191          92 :                 break;
     192             :             }
     193             :             else
     194          80 :                 key->entryRes[maybeEntries[i]] = GIN_FALSE;
     195             :         }
     196         132 :         if (i == nmaybe)
     197          40 :             break;
     198             : 
     199          92 :         boolResult = directBoolConsistentFn(key);
     200          92 :         recheck |= key->recheckCurItem;
     201             : 
     202          92 :         if (curResult != boolResult)
     203           8 :             return GIN_MAYBE;
     204             :     }
     205             : 
     206             :     /* TRUE with recheck is taken to mean MAYBE */
     207          40 :     if (curResult == GIN_TRUE && recheck)
     208           6 :         curResult = GIN_MAYBE;
     209             : 
     210          40 :     return curResult;
     211             : }
     212             : 
     213             : /*
     214             :  * Set up the implementation of the consistent functions for a scan key.
     215             :  */
     216             : void
     217        1704 : ginInitConsistentFunction(GinState *ginstate, GinScanKey key)
     218             : {
     219        1704 :     if (key->searchMode == GIN_SEARCH_MODE_EVERYTHING)
     220             :     {
     221           0 :         key->boolConsistentFn = trueConsistentFn;
     222           0 :         key->triConsistentFn = trueTriConsistentFn;
     223             :     }
     224             :     else
     225             :     {
     226        1704 :         key->consistentFmgrInfo = &ginstate->consistentFn[key->attnum - 1];
     227        1704 :         key->triConsistentFmgrInfo = &ginstate->triConsistentFn[key->attnum - 1];
     228        1704 :         key->collation = ginstate->supportCollation[key->attnum - 1];
     229             : 
     230        1704 :         if (OidIsValid(ginstate->consistentFn[key->attnum - 1].fn_oid))
     231        1704 :             key->boolConsistentFn = directBoolConsistentFn;
     232             :         else
     233           0 :             key->boolConsistentFn = shimBoolConsistentFn;
     234             : 
     235        1704 :         if (OidIsValid(ginstate->triConsistentFn[key->attnum - 1].fn_oid))
     236        1364 :             key->triConsistentFn = directTriConsistentFn;
     237             :         else
     238         340 :             key->triConsistentFn = shimTriConsistentFn;
     239             :     }
     240        1704 : }

Generated by: LCOV version 1.14