LCOV - differential code coverage report
Current view: top level - src/backend/access/gin - ginscan.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 94.1 % 188 177 11 177
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 8 8 8
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 94.1 % 188 177 11 177
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 100.0 % 8 8 8

 Age         Owner                  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-2023, 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
 2639 tgl                        25 CBC         791 : ginbeginscan(Relation rel, int nkeys, int norderbys)
                                 26                 : {
                                 27                 :     IndexScanDesc scan;
                                 28                 :     GinScanOpaque so;
                                 29                 : 
                                 30                 :     /* no order by operators allowed */
 4511                            31             791 :     Assert(norderbys == 0);
                                 32                 : 
                                 33             791 :     scan = RelationGetIndexScan(rel, nkeys, norderbys);
                                 34                 : 
                                 35                 :     /* allocate private workspace */
                                 36             791 :     so = (GinScanOpaque) palloc(sizeof(GinScanOpaqueData));
                                 37             791 :     so->keys = NULL;
                                 38             791 :     so->nkeys = 0;
                                 39             791 :     so->tempCtx = AllocSetContextCreate(CurrentMemoryContext,
                                 40                 :                                         "Gin scan temporary context",
                                 41                 :                                         ALLOCSET_DEFAULT_SIZES);
 2986 heikki.linnakangas         42             791 :     so->keyCtx = AllocSetContextCreate(CurrentMemoryContext,
                                 43                 :                                        "Gin scan key context",
                                 44                 :                                        ALLOCSET_DEFAULT_SIZES);
 4511 tgl                        45             791 :     initGinState(&so->ginstate, scan->indexRelation);
                                 46                 : 
                                 47             791 :     scan->opaque = so;
                                 48                 : 
 2639                            49             791 :     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
 4474                            57            1846 : ginFillScanEntry(GinScanOpaque so, OffsetNumber attnum,
                                 58                 :                  StrategyNumber strategy, int32 searchMode,
                                 59                 :                  Datum queryKey, GinNullCategory queryCategory,
                                 60                 :                  bool isPartialMatch, Pointer extra_data)
                                 61                 : {
                                 62            1846 :     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            1846 :     if (extra_data == NULL)
                                 73                 :     {
                                 74            2755 :         for (i = 0; i < so->totalentries; i++)
                                 75                 :         {
                                 76            1750 :             GinScanEntry prevEntry = so->entries[i];
                                 77                 : 
                                 78            1750 :             if (prevEntry->extra_data == NULL &&
                                 79            1600 :                 prevEntry->isPartialMatch == isPartialMatch &&
                                 80            1600 :                 prevEntry->strategy == strategy &&
                                 81            1530 :                 prevEntry->searchMode == searchMode &&
                                 82            3048 :                 prevEntry->attnum == attnum &&
                                 83            1518 :                 ginCompareEntries(ginstate, attnum,
                                 84                 :                                   prevEntry->queryKey,
                                 85            1518 :                                   prevEntry->queryCategory,
                                 86                 :                                   queryKey,
                                 87                 :                                   queryCategory) == 0)
                                 88                 :             {
                                 89                 :                 /* Successful match */
 4474 tgl                        90 UBC           0 :                 return prevEntry;
                                 91                 :             }
                                 92                 :         }
                                 93                 :     }
                                 94                 : 
                                 95                 :     /* Nope, create a new entry */
 4474 tgl                        96 CBC        1846 :     scanEntry = (GinScanEntry) palloc(sizeof(GinScanEntryData));
                                 97            1846 :     scanEntry->queryKey = queryKey;
                                 98            1846 :     scanEntry->queryCategory = queryCategory;
                                 99            1846 :     scanEntry->isPartialMatch = isPartialMatch;
                                100            1846 :     scanEntry->extra_data = extra_data;
                                101            1846 :     scanEntry->strategy = strategy;
                                102            1846 :     scanEntry->searchMode = searchMode;
                                103            1846 :     scanEntry->attnum = attnum;
                                104                 : 
                                105            1846 :     scanEntry->buffer = InvalidBuffer;
                                106            1846 :     ItemPointerSetMin(&scanEntry->curItem);
                                107            1846 :     scanEntry->matchBitmap = NULL;
                                108            1846 :     scanEntry->matchIterator = NULL;
                                109            1846 :     scanEntry->matchResult = NULL;
                                110            1846 :     scanEntry->list = NULL;
                                111            1846 :     scanEntry->nlist = 0;
                                112            1846 :     scanEntry->offset = InvalidOffsetNumber;
                                113            1846 :     scanEntry->isFinished = false;
                                114            1846 :     scanEntry->reduceResult = false;
                                115                 : 
                                116                 :     /* Add it to so's array */
                                117            1846 :     if (so->totalentries >= so->allocentries)
                                118                 :     {
                                119               3 :         so->allocentries *= 2;
                                120               3 :         so->entries = (GinScanEntry *)
                                121               3 :             repalloc(so->entries, so->allocentries * sizeof(GinScanEntry));
                                122                 :     }
                                123            1846 :     so->entries[so->totalentries++] = scanEntry;
                                124                 : 
                                125            1846 :     return scanEntry;
                                126                 : }
                                127                 : 
                                128                 : /*
                                129                 :  * Append hidden scan entry of given category to the scan key.
                                130                 :  *
                                131                 :  * NB: this had better be called at most once per scan key, since
                                132                 :  * ginFillScanKey leaves room for only one hidden entry.  Currently,
                                133                 :  * it seems sufficiently clear that this is true that we don't bother
                                134                 :  * with any cross-check logic.
                                135                 :  */
                                136                 : static void
 1177 akorotkov                 137             163 : ginScanKeyAddHiddenEntry(GinScanOpaque so, GinScanKey key,
                                138                 :                          GinNullCategory queryCategory)
                                139                 : {
                                140             163 :     int         i = key->nentries++;
                                141                 : 
                                142                 :     /* strategy is of no interest because this is not a partial-match item */
                                143             163 :     key->scanEntry[i] = ginFillScanEntry(so, key->attnum,
                                144                 :                                          InvalidStrategy, key->searchMode,
                                145                 :                                          (Datum) 0, queryCategory,
                                146                 :                                          false, NULL);
                                147             163 : }
                                148                 : 
                                149                 : /*
                                150                 :  * Initialize the next GinScanKey using the output from the extractQueryFn
                                151                 :  */
                                152                 : static void
 4474 tgl                       153             852 : ginFillScanKey(GinScanOpaque so, OffsetNumber attnum,
                                154                 :                StrategyNumber strategy, int32 searchMode,
                                155                 :                Datum query, uint32 nQueryValues,
                                156                 :                Datum *queryValues, GinNullCategory *queryCategories,
                                157                 :                bool *partial_matches, Pointer *extra_data)
                                158                 : {
                                159             852 :     GinScanKey  key = &(so->keys[so->nkeys++]);
                                160             852 :     GinState   *ginstate = &so->ginstate;
                                161                 :     uint32      i;
                                162                 : 
 4475                           163             852 :     key->nentries = nQueryValues;
 1177 akorotkov                 164             852 :     key->nuserentries = nQueryValues;
                                165                 : 
                                166                 :     /* Allocate one extra array slot for possible "hidden" entry */
                                167            1704 :     key->scanEntry = (GinScanEntry *) palloc(sizeof(GinScanEntry) *
                                168             852 :                                              (nQueryValues + 1));
                                169            1704 :     key->entryRes = (GinTernaryValue *) palloc0(sizeof(GinTernaryValue) *
                                170             852 :                                                 (nQueryValues + 1));
                                171                 : 
 4475 tgl                       172             852 :     key->query = query;
                                173             852 :     key->queryValues = queryValues;
                                174             852 :     key->queryCategories = queryCategories;
                                175             852 :     key->extra_data = extra_data;
 6186 teodor                    176             852 :     key->strategy = strategy;
 4475 tgl                       177             852 :     key->searchMode = searchMode;
 5385                           178             852 :     key->attnum = attnum;
                                179                 : 
                                180                 :     /*
                                181                 :      * Initially, scan keys of GIN_SEARCH_MODE_ALL mode are marked
                                182                 :      * excludeOnly.  This might get changed later.
                                183                 :      */
 1177 akorotkov                 184             852 :     key->excludeOnly = (searchMode == GIN_SEARCH_MODE_ALL);
                                185                 : 
 4635 tgl                       186             852 :     ItemPointerSetMin(&key->curItem);
 4474                           187             852 :     key->curItemMatches = false;
                                188             852 :     key->recheckCurItem = false;
                                189             852 :     key->isFinished = false;
 2991 heikki.linnakangas        190             852 :     key->nrequired = 0;
                                191             852 :     key->nadditional = 0;
                                192             852 :     key->requiredEntries = NULL;
                                193             852 :     key->additionalEntries = NULL;
                                194                 : 
 3348                           195             852 :     ginInitConsistentFunction(ginstate, key);
                                196                 : 
                                197                 :     /* Set up normal scan entries using extractQueryFn's outputs */
 4475 tgl                       198            2535 :     for (i = 0; i < nQueryValues; i++)
                                199                 :     {
                                200                 :         Datum       queryKey;
                                201                 :         GinNullCategory queryCategory;
                                202                 :         bool        isPartialMatch;
                                203                 :         Pointer     this_extra;
                                204                 : 
 1177 akorotkov                 205            1683 :         queryKey = queryValues[i];
                                206            1683 :         queryCategory = queryCategories[i];
                                207            1683 :         isPartialMatch =
                                208            1683 :             (ginstate->canPartialMatch[attnum - 1] && partial_matches)
                                209            1683 :             ? partial_matches[i] : false;
                                210            1683 :         this_extra = (extra_data) ? extra_data[i] : NULL;
                                211                 : 
 4474 tgl                       212            1683 :         key->scanEntry[i] = ginFillScanEntry(so, attnum,
                                213                 :                                              strategy, searchMode,
                                214                 :                                              queryKey, queryCategory,
                                215                 :                                              isPartialMatch, this_extra);
                                216                 :     }
                                217                 : 
                                218                 :     /*
                                219                 :      * For GIN_SEARCH_MODE_INCLUDE_EMPTY and GIN_SEARCH_MODE_EVERYTHING search
                                220                 :      * modes, we add the "hidden" entry immediately.  GIN_SEARCH_MODE_ALL is
                                221                 :      * handled later, since we might be able to omit the hidden entry for it.
                                222                 :      */
 1177 akorotkov                 223             852 :     if (searchMode == GIN_SEARCH_MODE_INCLUDE_EMPTY)
                                224              22 :         ginScanKeyAddHiddenEntry(so, key, GIN_CAT_EMPTY_ITEM);
                                225             830 :     else if (searchMode == GIN_SEARCH_MODE_EVERYTHING)
 1177 akorotkov                 226 UBC           0 :         ginScanKeyAddHiddenEntry(so, key, GIN_CAT_EMPTY_QUERY);
 6186 teodor                    227 CBC         852 : }
                                228                 : 
                                229                 : /*
                                230                 :  * Release current scan keys, if any.
                                231                 :  */
                                232                 : void
 2991 heikki.linnakangas        233            2379 : ginFreeScanKeys(GinScanOpaque so)
                                234                 : {
                                235                 :     uint32      i;
                                236                 : 
 4474 tgl                       237            2379 :     if (so->keys == NULL)
 6186 teodor                    238            1585 :         return;
                                239                 : 
 4474 tgl                       240            2640 :     for (i = 0; i < so->totalentries; i++)
                                241                 :     {
                                242            1846 :         GinScanEntry entry = so->entries[i];
                                243                 : 
                                244            1846 :         if (entry->buffer != InvalidBuffer)
 4474 tgl                       245 UBC           0 :             ReleaseBuffer(entry->buffer);
 2583 tgl                       246 CBC        1846 :         if (entry->list)
                                247            1083 :             pfree(entry->list);
 4474                           248            1846 :         if (entry->matchIterator)
 4474 tgl                       249 UBC           0 :             tbm_end_iterate(entry->matchIterator);
 4474 tgl                       250 CBC        1846 :         if (entry->matchBitmap)
                                251             267 :             tbm_free(entry->matchBitmap);
                                252                 :     }
                                253                 : 
 2986 heikki.linnakangas        254             794 :     MemoryContextResetAndDeleteChildren(so->keyCtx);
                                255                 : 
                                256             794 :     so->keys = NULL;
                                257             794 :     so->nkeys = 0;
 4474 tgl                       258             794 :     so->entries = NULL;
                                259             794 :     so->totalentries = 0;
                                260                 : }
                                261                 : 
                                262                 : void
 4557                           263             794 : ginNewScanKey(IndexScanDesc scan)
                                264                 : {
 6031 bruce                     265             794 :     ScanKey     scankey = scan->keyData;
 6186 teodor                    266             794 :     GinScanOpaque so = (GinScanOpaque) scan->opaque;
                                267                 :     int         i;
 4475 tgl                       268             794 :     bool        hasNullQuery = false;
 1177 akorotkov                 269             794 :     bool        attrHasNormalScan[INDEX_MAX_KEYS] = {false};
                                270                 :     MemoryContext oldCtx;
                                271                 : 
                                272                 :     /*
                                273                 :      * Allocate all the scan key information in the key context. (If
                                274                 :      * extractQuery leaks anything there, it won't be reset until the end of
                                275                 :      * scan or rescan, but that's OK.)
                                276                 :      */
 2986 heikki.linnakangas        277             794 :     oldCtx = MemoryContextSwitchTo(so->keyCtx);
                                278                 : 
                                279                 :     /* if no scan keys provided, allocate extra EVERYTHING GinScanKey */
 4475 tgl                       280             794 :     so->keys = (GinScanKey)
                                281             794 :         palloc(Max(scan->numberOfKeys, 1) * sizeof(GinScanKeyData));
 4474                           282             794 :     so->nkeys = 0;
                                283                 : 
                                284                 :     /* initialize expansible array of GinScanEntry pointers */
                                285             794 :     so->totalentries = 0;
                                286             794 :     so->allocentries = 32;
                                287             794 :     so->entries = (GinScanEntry *)
 2583                           288             794 :         palloc(so->allocentries * sizeof(GinScanEntry));
                                289                 : 
 5912 teodor                    290             794 :     so->isVoidRes = false;
                                291                 : 
 6031 bruce                     292            1646 :     for (i = 0; i < scan->numberOfKeys; i++)
                                293                 :     {
 5128 tgl                       294             858 :         ScanKey     skey = &scankey[i];
                                295                 :         Datum      *queryValues;
 4475                           296             858 :         int32       nQueryValues = 0;
 5050 bruce                     297             858 :         bool       *partial_matches = NULL;
                                298             858 :         Pointer    *extra_data = NULL;
 4475 tgl                       299             858 :         bool       *nullFlags = NULL;
                                300                 :         GinNullCategory *categories;
                                301             858 :         int32       searchMode = GIN_SEARCH_MODE_DEFAULT;
                                302                 : 
                                303                 :         /*
                                304                 :          * We assume that GIN-indexable operators are strict, so a null query
                                305                 :          * argument means an unsatisfiable query.
                                306                 :          */
 5128                           307             858 :         if (skey->sk_flags & SK_ISNULL)
                                308                 :         {
 5117 teodor                    309 UBC           0 :             so->isVoidRes = true;
 5117 teodor                    310 CBC           6 :             break;
                                311                 :         }
                                312                 : 
                                313                 :         /* OK to call the extractQueryFn */
                                314                 :         queryValues = (Datum *)
 4370 tgl                       315            2574 :             DatumGetPointer(FunctionCall7Coll(&so->ginstate.extractQueryFn[skey->sk_attno - 1],
 2118                           316             858 :                                               so->ginstate.supportCollation[skey->sk_attno - 1],
                                317                 :                                               skey->sk_argument,
                                318                 :                                               PointerGetDatum(&nQueryValues),
                                319             858 :                                               UInt16GetDatum(skey->sk_strategy),
                                320                 :                                               PointerGetDatum(&partial_matches),
                                321                 :                                               PointerGetDatum(&extra_data),
                                322                 :                                               PointerGetDatum(&nullFlags),
                                323                 :                                               PointerGetDatum(&searchMode)));
                                324                 : 
                                325                 :         /*
                                326                 :          * If bogus searchMode is returned, treat as GIN_SEARCH_MODE_ALL; note
                                327                 :          * in particular we don't allow extractQueryFn to select
                                328                 :          * GIN_SEARCH_MODE_EVERYTHING.
                                329                 :          */
 4475                           330             858 :         if (searchMode < GIN_SEARCH_MODE_DEFAULT ||
                                331             858 :             searchMode > GIN_SEARCH_MODE_ALL)
 4475 tgl                       332 UBC           0 :             searchMode = GIN_SEARCH_MODE_ALL;
                                333                 : 
                                334                 :         /* Non-default modes require the index to have placeholders */
 4475 tgl                       335 CBC         858 :         if (searchMode != GIN_SEARCH_MODE_DEFAULT)
                                336             182 :             hasNullQuery = true;
                                337                 : 
                                338                 :         /*
                                339                 :          * In default mode, no keys means an unsatisfiable query.
                                340                 :          */
                                341             858 :         if (queryValues == NULL || nQueryValues <= 0)
                                342                 :         {
                                343             152 :             if (searchMode == GIN_SEARCH_MODE_DEFAULT)
                                344                 :             {
                                345               6 :                 so->isVoidRes = true;
                                346               6 :                 break;
                                347                 :             }
                                348             146 :             nQueryValues = 0;   /* ensure sane value */
                                349                 :         }
                                350                 : 
                                351                 :         /*
                                352                 :          * Create GinNullCategory representation.  If the extractQueryFn
                                353                 :          * didn't create a nullFlags array, we assume everything is non-null.
                                354                 :          * While at it, detect whether any null keys are present.
                                355                 :          */
 1930 peter_e                   356             852 :         categories = (GinNullCategory *) palloc0(nQueryValues * sizeof(GinNullCategory));
                                357             852 :         if (nullFlags)
                                358                 :         {
                                359                 :             int32       j;
                                360                 : 
 4475 tgl                       361             512 :             for (j = 0; j < nQueryValues; j++)
                                362                 :             {
                                363             232 :                 if (nullFlags[j])
                                364                 :                 {
 1930 peter_e                   365 UBC           0 :                     categories[j] = GIN_CAT_NULL_KEY;
 4475 tgl                       366               0 :                     hasNullQuery = true;
                                367                 :                 }
                                368                 :             }
                                369                 :         }
                                370                 : 
 4474 tgl                       371 CBC         852 :         ginFillScanKey(so, skey->sk_attno,
                                372             852 :                        skey->sk_strategy, searchMode,
                                373                 :                        skey->sk_argument, nQueryValues,
                                374                 :                        queryValues, categories,
                                375                 :                        partial_matches, extra_data);
                                376                 : 
                                377                 :         /* Remember if we had any non-excludeOnly keys */
 1177 akorotkov                 378             852 :         if (searchMode != GIN_SEARCH_MODE_ALL)
                                379             692 :             attrHasNormalScan[skey->sk_attno - 1] = true;
                                380                 :     }
                                381                 : 
                                382                 :     /*
                                383                 :      * Processing GIN_SEARCH_MODE_ALL scan keys requires us to make a second
                                384                 :      * pass over the scan keys.  Above we marked each such scan key as
                                385                 :      * excludeOnly.  If the involved column has any normal (not excludeOnly)
                                386                 :      * scan key as well, then we can leave it like that.  Otherwise, one
                                387                 :      * excludeOnly scan key must receive a GIN_CAT_EMPTY_QUERY hidden entry
                                388                 :      * and be set to normal (excludeOnly = false).
                                389                 :      */
                                390            1646 :     for (i = 0; i < so->nkeys; i++)
                                391                 :     {
                                392             852 :         GinScanKey  key = &so->keys[i];
                                393                 : 
                                394             852 :         if (key->searchMode != GIN_SEARCH_MODE_ALL)
                                395             692 :             continue;
                                396                 : 
                                397             160 :         if (!attrHasNormalScan[key->attnum - 1])
                                398                 :         {
                                399             141 :             key->excludeOnly = false;
                                400             141 :             ginScanKeyAddHiddenEntry(so, key, GIN_CAT_EMPTY_QUERY);
                                401             141 :             attrHasNormalScan[key->attnum - 1] = true;
                                402                 :         }
                                403                 :     }
                                404                 : 
                                405                 :     /*
                                406                 :      * If there are no regular scan keys, generate an EVERYTHING scankey to
                                407                 :      * drive a full-index scan.
                                408                 :      */
 4474 tgl                       409             794 :     if (so->nkeys == 0 && !so->isVoidRes)
                                410                 :     {
 4475 tgl                       411 UBC           0 :         hasNullQuery = true;
 4474                           412               0 :         ginFillScanKey(so, FirstOffsetNumber,
                                413                 :                        InvalidStrategy, GIN_SEARCH_MODE_EVERYTHING,
                                414                 :                        (Datum) 0, 0,
                                415                 :                        NULL, NULL, NULL, NULL);
                                416                 :     }
                                417                 : 
                                418                 :     /*
                                419                 :      * If the index is version 0, it may be missing null and placeholder
                                420                 :      * entries, which would render searches for nulls and full-index scans
                                421                 :      * unreliable.  Throw an error if so.
                                422                 :      */
 4475 tgl                       423 CBC         794 :     if (hasNullQuery && !so->isVoidRes)
                                424                 :     {
                                425                 :         GinStatsData ginStats;
                                426                 : 
                                427             162 :         ginGetStats(scan->indexRelation, &ginStats);
                                428             162 :         if (ginStats.ginVersion < 1)
 4475 tgl                       429 UBC           0 :             ereport(ERROR,
                                430                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                431                 :                      errmsg("old GIN indexes do not support whole-index scans nor searches for nulls"),
                                432                 :                      errhint("To fix this, do REINDEX INDEX \"%s\".",
                                433                 :                              RelationGetRelationName(scan->indexRelation))));
                                434                 :     }
                                435                 : 
 2986 heikki.linnakangas        436 CBC         794 :     MemoryContextSwitchTo(oldCtx);
                                437                 : 
 5796 tgl                       438             794 :     pgstat_count_index_scan(scan->indexRelation);
 6186 teodor                    439             794 : }
                                440                 : 
                                441                 : void
 2639 tgl                       442             794 : ginrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
                                443                 :           ScanKey orderbys, int norderbys)
                                444                 : {
 4511                           445             794 :     GinScanOpaque so = (GinScanOpaque) scan->opaque;
                                446                 : 
 2991 heikki.linnakangas        447             794 :     ginFreeScanKeys(so);
                                448                 : 
 6031 bruce                     449             794 :     if (scankey && scan->numberOfKeys > 0)
                                450                 :     {
 6186 teodor                    451             794 :         memmove(scan->keyData, scankey,
 6031 bruce                     452             794 :                 scan->numberOfKeys * sizeof(ScanKeyData));
                                453                 :     }
 6186 teodor                    454             794 : }
                                455                 : 
                                456                 : 
                                457                 : void
 2639 tgl                       458             791 : ginendscan(IndexScanDesc scan)
                                459                 : {
 6031 bruce                     460             791 :     GinScanOpaque so = (GinScanOpaque) scan->opaque;
                                461                 : 
 2991 heikki.linnakangas        462             791 :     ginFreeScanKeys(so);
                                463                 : 
 4511 tgl                       464             791 :     MemoryContextDelete(so->tempCtx);
 2986 heikki.linnakangas        465             791 :     MemoryContextDelete(so->keyCtx);
                                466                 : 
 4511 tgl                       467             791 :     pfree(so);
 6186 teodor                    468             791 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a