LCOV - differential code coverage report
Current view: top level - src/backend/access/gin - ginscan.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: 806555e3000d0b0e0c536c1dc65548128d457d86 vs 1d325ad99cb2dec0e8b45ba36909ee0a497d2a57 Lines: 94.6 % 205 194 11 5 189 8
Current Date: 2025-12-17 08:58:58 +0900 Functions: 100.0 % 8 8 3 5
Baseline: lcov-20251217-005640-baseline Branches: 75.9 % 116 88 28 88
Baseline Date: 2025-12-16 12:57:12 -0800 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(1,7] days: 100.0 % 5 5 5
(30,360] days: 100.0 % 23 23 23
(360..) days: 93.8 % 177 166 11 166
Function coverage date bins:
(360..) days: 100.0 % 8 8 3 5
Branch coverage date bins:
(30,360] days: 72.2 % 18 13 5 13
(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
 3622 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 */
 5494                            31         [ -  + ]:            969 :     Assert(norderbys == 0);
                                 32                 :                : 
                                 33                 :            969 :     scan = RelationGetIndexScan(rel, nkeys, norderbys);
                                 34                 :                : 
                                 35                 :                :     /* allocate private workspace */
    7 michael@paquier.xyz        36                 :GNC         969 :     so = (GinScanOpaque) palloc_object(GinScanOpaqueData);
 5494 tgl@sss.pgh.pa.us          37                 :CBC         969 :     so->keys = NULL;
                                 38                 :            969 :     so->nkeys = 0;
                                 39                 :            969 :     so->tempCtx = AllocSetContextCreate(CurrentMemoryContext,
                                 40                 :                :                                         "Gin scan temporary context",
                                 41                 :                :                                         ALLOCSET_DEFAULT_SIZES);
 3969 heikki.linnakangas@i       42                 :            969 :     so->keyCtx = AllocSetContextCreate(CurrentMemoryContext,
                                 43                 :                :                                        "Gin scan key context",
                                 44                 :                :                                        ALLOCSET_DEFAULT_SIZES);
 5494 tgl@sss.pgh.pa.us          45                 :            969 :     initGinState(&so->ginstate, scan->indexRelation);
                                 46                 :                : 
                                 47                 :            969 :     scan->opaque = so;
                                 48                 :                : 
 3622                            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
 5457                            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                 :                :      */
  286                            77   [ +  +  +  - ]:           2038 :     if (extra_data == NULL && so->totalentries < 100)
                                 78                 :                :     {
 5457                            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 */
 5457 tgl@sss.pgh.pa.us          95                 :UBC           0 :                 return prevEntry;
                                 96                 :                :             }
                                 97                 :                :         }
                                 98                 :                :     }
                                 99                 :                : 
                                100                 :                :     /* Nope, create a new entry */
    7 michael@paquier.xyz       101                 :GNC        2038 :     scanEntry = palloc_object(GinScanEntryData);
 5457 tgl@sss.pgh.pa.us         102                 :CBC        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;
  277 melanieplageman@gmai      114                 :           2038 :     scanEntry->matchResult.blockno = InvalidBlockNumber;
  296                           115                 :           2038 :     scanEntry->matchNtuples = -1;
 5457 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;
    7 michael@paquier.xyz       126                 :GNC           3 :         so->entries = repalloc_array(so->entries, GinScanEntry, so->allocentries);
                                127                 :                :     }
 5457 tgl@sss.pgh.pa.us         128                 :CBC        2038 :     so->entries[so->totalentries++] = scanEntry;
                                129                 :                : 
                                130                 :           2038 :     return scanEntry;
                                131                 :                : }
                                132                 :                : 
                                133                 :                : /*
                                134                 :                :  * Append hidden scan entry of given category to the scan key.
                                135                 :                :  *
                                136                 :                :  * NB: this had better be called at most once per scan key, since
                                137                 :                :  * ginFillScanKey leaves room for only one hidden entry.  Currently,
                                138                 :                :  * it seems sufficiently clear that this is true that we don't bother
                                139                 :                :  * with any cross-check logic.
                                140                 :                :  */
                                141                 :                : static void
 2160 akorotkov@postgresql      142                 :            163 : ginScanKeyAddHiddenEntry(GinScanOpaque so, GinScanKey key,
                                143                 :                :                          GinNullCategory queryCategory)
                                144                 :                : {
                                145                 :            163 :     int         i = key->nentries++;
                                146                 :                : 
                                147                 :                :     /* strategy is of no interest because this is not a partial-match item */
                                148                 :            163 :     key->scanEntry[i] = ginFillScanEntry(so, key->attnum,
                                149                 :                :                                          InvalidStrategy, key->searchMode,
                                150                 :                :                                          (Datum) 0, queryCategory,
                                151                 :                :                                          false, NULL);
                                152                 :            163 : }
                                153                 :                : 
                                154                 :                : /*
                                155                 :                :  * Initialize the next GinScanKey using the output from the extractQueryFn
                                156                 :                :  */
                                157                 :                : static void
 5457 tgl@sss.pgh.pa.us         158                 :           1032 : ginFillScanKey(GinScanOpaque so, OffsetNumber attnum,
                                159                 :                :                StrategyNumber strategy, int32 searchMode,
                                160                 :                :                Datum query, uint32 nQueryValues,
                                161                 :                :                Datum *queryValues, GinNullCategory *queryCategories,
                                162                 :                :                bool *partial_matches, Pointer *extra_data)
                                163                 :                : {
                                164                 :           1032 :     GinScanKey  key = &(so->keys[so->nkeys++]);
                                165                 :           1032 :     GinState   *ginstate = &so->ginstate;
                                166                 :                :     uint32      i;
                                167                 :                : 
 5458                           168                 :           1032 :     key->nentries = nQueryValues;
 2160 akorotkov@postgresql      169                 :           1032 :     key->nuserentries = nQueryValues;
                                170                 :                : 
                                171                 :                :     /* Allocate one extra array slot for possible "hidden" entry */
    7 michael@paquier.xyz       172                 :GNC        1032 :     key->scanEntry = palloc_array(GinScanEntry, nQueryValues + 1);
                                173                 :           1032 :     key->entryRes = palloc0_array(GinTernaryValue, nQueryValues + 1);
                                174                 :                : 
 5458 tgl@sss.pgh.pa.us         175                 :CBC        1032 :     key->query = query;
                                176                 :           1032 :     key->queryValues = queryValues;
                                177                 :           1032 :     key->queryCategories = queryCategories;
                                178                 :           1032 :     key->extra_data = extra_data;
 7169 teodor@sigaev.ru          179                 :           1032 :     key->strategy = strategy;
 5458 tgl@sss.pgh.pa.us         180                 :           1032 :     key->searchMode = searchMode;
 6368                           181                 :           1032 :     key->attnum = attnum;
                                182                 :                : 
                                183                 :                :     /*
                                184                 :                :      * Initially, scan keys of GIN_SEARCH_MODE_ALL mode are marked
                                185                 :                :      * excludeOnly.  This might get changed later.
                                186                 :                :      */
 2160 akorotkov@postgresql      187                 :           1032 :     key->excludeOnly = (searchMode == GIN_SEARCH_MODE_ALL);
                                188                 :                : 
 5618 tgl@sss.pgh.pa.us         189                 :           1032 :     ItemPointerSetMin(&key->curItem);
 5457                           190                 :           1032 :     key->curItemMatches = false;
                                191                 :           1032 :     key->recheckCurItem = false;
                                192                 :           1032 :     key->isFinished = false;
 3974 heikki.linnakangas@i      193                 :           1032 :     key->nrequired = 0;
                                194                 :           1032 :     key->nadditional = 0;
                                195                 :           1032 :     key->requiredEntries = NULL;
                                196                 :           1032 :     key->additionalEntries = NULL;
                                197                 :                : 
 4331                           198                 :           1032 :     ginInitConsistentFunction(ginstate, key);
                                199                 :                : 
                                200                 :                :     /* Set up normal scan entries using extractQueryFn's outputs */
 5458 tgl@sss.pgh.pa.us         201         [ +  + ]:           2907 :     for (i = 0; i < nQueryValues; i++)
                                202                 :                :     {
                                203                 :                :         Datum       queryKey;
                                204                 :                :         GinNullCategory queryCategory;
                                205                 :                :         bool        isPartialMatch;
                                206                 :                :         Pointer     this_extra;
                                207                 :                : 
 2160 akorotkov@postgresql      208                 :           1875 :         queryKey = queryValues[i];
                                209                 :           1875 :         queryCategory = queryCategories[i];
                                210                 :           1875 :         isPartialMatch =
                                211   [ +  +  +  - ]:           1875 :             (ginstate->canPartialMatch[attnum - 1] && partial_matches)
                                212   [ +  +  +  + ]:           1875 :             ? partial_matches[i] : false;
                                213         [ +  + ]:           1875 :         this_extra = (extra_data) ? extra_data[i] : NULL;
                                214                 :                : 
 5457 tgl@sss.pgh.pa.us         215                 :           1875 :         key->scanEntry[i] = ginFillScanEntry(so, attnum,
                                216                 :                :                                              strategy, searchMode,
                                217                 :                :                                              queryKey, queryCategory,
                                218                 :                :                                              isPartialMatch, this_extra);
                                219                 :                :     }
                                220                 :                : 
                                221                 :                :     /*
                                222                 :                :      * For GIN_SEARCH_MODE_INCLUDE_EMPTY and GIN_SEARCH_MODE_EVERYTHING search
                                223                 :                :      * modes, we add the "hidden" entry immediately.  GIN_SEARCH_MODE_ALL is
                                224                 :                :      * handled later, since we might be able to omit the hidden entry for it.
                                225                 :                :      */
 2160 akorotkov@postgresql      226         [ +  + ]:           1032 :     if (searchMode == GIN_SEARCH_MODE_INCLUDE_EMPTY)
                                227                 :             22 :         ginScanKeyAddHiddenEntry(so, key, GIN_CAT_EMPTY_ITEM);
                                228         [ -  + ]:           1010 :     else if (searchMode == GIN_SEARCH_MODE_EVERYTHING)
 2160 akorotkov@postgresql      229                 :UBC           0 :         ginScanKeyAddHiddenEntry(so, key, GIN_CAT_EMPTY_QUERY);
 7169 teodor@sigaev.ru          230                 :CBC        1032 : }
                                231                 :                : 
                                232                 :                : /*
                                233                 :                :  * Release current scan keys, if any.
                                234                 :                :  */
                                235                 :                : void
 3974 heikki.linnakangas@i      236                 :           2913 : ginFreeScanKeys(GinScanOpaque so)
                                237                 :                : {
                                238                 :                :     uint32      i;
                                239                 :                : 
 5457 tgl@sss.pgh.pa.us         240         [ +  + ]:           2913 :     if (so->keys == NULL)
 7169 teodor@sigaev.ru          241                 :           1941 :         return;
                                242                 :                : 
 5457 tgl@sss.pgh.pa.us         243         [ +  + ]:           3010 :     for (i = 0; i < so->totalentries; i++)
                                244                 :                :     {
                                245                 :           2038 :         GinScanEntry entry = so->entries[i];
                                246                 :                : 
                                247         [ -  + ]:           2038 :         if (entry->buffer != InvalidBuffer)
 5457 tgl@sss.pgh.pa.us         248                 :UBC           0 :             ReleaseBuffer(entry->buffer);
 3566 tgl@sss.pgh.pa.us         249         [ +  + ]:CBC        2038 :         if (entry->list)
                                250                 :           1092 :             pfree(entry->list);
 5457                           251         [ -  + ]:           2038 :         if (entry->matchIterator)
  364 melanieplageman@gmai      252                 :UBC           0 :             tbm_end_private_iterate(entry->matchIterator);
 5457 tgl@sss.pgh.pa.us         253         [ +  + ]:CBC        2038 :         if (entry->matchBitmap)
                                254                 :            440 :             tbm_free(entry->matchBitmap);
                                255                 :                :     }
                                256                 :                : 
  763 nathan@postgresql.or      257                 :            972 :     MemoryContextReset(so->keyCtx);
                                258                 :                : 
 3969 heikki.linnakangas@i      259                 :            972 :     so->keys = NULL;
                                260                 :            972 :     so->nkeys = 0;
 5457 tgl@sss.pgh.pa.us         261                 :            972 :     so->entries = NULL;
                                262                 :            972 :     so->totalentries = 0;
                                263                 :                : }
                                264                 :                : 
                                265                 :                : void
 5540                           266                 :            972 : ginNewScanKey(IndexScanDesc scan)
                                267                 :                : {
 7014 bruce@momjian.us          268                 :            972 :     ScanKey     scankey = scan->keyData;
 7169 teodor@sigaev.ru          269                 :            972 :     GinScanOpaque so = (GinScanOpaque) scan->opaque;
                                270                 :                :     int         i;
                                271                 :                :     int         numExcludeOnly;
 5458 tgl@sss.pgh.pa.us         272                 :            972 :     bool        hasNullQuery = false;
 2160 akorotkov@postgresql      273                 :            972 :     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                 :                :      */
 3969 heikki.linnakangas@i      281                 :            972 :     oldCtx = MemoryContextSwitchTo(so->keyCtx);
                                282                 :                : 
                                283                 :                :     /* if no scan keys provided, allocate extra EVERYTHING GinScanKey */
 5458 tgl@sss.pgh.pa.us         284                 :            972 :     so->keys = (GinScanKey)
                                285                 :            972 :         palloc(Max(scan->numberOfKeys, 1) * sizeof(GinScanKeyData));
 5457                           286                 :            972 :     so->nkeys = 0;
                                287                 :                : 
                                288                 :                :     /* initialize expansible array of GinScanEntry pointers */
                                289                 :            972 :     so->totalentries = 0;
                                290                 :            972 :     so->allocentries = 32;
                                291                 :            972 :     so->entries = (GinScanEntry *)
 3566                           292                 :            972 :         palloc(so->allocentries * sizeof(GinScanEntry));
                                293                 :                : 
 6895 teodor@sigaev.ru          294                 :            972 :     so->isVoidRes = false;
                                295                 :                : 
 7014 bruce@momjian.us          296         [ +  + ]:           2004 :     for (i = 0; i < scan->numberOfKeys; i++)
                                297                 :                :     {
 6111 tgl@sss.pgh.pa.us         298                 :           1038 :         ScanKey     skey = &scankey[i];
                                299                 :                :         Datum      *queryValues;
 5458                           300                 :           1038 :         int32       nQueryValues = 0;
 6033 bruce@momjian.us          301                 :           1038 :         bool       *partial_matches = NULL;
                                302                 :           1038 :         Pointer    *extra_data = NULL;
 5458 tgl@sss.pgh.pa.us         303                 :           1038 :         bool       *nullFlags = NULL;
                                304                 :                :         GinNullCategory *categories;
                                305                 :           1038 :         int32       searchMode = GIN_SEARCH_MODE_DEFAULT;
                                306                 :                : 
                                307                 :                :         /*
                                308                 :                :          * We assume that GIN-indexable operators are strict, so a null query
                                309                 :                :          * argument means an unsatisfiable query.
                                310                 :                :          */
 6111                           311         [ -  + ]:           1038 :         if (skey->sk_flags & SK_ISNULL)
                                312                 :                :         {
 6100 teodor@sigaev.ru          313                 :UBC           0 :             so->isVoidRes = true;
 6100 teodor@sigaev.ru          314                 :CBC           6 :             break;
                                315                 :                :         }
                                316                 :                : 
                                317                 :                :         /* OK to call the extractQueryFn */
                                318                 :                :         queryValues = (Datum *)
 5353 tgl@sss.pgh.pa.us         319                 :           3114 :             DatumGetPointer(FunctionCall7Coll(&so->ginstate.extractQueryFn[skey->sk_attno - 1],
 3101                           320                 :           1038 :                                               so->ginstate.supportCollation[skey->sk_attno - 1],
                                321                 :                :                                               skey->sk_argument,
                                322                 :                :                                               PointerGetDatum(&nQueryValues),
                                323                 :           1038 :                                               UInt16GetDatum(skey->sk_strategy),
                                324                 :                :                                               PointerGetDatum(&partial_matches),
                                325                 :                :                                               PointerGetDatum(&extra_data),
                                326                 :                :                                               PointerGetDatum(&nullFlags),
                                327                 :                :                                               PointerGetDatum(&searchMode)));
                                328                 :                : 
                                329                 :                :         /*
                                330                 :                :          * If bogus searchMode is returned, treat as GIN_SEARCH_MODE_ALL; note
                                331                 :                :          * in particular we don't allow extractQueryFn to select
                                332                 :                :          * GIN_SEARCH_MODE_EVERYTHING.
                                333                 :                :          */
 5458                           334         [ +  - ]:           1038 :         if (searchMode < GIN_SEARCH_MODE_DEFAULT ||
                                335         [ -  + ]:           1038 :             searchMode > GIN_SEARCH_MODE_ALL)
 5458 tgl@sss.pgh.pa.us         336                 :UBC           0 :             searchMode = GIN_SEARCH_MODE_ALL;
                                337                 :                : 
                                338                 :                :         /* Non-default modes require the index to have placeholders */
 5458 tgl@sss.pgh.pa.us         339         [ +  + ]:CBC        1038 :         if (searchMode != GIN_SEARCH_MODE_DEFAULT)
                                340                 :            184 :             hasNullQuery = true;
                                341                 :                : 
                                342                 :                :         /*
                                343                 :                :          * In default mode, no keys means an unsatisfiable query.
                                344                 :                :          */
                                345   [ +  +  +  + ]:           1038 :         if (queryValues == NULL || nQueryValues <= 0)
                                346                 :                :         {
                                347         [ +  + ]:            154 :             if (searchMode == GIN_SEARCH_MODE_DEFAULT)
                                348                 :                :             {
                                349                 :              6 :                 so->isVoidRes = true;
                                350                 :              6 :                 break;
                                351                 :                :             }
                                352                 :            148 :             nQueryValues = 0;   /* ensure sane value */
                                353                 :                :         }
                                354                 :                : 
                                355                 :                :         /*
                                356                 :                :          * Create GinNullCategory representation.  If the extractQueryFn
                                357                 :                :          * didn't create a nullFlags array, we assume everything is non-null.
                                358                 :                :          * While at it, detect whether any null keys are present.
                                359                 :                :          */
 2913 peter_e@gmx.net           360                 :           1032 :         categories = (GinNullCategory *) palloc0(nQueryValues * sizeof(GinNullCategory));
                                361         [ +  + ]:           1032 :         if (nullFlags)
                                362                 :                :         {
                                363                 :                :             int32       j;
                                364                 :                : 
 5458 tgl@sss.pgh.pa.us         365         [ +  + ]:            512 :             for (j = 0; j < nQueryValues; j++)
                                366                 :                :             {
                                367         [ -  + ]:            232 :                 if (nullFlags[j])
                                368                 :                :                 {
 2913 peter_e@gmx.net           369                 :UBC           0 :                     categories[j] = GIN_CAT_NULL_KEY;
 5458 tgl@sss.pgh.pa.us         370                 :              0 :                     hasNullQuery = true;
                                371                 :                :                 }
                                372                 :                :             }
                                373                 :                :         }
                                374                 :                : 
 5457 tgl@sss.pgh.pa.us         375                 :CBC        1032 :         ginFillScanKey(so, skey->sk_attno,
                                376                 :           1032 :                        skey->sk_strategy, searchMode,
                                377                 :                :                        skey->sk_argument, nQueryValues,
                                378                 :                :                        queryValues, categories,
                                379                 :                :                        partial_matches, extra_data);
                                380                 :                : 
                                381                 :                :         /* Remember if we had any non-excludeOnly keys */
 2160 akorotkov@postgresql      382         [ +  + ]:           1032 :         if (searchMode != GIN_SEARCH_MODE_ALL)
                                383                 :            870 :             attrHasNormalScan[skey->sk_attno - 1] = true;
                                384                 :                :     }
                                385                 :                : 
                                386                 :                :     /*
                                387                 :                :      * Processing GIN_SEARCH_MODE_ALL scan keys requires us to make a second
                                388                 :                :      * pass over the scan keys.  Above we marked each such scan key as
                                389                 :                :      * excludeOnly.  If the involved column has any normal (not excludeOnly)
                                390                 :                :      * scan key as well, then we can leave it like that.  Otherwise, one
                                391                 :                :      * excludeOnly scan key must receive a GIN_CAT_EMPTY_QUERY hidden entry
                                392                 :                :      * and be set to normal (excludeOnly = false).
                                393                 :                :      */
  113 tgl@sss.pgh.pa.us         394                 :            972 :     numExcludeOnly = 0;
 2160 akorotkov@postgresql      395         [ +  + ]:           2004 :     for (i = 0; i < so->nkeys; i++)
                                396                 :                :     {
                                397                 :           1032 :         GinScanKey  key = &so->keys[i];
                                398                 :                : 
                                399         [ +  + ]:           1032 :         if (key->searchMode != GIN_SEARCH_MODE_ALL)
                                400                 :            870 :             continue;
                                401                 :                : 
                                402         [ +  + ]:            162 :         if (!attrHasNormalScan[key->attnum - 1])
                                403                 :                :         {
                                404                 :            141 :             key->excludeOnly = false;
                                405                 :            141 :             ginScanKeyAddHiddenEntry(so, key, GIN_CAT_EMPTY_QUERY);
                                406                 :            141 :             attrHasNormalScan[key->attnum - 1] = true;
                                407                 :                :         }
                                408                 :                :         else
  113 tgl@sss.pgh.pa.us         409                 :             21 :             numExcludeOnly++;
                                410                 :                :     }
                                411                 :                : 
                                412                 :                :     /*
                                413                 :                :      * If we left any excludeOnly scan keys as-is, move them to the end of the
                                414                 :                :      * scan key array: they must appear after normal key(s).
                                415                 :                :      */
                                416         [ +  + ]:            972 :     if (numExcludeOnly > 0)
                                417                 :                :     {
                                418                 :                :         GinScanKey  tmpkeys;
                                419                 :                :         int         iNormalKey;
                                420                 :                :         int         iExcludeOnly;
                                421                 :                : 
                                422                 :                :         /* We'd better have made at least one normal key */
                                423         [ -  + ]:             21 :         Assert(numExcludeOnly < so->nkeys);
                                424                 :                :         /* Make a temporary array to hold the re-ordered scan keys */
                                425                 :             21 :         tmpkeys = (GinScanKey) palloc(so->nkeys * sizeof(GinScanKeyData));
                                426                 :                :         /* Re-order the keys ... */
                                427                 :             21 :         iNormalKey = 0;
                                428                 :             21 :         iExcludeOnly = so->nkeys - numExcludeOnly;
                                429         [ +  + ]:             75 :         for (i = 0; i < so->nkeys; i++)
                                430                 :                :         {
                                431                 :             54 :             GinScanKey  key = &so->keys[i];
                                432                 :                : 
                                433         [ +  + ]:             54 :             if (key->excludeOnly)
                                434                 :                :             {
                                435                 :             21 :                 memcpy(tmpkeys + iExcludeOnly, key, sizeof(GinScanKeyData));
                                436                 :             21 :                 iExcludeOnly++;
                                437                 :                :             }
                                438                 :                :             else
                                439                 :                :             {
                                440                 :             33 :                 memcpy(tmpkeys + iNormalKey, key, sizeof(GinScanKeyData));
                                441                 :             33 :                 iNormalKey++;
                                442                 :                :             }
                                443                 :                :         }
                                444         [ -  + ]:             21 :         Assert(iNormalKey == so->nkeys - numExcludeOnly);
                                445         [ -  + ]:             21 :         Assert(iExcludeOnly == so->nkeys);
                                446                 :                :         /* ... and copy them back to so->keys[] */
                                447                 :             21 :         memcpy(so->keys, tmpkeys, so->nkeys * sizeof(GinScanKeyData));
                                448                 :             21 :         pfree(tmpkeys);
                                449                 :                :     }
                                450                 :                : 
                                451                 :                :     /*
                                452                 :                :      * If there are no regular scan keys, generate an EVERYTHING scankey to
                                453                 :                :      * drive a full-index scan.
                                454                 :                :      */
 5457                           455   [ +  +  -  + ]:            972 :     if (so->nkeys == 0 && !so->isVoidRes)
                                456                 :                :     {
 5458 tgl@sss.pgh.pa.us         457                 :UBC           0 :         hasNullQuery = true;
 5457                           458                 :              0 :         ginFillScanKey(so, FirstOffsetNumber,
                                459                 :                :                        InvalidStrategy, GIN_SEARCH_MODE_EVERYTHING,
                                460                 :                :                        (Datum) 0, 0,
                                461                 :                :                        NULL, NULL, NULL, NULL);
                                462                 :                :     }
                                463                 :                : 
                                464                 :                :     /*
                                465                 :                :      * If the index is version 0, it may be missing null and placeholder
                                466                 :                :      * entries, which would render searches for nulls and full-index scans
                                467                 :                :      * unreliable.  Throw an error if so.
                                468                 :                :      */
 5458 tgl@sss.pgh.pa.us         469   [ +  +  +  - ]:CBC         972 :     if (hasNullQuery && !so->isVoidRes)
                                470                 :                :     {
                                471                 :                :         GinStatsData ginStats;
                                472                 :                : 
                                473                 :            164 :         ginGetStats(scan->indexRelation, &ginStats);
                                474         [ -  + ]:            164 :         if (ginStats.ginVersion < 1)
 5458 tgl@sss.pgh.pa.us         475         [ #  # ]:UBC           0 :             ereport(ERROR,
                                476                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                477                 :                :                      errmsg("old GIN indexes do not support whole-index scans nor searches for nulls"),
                                478                 :                :                      errhint("To fix this, do REINDEX INDEX \"%s\".",
                                479                 :                :                              RelationGetRelationName(scan->indexRelation))));
                                480                 :                :     }
                                481                 :                : 
 3969 heikki.linnakangas@i      482                 :CBC         972 :     MemoryContextSwitchTo(oldCtx);
                                483                 :                : 
 6779 tgl@sss.pgh.pa.us         484   [ -  +  -  -  :            972 :     pgstat_count_index_scan(scan->indexRelation);
                                              +  - ]
  281 pg@bowt.ie                485         [ +  - ]:            972 :     if (scan->instrument)
                                486                 :            972 :         scan->instrument->nsearches++;
 7169 teodor@sigaev.ru          487                 :            972 : }
                                488                 :                : 
                                489                 :                : void
 3622 tgl@sss.pgh.pa.us         490                 :            972 : ginrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
                                491                 :                :           ScanKey orderbys, int norderbys)
                                492                 :                : {
 5494                           493                 :            972 :     GinScanOpaque so = (GinScanOpaque) scan->opaque;
                                494                 :                : 
 3974 heikki.linnakangas@i      495                 :            972 :     ginFreeScanKeys(so);
                                496                 :                : 
 7014 bruce@momjian.us          497   [ +  -  +  - ]:            972 :     if (scankey && scan->numberOfKeys > 0)
  462 peter@eisentraut.org      498                 :            972 :         memcpy(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData));
 7169 teodor@sigaev.ru          499                 :            972 : }
                                500                 :                : 
                                501                 :                : 
                                502                 :                : void
 3622 tgl@sss.pgh.pa.us         503                 :            969 : ginendscan(IndexScanDesc scan)
                                504                 :                : {
 7014 bruce@momjian.us          505                 :            969 :     GinScanOpaque so = (GinScanOpaque) scan->opaque;
                                506                 :                : 
 3974 heikki.linnakangas@i      507                 :            969 :     ginFreeScanKeys(so);
                                508                 :                : 
 5494 tgl@sss.pgh.pa.us         509                 :            969 :     MemoryContextDelete(so->tempCtx);
 3969 heikki.linnakangas@i      510                 :            969 :     MemoryContextDelete(so->keyCtx);
                                511                 :                : 
 5494 tgl@sss.pgh.pa.us         512                 :            969 :     pfree(so);
 7169 teodor@sigaev.ru          513                 :            969 : }
        

Generated by: LCOV version 2.4-beta