LCOV - differential code coverage report
Current view: top level - src/backend/access/gin - ginscan.c (source / functions) Coverage Total Hit UIC UBC GIC GNC CBC DCB
Current: ba12a202ce1b5581dc0ed149cf3f637d7897ad5d vs 2866d8c7dbfc9d882a7d80fef93fbbe763709932 Lines: 94.6 % 203 192 11 7 185 9
Current Date: 2026-08-27 14:31:44 +0300 Functions: 100.0 % 8 8 1 7
Baseline: lcov-20260827-baseline Branches: 76.3 % 114 87 1 26 1 6 80
Baseline Date: 2026-08-27 14:31:58 +0300 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 100.0 % 4 4 4
(30,360] days: 100.0 % 8 8 3 5
(360..) days: 94.2 % 191 180 11 180
Function coverage date bins:
(360..) days: 100.0 % 8 8 1 7
Branch coverage date bins:
(30,360] days: 100.0 % 6 6 6
(360..) days: 75.0 % 108 81 1 26 1 80

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * ginscan.c
                                  4                 :                :  *    routines to manage scans of inverted index relations
                                  5                 :                :  *
                                  6                 :                :  *
                                  7                 :                :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
                                  8                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  9                 :                :  *
                                 10                 :                :  * IDENTIFICATION
                                 11                 :                :  *          src/backend/access/gin/ginscan.c
                                 12                 :                :  *-------------------------------------------------------------------------
                                 13                 :                :  */
                                 14                 :                : 
                                 15                 :                : #include "postgres.h"
                                 16                 :                : 
                                 17                 :                : #include "access/gin_private.h"
                                 18                 :                : #include "access/relscan.h"
                                 19                 :                : #include "executor/instrument_node.h"
                                 20                 :                : #include "pgstat.h"
                                 21                 :                : #include "utils/memutils.h"
                                 22                 :                : #include "utils/rel.h"
                                 23                 :                : 
                                 24                 :                : 
                                 25                 :                : IndexScanDesc
 3875 tgl@sss.pgh.pa.us          26                 :CBC        1148 : ginbeginscan(Relation rel, int nkeys, int norderbys)
                                 27                 :                : {
                                 28                 :                :     IndexScanDesc scan;
                                 29                 :                :     GinScanOpaque so;
                                 30                 :                : 
                                 31                 :                :     /* no order by operators allowed */
 5747                            32         [ -  + ]:           1148 :     Assert(norderbys == 0);
                                 33                 :                : 
                                 34                 :           1148 :     scan = RelationGetIndexScan(rel, nkeys, norderbys);
                                 35                 :                : 
                                 36                 :                :     /* allocate private workspace */
  260 michael@paquier.xyz        37                 :           1148 :     so = (GinScanOpaque) palloc_object(GinScanOpaqueData);
 5747 tgl@sss.pgh.pa.us          38                 :           1148 :     so->keys = NULL;
                                 39                 :           1148 :     so->nkeys = 0;
                                 40                 :           1148 :     so->tempCtx = AllocSetContextCreate(CurrentMemoryContext,
                                 41                 :                :                                         "Gin scan temporary context",
                                 42                 :                :                                         ALLOCSET_DEFAULT_SIZES);
 4222 heikki.linnakangas@i       43                 :           1148 :     so->keyCtx = AllocSetContextCreate(CurrentMemoryContext,
                                 44                 :                :                                        "Gin scan key context",
                                 45                 :                :                                        ALLOCSET_DEFAULT_SIZES);
 5747 tgl@sss.pgh.pa.us          46                 :           1148 :     initGinState(&so->ginstate, scan->indexRelation);
                                 47                 :                : 
                                 48                 :           1148 :     scan->opaque = so;
                                 49                 :                : 
 3875                            50                 :           1148 :     return scan;
                                 51                 :                : }
                                 52                 :                : 
                                 53                 :                : /*
                                 54                 :                :  * Create a new GinScanEntry, unless an equivalent one already exists,
                                 55                 :                :  * in which case just return it
                                 56                 :                :  */
                                 57                 :                : static GinScanEntry
 5710                            58                 :           3828 : ginFillScanEntry(GinScanOpaque so, OffsetNumber attnum,
                                 59                 :                :                  StrategyNumber strategy, int32 searchMode,
                                 60                 :                :                  Datum queryKey, GinNullCategory queryCategory,
                                 61                 :                :                  bool isPartialMatch, Pointer extra_data)
                                 62                 :                : {
                                 63                 :           3828 :     GinState   *ginstate = &so->ginstate;
                                 64                 :                :     GinScanEntry scanEntry;
                                 65                 :                :     uint32      i;
                                 66                 :                : 
                                 67                 :                :     /*
                                 68                 :                :      * Look for an existing equivalent entry.
                                 69                 :                :      *
                                 70                 :                :      * Entries with non-null extra_data are never considered identical, since
                                 71                 :                :      * we can't know exactly what the opclass might be doing with that.
                                 72                 :                :      *
                                 73                 :                :      * Also, give up de-duplication once we have 100 entries.  That avoids
                                 74                 :                :      * spending O(N^2) time on probably-fruitless de-duplication of large
                                 75                 :                :      * search-key sets.  The threshold of 100 is arbitrary but matches
                                 76                 :                :      * predtest.c's threshold for what's a large array.
                                 77                 :                :      */
  539                            78   [ +  +  +  + ]:           3828 :     if (extra_data == NULL && so->totalentries < 100)
                                 79                 :                :     {
 5710                            80         [ +  + ]:          28398 :         for (i = 0; i < so->totalentries; i++)
                                 81                 :                :         {
                                 82                 :          26685 :             GinScanEntry prevEntry = so->entries[i];
                                 83                 :                : 
                                 84         [ +  + ]:          26685 :             if (prevEntry->extra_data == NULL &&
                                 85         [ +  - ]:          26485 :                 prevEntry->isPartialMatch == isPartialMatch &&
                                 86         [ +  + ]:          26485 :                 prevEntry->strategy == strategy &&
                                 87         [ +  - ]:          26394 :                 prevEntry->searchMode == searchMode &&
                                 88   [ +  +  -  + ]:          52772 :                 prevEntry->attnum == attnum &&
                                 89                 :          26378 :                 ginCompareEntries(ginstate, attnum,
                                 90                 :                :                                   prevEntry->queryKey,
                                 91                 :          26378 :                                   prevEntry->queryCategory,
                                 92                 :                :                                   queryKey,
                                 93                 :                :                                   queryCategory) == 0)
                                 94                 :                :             {
                                 95                 :                :                 /* Successful match */
 5710 tgl@sss.pgh.pa.us          96                 :UBC           0 :                 return prevEntry;
                                 97                 :                :             }
                                 98                 :                :         }
                                 99                 :                :     }
                                100                 :                : 
                                101                 :                :     /* Nope, create a new entry */
  260 michael@paquier.xyz       102                 :CBC        3828 :     scanEntry = palloc_object(GinScanEntryData);
 5710 tgl@sss.pgh.pa.us         103                 :           3828 :     scanEntry->queryKey = queryKey;
                                104                 :           3828 :     scanEntry->queryCategory = queryCategory;
                                105                 :           3828 :     scanEntry->isPartialMatch = isPartialMatch;
                                106                 :           3828 :     scanEntry->extra_data = extra_data;
                                107                 :           3828 :     scanEntry->strategy = strategy;
                                108                 :           3828 :     scanEntry->searchMode = searchMode;
                                109                 :           3828 :     scanEntry->attnum = attnum;
                                110                 :                : 
                                111                 :           3828 :     scanEntry->buffer = InvalidBuffer;
                                112                 :           3828 :     ItemPointerSetMin(&scanEntry->curItem);
                                113                 :           3828 :     scanEntry->matchBitmap = NULL;
                                114                 :           3828 :     scanEntry->matchIterator = NULL;
  530 melanieplageman@gmai      115                 :           3828 :     scanEntry->matchResult.blockno = InvalidBlockNumber;
  549                           116                 :           3828 :     scanEntry->matchNtuples = -1;
 5710 tgl@sss.pgh.pa.us         117                 :           3828 :     scanEntry->list = NULL;
                                118                 :           3828 :     scanEntry->nlist = 0;
                                119                 :           3828 :     scanEntry->offset = InvalidOffsetNumber;
                                120                 :           3828 :     scanEntry->isFinished = false;
                                121                 :           3828 :     scanEntry->reduceResult = false;
                                122                 :                : 
                                123                 :                :     /* Add it to so's array */
                                124         [ +  + ]:           3828 :     if (so->totalentries >= so->allocentries)
                                125                 :                :     {
                                126                 :             23 :         so->allocentries *= 2;
  260 michael@paquier.xyz       127                 :             23 :         so->entries = repalloc_array(so->entries, GinScanEntry, so->allocentries);
                                128                 :                :     }
 5710 tgl@sss.pgh.pa.us         129                 :           3828 :     so->entries[so->totalentries++] = scanEntry;
                                130                 :                : 
                                131                 :           3828 :     return scanEntry;
                                132                 :                : }
                                133                 :                : 
                                134                 :                : /*
                                135                 :                :  * Append hidden scan entry of given category to the scan key.
                                136                 :                :  *
                                137                 :                :  * NB: this had better be called at most once per scan key, since
                                138                 :                :  * ginFillScanKey leaves room for only one hidden entry.  Currently,
                                139                 :                :  * it seems sufficiently clear that this is true that we don't bother
                                140                 :                :  * with any cross-check logic.
                                141                 :                :  */
                                142                 :                : static void
 2413 akorotkov@postgresql      143                 :            214 : ginScanKeyAddHiddenEntry(GinScanOpaque so, GinScanKey key,
                                144                 :                :                          GinNullCategory queryCategory)
                                145                 :                : {
                                146                 :            214 :     int         i = key->nentries++;
                                147                 :                : 
                                148                 :                :     /* strategy is of no interest because this is not a partial-match item */
                                149                 :            214 :     key->scanEntry[i] = ginFillScanEntry(so, key->attnum,
                                150                 :                :                                          InvalidStrategy, key->searchMode,
                                151                 :                :                                          (Datum) 0, queryCategory,
                                152                 :                :                                          false, NULL);
                                153                 :            214 : }
                                154                 :                : 
                                155                 :                : /*
                                156                 :                :  * Initialize the next GinScanKey using the output from the extractQueryFn
                                157                 :                :  */
                                158                 :                : static void
 5710 tgl@sss.pgh.pa.us         159                 :           1230 : ginFillScanKey(GinScanOpaque so, OffsetNumber attnum,
                                160                 :                :                StrategyNumber strategy, int32 searchMode,
                                161                 :                :                Datum query, uint32 nQueryValues,
                                162                 :                :                Datum *queryValues, GinNullCategory *queryCategories,
                                163                 :                :                bool *partial_matches, Pointer *extra_data)
                                164                 :                : {
                                165                 :           1230 :     GinScanKey  key = &(so->keys[so->nkeys++]);
                                166                 :           1230 :     GinState   *ginstate = &so->ginstate;
                                167                 :                :     uint32      i;
                                168                 :                : 
 5711                           169                 :           1230 :     key->nentries = nQueryValues;
 2413 akorotkov@postgresql      170                 :           1230 :     key->nuserentries = nQueryValues;
                                171                 :                : 
                                172                 :                :     /* Allocate one extra array slot for possible "hidden" entry */
  260 michael@paquier.xyz       173                 :           1230 :     key->scanEntry = palloc_array(GinScanEntry, nQueryValues + 1);
                                174                 :           1230 :     key->entryRes = palloc0_array(GinTernaryValue, nQueryValues + 1);
                                175                 :                : 
 5711 tgl@sss.pgh.pa.us         176                 :           1230 :     key->query = query;
                                177                 :           1230 :     key->queryValues = queryValues;
                                178                 :           1230 :     key->queryCategories = queryCategories;
                                179                 :           1230 :     key->extra_data = extra_data;
 7422 teodor@sigaev.ru          180                 :           1230 :     key->strategy = strategy;
 5711 tgl@sss.pgh.pa.us         181                 :           1230 :     key->searchMode = searchMode;
 6621                           182                 :           1230 :     key->attnum = attnum;
                                183                 :                : 
                                184                 :                :     /*
                                185                 :                :      * Initially, scan keys of GIN_SEARCH_MODE_ALL mode are marked
                                186                 :                :      * excludeOnly.  This might get changed later.
                                187                 :                :      */
 2413 akorotkov@postgresql      188                 :           1230 :     key->excludeOnly = (searchMode == GIN_SEARCH_MODE_ALL);
                                189                 :                : 
 5871 tgl@sss.pgh.pa.us         190                 :           1230 :     ItemPointerSetMin(&key->curItem);
 5710                           191                 :           1230 :     key->curItemMatches = false;
                                192                 :           1230 :     key->recheckCurItem = false;
                                193                 :           1230 :     key->isFinished = false;
 4227 heikki.linnakangas@i      194                 :           1230 :     key->nrequired = 0;
                                195                 :           1230 :     key->nadditional = 0;
                                196                 :           1230 :     key->requiredEntries = NULL;
                                197                 :           1230 :     key->additionalEntries = NULL;
                                198                 :                : 
 4584                           199                 :           1230 :     ginInitConsistentFunction(ginstate, key);
                                200                 :                : 
                                201                 :                :     /* Set up normal scan entries using extractQueryFn's outputs */
 5711 tgl@sss.pgh.pa.us         202         [ +  + ]:           4844 :     for (i = 0; i < nQueryValues; i++)
                                203                 :                :     {
                                204                 :                :         Datum       queryKey;
                                205                 :                :         GinNullCategory queryCategory;
                                206                 :                :         bool        isPartialMatch;
                                207                 :                :         Pointer     this_extra;
                                208                 :                : 
 2413 akorotkov@postgresql      209                 :           3614 :         queryKey = queryValues[i];
                                210                 :           3614 :         queryCategory = queryCategories[i];
                                211                 :           3614 :         isPartialMatch =
                                212         [ +  - ]:            562 :             (ginstate->canPartialMatch[attnum - 1] && partial_matches)
                                213         [ +  + ]:           4176 :             ? partial_matches[i] : false;
                                214         [ +  + ]:           3614 :         this_extra = (extra_data) ? extra_data[i] : NULL;
                                215                 :                : 
 5710 tgl@sss.pgh.pa.us         216                 :           3614 :         key->scanEntry[i] = ginFillScanEntry(so, attnum,
                                217                 :                :                                              strategy, searchMode,
                                218                 :                :                                              queryKey, queryCategory,
                                219                 :                :                                              isPartialMatch, this_extra);
                                220                 :                :     }
                                221                 :                : 
                                222                 :                :     /*
                                223                 :                :      * For GIN_SEARCH_MODE_INCLUDE_EMPTY and GIN_SEARCH_MODE_EVERYTHING search
                                224                 :                :      * modes, we add the "hidden" entry immediately.  GIN_SEARCH_MODE_ALL is
                                225                 :                :      * handled later, since we might be able to omit the hidden entry for it.
                                226                 :                :      */
 2413 akorotkov@postgresql      227         [ +  + ]:           1230 :     if (searchMode == GIN_SEARCH_MODE_INCLUDE_EMPTY)
                                228                 :             29 :         ginScanKeyAddHiddenEntry(so, key, GIN_CAT_EMPTY_ITEM);
                                229         [ -  + ]:           1201 :     else if (searchMode == GIN_SEARCH_MODE_EVERYTHING)
 2413 akorotkov@postgresql      230                 :UBC           0 :         ginScanKeyAddHiddenEntry(so, key, GIN_CAT_EMPTY_QUERY);
 7422 teodor@sigaev.ru          231                 :CBC        1230 : }
                                232                 :                : 
                                233                 :                : /*
                                234                 :                :  * Release current scan keys, if any.
                                235                 :                :  */
                                236                 :                : void
 4227 heikki.linnakangas@i      237                 :           3452 : ginFreeScanKeys(GinScanOpaque so)
                                238                 :                : {
                                239                 :                :     uint32      i;
                                240                 :                : 
 5710 tgl@sss.pgh.pa.us         241         [ +  + ]:           3452 :     if (so->keys == NULL)
 7422 teodor@sigaev.ru          242                 :           2300 :         return;
                                243                 :                : 
 5710 tgl@sss.pgh.pa.us         244         [ +  + ]:           4980 :     for (i = 0; i < so->totalentries; i++)
                                245                 :                :     {
                                246                 :           3828 :         GinScanEntry entry = so->entries[i];
                                247                 :                : 
                                248         [ -  + ]:           3828 :         if (entry->buffer != InvalidBuffer)
 5710 tgl@sss.pgh.pa.us         249                 :UBC           0 :             ReleaseBuffer(entry->buffer);
 3819 tgl@sss.pgh.pa.us         250         [ +  + ]:CBC        3828 :         if (entry->list)
                                251                 :           2428 :             pfree(entry->list);
 5710                           252         [ -  + ]:           3828 :         if (entry->matchIterator)
  617 melanieplageman@gmai      253                 :UBC           0 :             tbm_end_private_iterate(entry->matchIterator);
 5710 tgl@sss.pgh.pa.us         254         [ +  + ]:CBC        3828 :         if (entry->matchBitmap)
                                255                 :            486 :             tbm_free(entry->matchBitmap);
                                256                 :                :     }
                                257                 :                : 
 1016 nathan@postgresql.or      258                 :           1152 :     MemoryContextReset(so->keyCtx);
                                259                 :                : 
 4222 heikki.linnakangas@i      260                 :           1152 :     so->keys = NULL;
                                261                 :           1152 :     so->nkeys = 0;
 5710 tgl@sss.pgh.pa.us         262                 :           1152 :     so->entries = NULL;
                                263                 :           1152 :     so->totalentries = 0;
                                264                 :                : }
                                265                 :                : 
                                266                 :                : void
 5793                           267                 :           1152 : ginNewScanKey(IndexScanDesc scan)
                                268                 :                : {
 7267 bruce@momjian.us          269                 :           1152 :     ScanKey     scankey = scan->keyData;
 7422 teodor@sigaev.ru          270                 :           1152 :     GinScanOpaque so = (GinScanOpaque) scan->opaque;
                                271                 :                :     int         numExcludeOnly;
 5711 tgl@sss.pgh.pa.us         272                 :           1152 :     bool        hasNullQuery = false;
 2413 akorotkov@postgresql      273                 :           1152 :     bool        attrHasNormalScan[INDEX_MAX_KEYS] = {false};
                                274                 :                :     MemoryContext oldCtx;
                                275                 :                : 
                                276                 :                :     /*
                                277                 :                :      * Allocate all the scan key information in the key context. (If
                                278                 :                :      * extractQuery leaks anything there, it won't be reset until the end of
                                279                 :                :      * scan or rescan, but that's OK.)
                                280                 :                :      */
 4222 heikki.linnakangas@i      281                 :           1152 :     oldCtx = MemoryContextSwitchTo(so->keyCtx);
                                282                 :                : 
                                283                 :                :     /* if no scan keys provided, allocate extra EVERYTHING GinScanKey */
   10 michael@paquier.xyz       284                 :GNC        1152 :     so->keys = palloc_array(GinScanKeyData, Max(scan->numberOfKeys, 1));
 5710 tgl@sss.pgh.pa.us         285                 :CBC        1152 :     so->nkeys = 0;
                                286                 :                : 
                                287                 :                :     /* initialize expansible array of GinScanEntry pointers */
                                288                 :           1152 :     so->totalentries = 0;
                                289                 :           1152 :     so->allocentries = 32;
   10 michael@paquier.xyz       290                 :GNC        1152 :     so->entries = palloc_array(GinScanEntry, so->allocentries);
                                291                 :                : 
 7148 teodor@sigaev.ru          292                 :CBC        1152 :     so->isVoidRes = false;
                                293                 :                : 
   47 peter@eisentraut.org      294         [ +  + ]:GNC        2382 :     for (int i = 0; i < scan->numberOfKeys; i++)
                                295                 :                :     {
 6364 tgl@sss.pgh.pa.us         296                 :CBC        1238 :         ScanKey     skey = &scankey[i];
                                297                 :                :         Datum      *queryValues;
 5711                           298                 :           1238 :         int32       nQueryValues = 0;
 6286 bruce@momjian.us          299                 :           1238 :         bool       *partial_matches = NULL;
                                300                 :           1238 :         Pointer    *extra_data = NULL;
 5711 tgl@sss.pgh.pa.us         301                 :           1238 :         bool       *nullFlags = NULL;
                                302                 :                :         GinNullCategory *categories;
                                303                 :           1238 :         int32       searchMode = GIN_SEARCH_MODE_DEFAULT;
                                304                 :                : 
                                305                 :                :         /*
                                306                 :                :          * We assume that GIN-indexable operators are strict, so a null query
                                307                 :                :          * argument means an unsatisfiable query.
                                308                 :                :          */
 6364                           309         [ -  + ]:           1238 :         if (skey->sk_flags & SK_ISNULL)
                                310                 :                :         {
 6353 teodor@sigaev.ru          311                 :UBC           0 :             so->isVoidRes = true;
 6353 teodor@sigaev.ru          312                 :CBC           8 :             break;
                                313                 :                :         }
                                314                 :                : 
                                315                 :                :         /* OK to call the extractQueryFn */
                                316                 :                :         queryValues = (Datum *)
 5606 tgl@sss.pgh.pa.us         317                 :           1238 :             DatumGetPointer(FunctionCall7Coll(&so->ginstate.extractQueryFn[skey->sk_attno - 1],
 3354                           318                 :           1238 :                                               so->ginstate.supportCollation[skey->sk_attno - 1],
                                319                 :                :                                               skey->sk_argument,
                                320                 :                :                                               PointerGetDatum(&nQueryValues),
                                321                 :           1238 :                                               UInt16GetDatum(skey->sk_strategy),
                                322                 :                :                                               PointerGetDatum(&partial_matches),
                                323                 :                :                                               PointerGetDatum(&extra_data),
                                324                 :                :                                               PointerGetDatum(&nullFlags),
                                325                 :                :                                               PointerGetDatum(&searchMode)));
                                326                 :                : 
                                327                 :                :         /*
                                328                 :                :          * If bogus searchMode is returned, treat as GIN_SEARCH_MODE_ALL; note
                                329                 :                :          * in particular we don't allow extractQueryFn to select
                                330                 :                :          * GIN_SEARCH_MODE_EVERYTHING.
                                331                 :                :          */
 5711                           332         [ +  - ]:           1238 :         if (searchMode < GIN_SEARCH_MODE_DEFAULT ||
                                333         [ -  + ]:           1238 :             searchMode > GIN_SEARCH_MODE_ALL)
 5711 tgl@sss.pgh.pa.us         334                 :UBC           0 :             searchMode = GIN_SEARCH_MODE_ALL;
                                335                 :                : 
                                336                 :                :         /* Non-default modes require the index to have placeholders */
 5711 tgl@sss.pgh.pa.us         337         [ +  + ]:CBC        1238 :         if (searchMode != GIN_SEARCH_MODE_DEFAULT)
                                338                 :            240 :             hasNullQuery = true;
                                339                 :                : 
                                340                 :                :         /*
                                341                 :                :          * In default mode, no keys means an unsatisfiable query.
                                342                 :                :          */
                                343   [ +  +  +  + ]:           1238 :         if (queryValues == NULL || nQueryValues <= 0)
                                344                 :                :         {
                                345         [ +  + ]:            201 :             if (searchMode == GIN_SEARCH_MODE_DEFAULT)
                                346                 :                :             {
                                347                 :              8 :                 so->isVoidRes = true;
                                348                 :              8 :                 break;
                                349                 :                :             }
                                350                 :            193 :             nQueryValues = 0;   /* ensure sane value */
                                351                 :                :         }
                                352                 :                : 
                                353                 :                :         /*
                                354                 :                :          * Create GinNullCategory representation.  If the extractQueryFn
                                355                 :                :          * didn't create a nullFlags array, we assume everything is non-null.
                                356                 :                :          * While at it, detect whether any null keys are present.
                                357                 :                :          */
   10 michael@paquier.xyz       358                 :GNC        1230 :         categories = palloc0_array(GinNullCategory, nQueryValues);
 3166 peter_e@gmx.net           359         [ +  + ]:CBC        1230 :         if (nullFlags)
                                360                 :                :         {
                                361                 :                :             int32       j;
                                362                 :                : 
 5711 tgl@sss.pgh.pa.us         363         [ +  + ]:           2169 :             for (j = 0; j < nQueryValues; j++)
                                364                 :                :             {
                                365         [ -  + ]:           1800 :                 if (nullFlags[j])
                                366                 :                :                 {
 3166 peter_e@gmx.net           367                 :UBC           0 :                     categories[j] = GIN_CAT_NULL_KEY;
 5711 tgl@sss.pgh.pa.us         368                 :              0 :                     hasNullQuery = true;
                                369                 :                :                 }
                                370                 :                :             }
                                371                 :                :         }
                                372                 :                : 
 5710 tgl@sss.pgh.pa.us         373                 :CBC        1230 :         ginFillScanKey(so, skey->sk_attno,
                                374                 :           1230 :                        skey->sk_strategy, searchMode,
                                375                 :                :                        skey->sk_argument, nQueryValues,
                                376                 :                :                        queryValues, categories,
                                377                 :                :                        partial_matches, extra_data);
                                378                 :                : 
                                379                 :                :         /* Remember if we had any non-excludeOnly keys */
 2413 akorotkov@postgresql      380         [ +  + ]:           1230 :         if (searchMode != GIN_SEARCH_MODE_ALL)
                                381                 :           1019 :             attrHasNormalScan[skey->sk_attno - 1] = true;
                                382                 :                :     }
                                383                 :                : 
                                384                 :                :     /*
                                385                 :                :      * Processing GIN_SEARCH_MODE_ALL scan keys requires us to make a second
                                386                 :                :      * pass over the scan keys.  Above we marked each such scan key as
                                387                 :                :      * excludeOnly.  If the involved column has any normal (not excludeOnly)
                                388                 :                :      * scan key as well, then we can leave it like that.  Otherwise, one
                                389                 :                :      * excludeOnly scan key must receive a GIN_CAT_EMPTY_QUERY hidden entry
                                390                 :                :      * and be set to normal (excludeOnly = false).
                                391                 :                :      */
  366 tgl@sss.pgh.pa.us         392                 :           1152 :     numExcludeOnly = 0;
   47 peter@eisentraut.org      393         [ +  + ]:GNC        2382 :     for (uint32 i = 0; i < so->nkeys; i++)
                                394                 :                :     {
 2413 akorotkov@postgresql      395                 :CBC        1230 :         GinScanKey  key = &so->keys[i];
                                396                 :                : 
                                397         [ +  + ]:           1230 :         if (key->searchMode != GIN_SEARCH_MODE_ALL)
                                398                 :           1019 :             continue;
                                399                 :                : 
                                400         [ +  + ]:            211 :         if (!attrHasNormalScan[key->attnum - 1])
                                401                 :                :         {
                                402                 :            185 :             key->excludeOnly = false;
                                403                 :            185 :             ginScanKeyAddHiddenEntry(so, key, GIN_CAT_EMPTY_QUERY);
                                404                 :            185 :             attrHasNormalScan[key->attnum - 1] = true;
                                405                 :                :         }
                                406                 :                :         else
  366 tgl@sss.pgh.pa.us         407                 :             26 :             numExcludeOnly++;
                                408                 :                :     }
                                409                 :                : 
                                410                 :                :     /*
                                411                 :                :      * If we left any excludeOnly scan keys as-is, move them to the end of the
                                412                 :                :      * scan key array: they must appear after normal key(s).
                                413                 :                :      */
                                414         [ +  + ]:           1152 :     if (numExcludeOnly > 0)
                                415                 :                :     {
                                416                 :                :         GinScanKey  tmpkeys;
                                417                 :                :         int         iNormalKey;
                                418                 :                :         int         iExcludeOnly;
                                419                 :                : 
                                420                 :                :         /* We'd better have made at least one normal key */
                                421         [ -  + ]:             26 :         Assert(numExcludeOnly < so->nkeys);
                                422                 :                :         /* Make a temporary array to hold the re-ordered scan keys */
   10 michael@paquier.xyz       423                 :GNC          26 :         tmpkeys = palloc_array(GinScanKeyData, so->nkeys);
                                424                 :                :         /* Re-order the keys ... */
  366 tgl@sss.pgh.pa.us         425                 :CBC          26 :         iNormalKey = 0;
                                426                 :             26 :         iExcludeOnly = so->nkeys - numExcludeOnly;
   47 peter@eisentraut.org      427         [ +  + ]:GNC          94 :         for (uint32 i = 0; i < so->nkeys; i++)
                                428                 :                :         {
  366 tgl@sss.pgh.pa.us         429                 :CBC          68 :             GinScanKey  key = &so->keys[i];
                                430                 :                : 
                                431         [ +  + ]:             68 :             if (key->excludeOnly)
                                432                 :                :             {
                                433                 :             26 :                 memcpy(tmpkeys + iExcludeOnly, key, sizeof(GinScanKeyData));
                                434                 :             26 :                 iExcludeOnly++;
                                435                 :                :             }
                                436                 :                :             else
                                437                 :                :             {
                                438                 :             42 :                 memcpy(tmpkeys + iNormalKey, key, sizeof(GinScanKeyData));
                                439                 :             42 :                 iNormalKey++;
                                440                 :                :             }
                                441                 :                :         }
                                442         [ -  + ]:             26 :         Assert(iNormalKey == so->nkeys - numExcludeOnly);
                                443         [ -  + ]:             26 :         Assert(iExcludeOnly == so->nkeys);
                                444                 :                :         /* ... and copy them back to so->keys[] */
                                445                 :             26 :         memcpy(so->keys, tmpkeys, so->nkeys * sizeof(GinScanKeyData));
                                446                 :             26 :         pfree(tmpkeys);
                                447                 :                :     }
                                448                 :                : 
                                449                 :                :     /*
                                450                 :                :      * If there are no regular scan keys, generate an EVERYTHING scankey to
                                451                 :                :      * drive a full-index scan.
                                452                 :                :      */
 5710                           453   [ +  +  -  + ]:           1152 :     if (so->nkeys == 0 && !so->isVoidRes)
                                454                 :                :     {
 5711 tgl@sss.pgh.pa.us         455                 :UBC           0 :         hasNullQuery = true;
 5710                           456                 :              0 :         ginFillScanKey(so, FirstOffsetNumber,
                                457                 :                :                        InvalidStrategy, GIN_SEARCH_MODE_EVERYTHING,
                                458                 :                :                        (Datum) 0, 0,
                                459                 :                :                        NULL, NULL, NULL, NULL);
                                460                 :                :     }
                                461                 :                : 
                                462                 :                :     /*
                                463                 :                :      * If the index is version 0, it may be missing null and placeholder
                                464                 :                :      * entries, which would render searches for nulls and full-index scans
                                465                 :                :      * unreliable.  Throw an error if so.
                                466                 :                :      */
 5711 tgl@sss.pgh.pa.us         467   [ +  +  +  - ]:CBC        1152 :     if (hasNullQuery && !so->isVoidRes)
                                468                 :                :     {
                                469                 :                :         GinStatsData ginStats;
                                470                 :                : 
                                471                 :            214 :         ginGetStats(scan->indexRelation, &ginStats);
                                472         [ -  + ]:            214 :         if (ginStats.ginVersion < 1)
 5711 tgl@sss.pgh.pa.us         473         [ #  # ]:UBC           0 :             ereport(ERROR,
                                474                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                475                 :                :                      errmsg("old GIN indexes do not support whole-index scans nor searches for nulls"),
                                476                 :                :                      errhint("To fix this, do REINDEX INDEX \"%s\".",
                                477                 :                :                              RelationGetRelationName(scan->indexRelation))));
                                478                 :                :     }
                                479                 :                : 
 4222 heikki.linnakangas@i      480                 :CBC        1152 :     MemoryContextSwitchTo(oldCtx);
                                481                 :                : 
 7032 tgl@sss.pgh.pa.us         482   [ -  +  -  -  :           1152 :     pgstat_count_index_scan(scan->indexRelation);
                                        +  -  -  + ]
  534 pg@bowt.ie                483         [ +  + ]:           1152 :     if (scan->instrument)
                                484                 :             42 :         scan->instrument->nsearches++;
 7422 teodor@sigaev.ru          485                 :           1152 : }
                                486                 :                : 
                                487                 :                : void
 3875 tgl@sss.pgh.pa.us         488                 :           1152 : ginrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
                                489                 :                :           ScanKey orderbys, int norderbys)
                                490                 :                : {
 5747                           491                 :           1152 :     GinScanOpaque so = (GinScanOpaque) scan->opaque;
                                492                 :                : 
 4227 heikki.linnakangas@i      493                 :           1152 :     ginFreeScanKeys(so);
                                494                 :                : 
 7267 bruce@momjian.us          495   [ +  -  +  - ]:           1152 :     if (scankey && scan->numberOfKeys > 0)
  715 peter@eisentraut.org      496                 :           1152 :         memcpy(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData));
 7422 teodor@sigaev.ru          497                 :           1152 : }
                                498                 :                : 
                                499                 :                : 
                                500                 :                : void
 3875 tgl@sss.pgh.pa.us         501                 :           1148 : ginendscan(IndexScanDesc scan)
                                502                 :                : {
 7267 bruce@momjian.us          503                 :           1148 :     GinScanOpaque so = (GinScanOpaque) scan->opaque;
                                504                 :                : 
 4227 heikki.linnakangas@i      505                 :           1148 :     ginFreeScanKeys(so);
                                506                 :                : 
 5747 tgl@sss.pgh.pa.us         507                 :           1148 :     MemoryContextDelete(so->tempCtx);
 4222 heikki.linnakangas@i      508                 :           1148 :     MemoryContextDelete(so->keyCtx);
                                509                 :                : 
 5747 tgl@sss.pgh.pa.us         510                 :           1148 :     pfree(so);
 7422 teodor@sigaev.ru          511                 :           1148 : }
        

Generated by: LCOV version 2.0-1