LCOV - differential code coverage report
Current view: top level - src/backend/access/gin - ginscan.c (source / functions) Coverage Total Hit UBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 94.7 % 208 197 11 197
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 8 8 8
Baseline: lcov-20250906-005545-baseline Branches: 75.9 % 116 88 28 88
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 100.0 % 18 18 18
(30,360] days: 85.7 % 7 6 1 6
(360..) days: 94.5 % 183 173 10 173
Function coverage date bins:
(360..) days: 100.0 % 8 8 8
Branch coverage date bins:
(7,30] days: 75.0 % 12 9 3 9
(30,360] days: 66.7 % 6 4 2 4
(360..) days: 76.5 % 98 75 23 75

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

Generated by: LCOV version 2.4-beta