LCOV - code coverage report
Current view: top level - src/backend/access/gin - ginlogic.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 32.0 % 100 32
Test Date: 2026-01-26 10:56:24 Functions: 42.9 % 7 3
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 9.4 % 32 3

             Branch data     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-2026, 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                 :         139 : 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                 :         139 :         key->recheckCurItem = true;
      72                 :             : 
      73                 :         278 :         return DatumGetBool(FunctionCall8Coll(key->consistentFmgrInfo,
      74                 :         139 :                                                                                   key->collation,
      75                 :         139 :                                                                                   PointerGetDatum(key->entryRes),
      76                 :         139 :                                                                                   UInt16GetDatum(key->strategy),
      77                 :         139 :                                                                                   key->query,
      78                 :         139 :                                                                                   UInt32GetDatum(key->nuserentries),
      79                 :         139 :                                                                                   PointerGetDatum(key->extra_data),
      80                 :         139 :                                                                                   PointerGetDatum(&key->recheckCurItem),
      81                 :         139 :                                                                                   PointerGetDatum(key->queryValues),
      82                 :         139 :                                                                                   PointerGetDatum(key->queryCategories)));
      83                 :             : }
      84                 :             : 
      85                 :             : /*
      86                 :             :  * A helper function for calling a native ternary logic consistent function.
      87                 :             :  */
      88                 :             : static GinTernaryValue
      89                 :      126177 : directTriConsistentFn(GinScanKey key)
      90                 :             : {
      91                 :      252354 :         return DatumGetGinTernaryValue(FunctionCall7Coll(key->triConsistentFmgrInfo,
      92                 :      126177 :                                                                                                          key->collation,
      93                 :      126177 :                                                                                                          PointerGetDatum(key->entryRes),
      94                 :      126177 :                                                                                                          UInt16GetDatum(key->strategy),
      95                 :      126177 :                                                                                                          key->query,
      96                 :      126177 :                                                                                                          UInt32GetDatum(key->nuserentries),
      97                 :      126177 :                                                                                                          PointerGetDatum(key->extra_data),
      98                 :      126177 :                                                                                                          PointerGetDatum(key->queryValues),
      99                 :      126177 :                                                                                                          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                 :           0 :         GinTernaryValue result;
     111                 :             : 
     112                 :           0 :         result = DatumGetGinTernaryValue(FunctionCall7Coll(key->triConsistentFmgrInfo,
     113                 :           0 :                                                                                                            key->collation,
     114                 :           0 :                                                                                                            PointerGetDatum(key->entryRes),
     115                 :           0 :                                                                                                            UInt16GetDatum(key->strategy),
     116                 :           0 :                                                                                                            key->query,
     117                 :           0 :                                                                                                            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                 :           0 : }
     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.  For now that's okay
     144                 :             :  * so long as we restore the entry-time contents before returning.  This may
     145                 :             :  * need revisiting if we ever invent multithreaded GIN scans, though.
     146                 :             :  */
     147                 :             : static GinTernaryValue
     148                 :           0 : shimTriConsistentFn(GinScanKey key)
     149                 :             : {
     150                 :           0 :         int                     nmaybe;
     151                 :           0 :         int                     maybeEntries[MAX_MAYBE_ENTRIES];
     152                 :           0 :         int                     i;
     153                 :           0 :         bool            boolResult;
     154                 :           0 :         bool            recheck;
     155                 :           0 :         GinTernaryValue curResult;
     156                 :             : 
     157                 :             :         /*
     158                 :             :          * Count how many MAYBE inputs there are, and store their indexes in
     159                 :             :          * maybeEntries. If there are too many MAYBE inputs, it's not feasible to
     160                 :             :          * test all combinations, so give up and return MAYBE.
     161                 :             :          */
     162                 :           0 :         nmaybe = 0;
     163         [ #  # ]:           0 :         for (i = 0; i < key->nentries; i++)
     164                 :             :         {
     165         [ #  # ]:           0 :                 if (key->entryRes[i] == GIN_MAYBE)
     166                 :             :                 {
     167         [ #  # ]:           0 :                         if (nmaybe >= MAX_MAYBE_ENTRIES)
     168                 :           0 :                                 return GIN_MAYBE;
     169                 :           0 :                         maybeEntries[nmaybe++] = i;
     170                 :           0 :                 }
     171                 :           0 :         }
     172                 :             : 
     173                 :             :         /*
     174                 :             :          * If none of the inputs were MAYBE, we can just call the consistent
     175                 :             :          * function as-is.
     176                 :             :          */
     177         [ #  # ]:           0 :         if (nmaybe == 0)
     178                 :           0 :                 return directBoolConsistentFn(key);
     179                 :             : 
     180                 :             :         /* First call consistent function with all the maybe-inputs set FALSE */
     181         [ #  # ]:           0 :         for (i = 0; i < nmaybe; i++)
     182                 :           0 :                 key->entryRes[maybeEntries[i]] = GIN_FALSE;
     183                 :           0 :         curResult = directBoolConsistentFn(key);
     184                 :           0 :         recheck = key->recheckCurItem;
     185                 :             : 
     186                 :           0 :         for (;;)
     187                 :             :         {
     188                 :             :                 /* Twiddle the entries for next combination. */
     189         [ #  # ]:           0 :                 for (i = 0; i < nmaybe; i++)
     190                 :             :                 {
     191         [ #  # ]:           0 :                         if (key->entryRes[maybeEntries[i]] == GIN_FALSE)
     192                 :             :                         {
     193                 :           0 :                                 key->entryRes[maybeEntries[i]] = GIN_TRUE;
     194                 :           0 :                                 break;
     195                 :             :                         }
     196                 :             :                         else
     197                 :           0 :                                 key->entryRes[maybeEntries[i]] = GIN_FALSE;
     198                 :           0 :                 }
     199         [ #  # ]:           0 :                 if (i == nmaybe)
     200                 :           0 :                         break;
     201                 :             : 
     202                 :           0 :                 boolResult = directBoolConsistentFn(key);
     203                 :           0 :                 recheck |= key->recheckCurItem;
     204                 :             : 
     205         [ #  # ]:           0 :                 if (curResult != boolResult)
     206                 :             :                 {
     207                 :           0 :                         curResult = GIN_MAYBE;
     208                 :           0 :                         break;
     209                 :             :                 }
     210                 :             :         }
     211                 :             : 
     212                 :             :         /* TRUE with recheck is taken to mean MAYBE */
     213   [ #  #  #  # ]:           0 :         if (curResult == GIN_TRUE && recheck)
     214                 :           0 :                 curResult = GIN_MAYBE;
     215                 :             : 
     216                 :             :         /* We must restore the original state of the entryRes array */
     217         [ #  # ]:           0 :         for (i = 0; i < nmaybe; i++)
     218                 :           0 :                 key->entryRes[maybeEntries[i]] = GIN_MAYBE;
     219                 :             : 
     220                 :           0 :         return curResult;
     221                 :           0 : }
     222                 :             : 
     223                 :             : /*
     224                 :             :  * Set up the implementation of the consistent functions for a scan key.
     225                 :             :  */
     226                 :             : void
     227                 :         192 : ginInitConsistentFunction(GinState *ginstate, GinScanKey key)
     228                 :             : {
     229         [ -  + ]:         192 :         if (key->searchMode == GIN_SEARCH_MODE_EVERYTHING)
     230                 :             :         {
     231                 :           0 :                 key->boolConsistentFn = trueConsistentFn;
     232                 :           0 :                 key->triConsistentFn = trueTriConsistentFn;
     233                 :           0 :         }
     234                 :             :         else
     235                 :             :         {
     236                 :         192 :                 key->consistentFmgrInfo = &ginstate->consistentFn[key->attnum - 1];
     237                 :         192 :                 key->triConsistentFmgrInfo = &ginstate->triConsistentFn[key->attnum - 1];
     238                 :         192 :                 key->collation = ginstate->supportCollation[key->attnum - 1];
     239                 :             : 
     240         [ +  - ]:         192 :                 if (OidIsValid(ginstate->consistentFn[key->attnum - 1].fn_oid))
     241                 :         192 :                         key->boolConsistentFn = directBoolConsistentFn;
     242                 :             :                 else
     243                 :           0 :                         key->boolConsistentFn = shimBoolConsistentFn;
     244                 :             : 
     245         [ +  - ]:         192 :                 if (OidIsValid(ginstate->triConsistentFn[key->attnum - 1].fn_oid))
     246                 :         192 :                         key->triConsistentFn = directTriConsistentFn;
     247                 :             :                 else
     248                 :           0 :                         key->triConsistentFn = shimTriConsistentFn;
     249                 :             :         }
     250                 :         192 : }
        

Generated by: LCOV version 2.3.2-1