LCOV - differential code coverage report
Current view: top level - src/backend/access/gin - ginutil.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 96.1 % 259 249 4 3 3 2 130 3 114 5 126 5
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 15 15 14 1 13 1
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 [..60] days: 100.0 % 2 2 2
Legend: Lines: hit not hit (240..) days: 96.1 % 257 247 4 3 3 2 130 1 114 5 126
Function coverage date bins:
(240..) days: 53.6 % 28 15 14 1 13

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * ginutil.c
                                  4                 :  *    Utility routines for the Postgres inverted index access method.
                                  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/ginutil.c
                                 12                 :  *-------------------------------------------------------------------------
                                 13                 :  */
                                 14                 : 
                                 15                 : #include "postgres.h"
                                 16                 : 
                                 17                 : #include "access/gin_private.h"
                                 18                 : #include "access/ginxlog.h"
                                 19                 : #include "access/reloptions.h"
                                 20                 : #include "access/xloginsert.h"
                                 21                 : #include "catalog/pg_collation.h"
                                 22                 : #include "catalog/pg_type.h"
                                 23                 : #include "commands/vacuum.h"
                                 24                 : #include "miscadmin.h"
                                 25                 : #include "storage/indexfsm.h"
                                 26                 : #include "storage/lmgr.h"
                                 27                 : #include "storage/predicate.h"
                                 28                 : #include "utils/builtins.h"
                                 29                 : #include "utils/index_selfuncs.h"
                                 30                 : #include "utils/typcache.h"
                                 31                 : 
                                 32                 : 
                                 33                 : /*
                                 34                 :  * GIN handler function: return IndexAmRoutine with access method parameters
                                 35                 :  * and callbacks.
                                 36                 :  */
                                 37                 : Datum
 2639 tgl                        38 CBC         870 : ginhandler(PG_FUNCTION_ARGS)
                                 39                 : {
                                 40             870 :     IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
                                 41                 : 
                                 42             870 :     amroutine->amstrategies = 0;
 2537 teodor                     43             870 :     amroutine->amsupport = GINNProcs;
 1105 akorotkov                  44             870 :     amroutine->amoptsprocnum = GIN_OPTIONS_PROC;
 2639 tgl                        45             870 :     amroutine->amcanorder = false;
                                 46             870 :     amroutine->amcanorderbyop = false;
                                 47             870 :     amroutine->amcanbackward = false;
                                 48             870 :     amroutine->amcanunique = false;
                                 49             870 :     amroutine->amcanmulticol = true;
                                 50             870 :     amroutine->amoptionalkey = true;
                                 51             870 :     amroutine->amsearcharray = false;
                                 52             870 :     amroutine->amsearchnulls = false;
                                 53             870 :     amroutine->amstorage = true;
                                 54             870 :     amroutine->amclusterable = false;
 1836 teodor                     55             870 :     amroutine->ampredlocks = true;
 2244 rhaas                      56             870 :     amroutine->amcanparallel = false;
 1828 teodor                     57             870 :     amroutine->amcaninclude = false;
 1180 akapila                    58             870 :     amroutine->amusemaintenanceworkmem = true;
   20 tomas.vondra               59 GNC         870 :     amroutine->amsummarizing = false;
 1180 akapila                    60 CBC         870 :     amroutine->amparallelvacuumoptions =
 1180 akapila                    61 ECB             :         VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_CLEANUP;
 2639 tgl                        62 GIC         870 :     amroutine->amkeytype = InvalidOid;
 2639 tgl                        63 ECB             : 
 2639 tgl                        64 GIC         870 :     amroutine->ambuild = ginbuild;
 2639 tgl                        65 CBC         870 :     amroutine->ambuildempty = ginbuildempty;
                                 66             870 :     amroutine->aminsert = gininsert;
                                 67             870 :     amroutine->ambulkdelete = ginbulkdelete;
                                 68             870 :     amroutine->amvacuumcleanup = ginvacuumcleanup;
                                 69             870 :     amroutine->amcanreturn = NULL;
                                 70             870 :     amroutine->amcostestimate = gincostestimate;
                                 71             870 :     amroutine->amoptions = ginoptions;
 2430                            72             870 :     amroutine->amproperty = NULL;
 1468 alvherre                   73             870 :     amroutine->ambuildphasename = NULL;
 2639 tgl                        74             870 :     amroutine->amvalidate = ginvalidate;
  981                            75             870 :     amroutine->amadjustmembers = ginadjustmembers;
 2639                            76             870 :     amroutine->ambeginscan = ginbeginscan;
                                 77             870 :     amroutine->amrescan = ginrescan;
                                 78             870 :     amroutine->amgettuple = NULL;
                                 79             870 :     amroutine->amgetbitmap = gingetbitmap;
                                 80             870 :     amroutine->amendscan = ginendscan;
                                 81             870 :     amroutine->ammarkpos = NULL;
                                 82             870 :     amroutine->amrestrpos = NULL;
 2266 rhaas                      83             870 :     amroutine->amestimateparallelscan = NULL;
                                 84             870 :     amroutine->aminitparallelscan = NULL;
                                 85             870 :     amroutine->amparallelrescan = NULL;
 2639 tgl                        86 ECB             : 
 2639 tgl                        87 GIC         870 :     PG_RETURN_POINTER(amroutine);
 2639 tgl                        88 ECB             : }
                                 89                 : 
                                 90                 : /*
                                 91                 :  * initGinState: fill in an empty GinState struct to describe the index
                                 92                 :  *
                                 93                 :  * Note: assorted subsidiary data is allocated in the CurrentMemoryContext.
                                 94                 :  */
                                 95                 : void
 6031 bruce                      96 GIC        1064 : initGinState(GinState *state, Relation index)
 6031 bruce                      97 ECB             : {
 4475 tgl                        98 GIC        1064 :     TupleDesc   origTupdesc = RelationGetDescr(index);
 5050 bruce                      99 ECB             :     int         i;
                                100                 : 
 4475 tgl                       101 GIC        1064 :     MemSet(state, 0, sizeof(GinState));
 5385 tgl                       102 ECB             : 
 4475 tgl                       103 GIC        1064 :     state->index = index;
  578 michael                   104 CBC        1064 :     state->oneCol = (origTupdesc->natts == 1);
 4475 tgl                       105            1064 :     state->origTupdesc = origTupdesc;
 5385 tgl                       106 ECB             : 
 4475 tgl                       107 GIC        2269 :     for (i = 0; i < origTupdesc->natts; i++)
 5385 tgl                       108 ECB             :     {
 2058 andres                    109 GIC        1205 :         Form_pg_attribute attr = TupleDescAttr(origTupdesc, i);
 2058 andres                    110 ECB             : 
 4475 tgl                       111 GIC        1205 :         if (state->oneCol)
 4475 tgl                       112 CBC         923 :             state->tupdesc[i] = state->origTupdesc;
 4475 tgl                       113 ECB             :         else
                                114                 :         {
 1601 andres                    115 GIC         282 :             state->tupdesc[i] = CreateTemplateTupleDesc(2);
 4475 tgl                       116 ECB             : 
 4475 tgl                       117 GIC         282 :             TupleDescInitEntry(state->tupdesc[i], (AttrNumber) 1, NULL,
 4475 tgl                       118 ECB             :                                INT2OID, -1, 0);
 4475 tgl                       119 GIC         282 :             TupleDescInitEntry(state->tupdesc[i], (AttrNumber) 2, NULL,
 2058 andres                    120 ECB             :                                attr->atttypid,
                                121                 :                                attr->atttypmod,
 2058 andres                    122 GIC         282 :                                attr->attndims);
 4397 tgl                       123 CBC         282 :             TupleDescInitEntryCollation(state->tupdesc[i], (AttrNumber) 2,
 2058 andres                    124 ECB             :                                         attr->attcollation);
                                125                 :         }
                                126                 : 
                                127                 :         /*
                                128                 :          * If the compare proc isn't specified in the opclass definition, look
                                129                 :          * up the index key type's default btree comparator.
                                130                 :          */
 2386 tgl                       131 GIC        1205 :         if (index_getprocid(index, i + 1, GIN_COMPARE_PROC) != InvalidOid)
 2386 tgl                       132 ECB             :         {
 2386 tgl                       133 GIC         640 :             fmgr_info_copy(&(state->compareFn[i]),
 2386 tgl                       134 CBC         640 :                            index_getprocinfo(index, i + 1, GIN_COMPARE_PROC),
 2386 tgl                       135 ECB             :                            CurrentMemoryContext);
                                136                 :         }
                                137                 :         else
                                138                 :         {
                                139                 :             TypeCacheEntry *typentry;
                                140                 : 
 2058 andres                    141 GIC         565 :             typentry = lookup_type_cache(attr->atttypid,
 2386 tgl                       142 ECB             :                                          TYPECACHE_CMP_PROC_FINFO);
 2386 tgl                       143 GIC         565 :             if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
 2386 tgl                       144 LBC           0 :                 ereport(ERROR,
 2386 tgl                       145 EUB             :                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
                                146                 :                          errmsg("could not identify a comparison function for type %s",
                                147                 :                                 format_type_be(attr->atttypid))));
 2386 tgl                       148 GIC         565 :             fmgr_info_copy(&(state->compareFn[i]),
 2386 tgl                       149 ECB             :                            &(typentry->cmp_proc_finfo),
                                150                 :                            CurrentMemoryContext);
                                151                 :         }
                                152                 : 
                                153                 :         /* Opclass must always provide extract procs */
 5385 tgl                       154 GIC        1205 :         fmgr_info_copy(&(state->extractValueFn[i]),
 5050 bruce                     155 CBC        1205 :                        index_getprocinfo(index, i + 1, GIN_EXTRACTVALUE_PROC),
 5050 bruce                     156 ECB             :                        CurrentMemoryContext);
 5385 tgl                       157 GIC        1205 :         fmgr_info_copy(&(state->extractQueryFn[i]),
 5050 bruce                     158 CBC        1205 :                        index_getprocinfo(index, i + 1, GIN_EXTRACTQUERY_PROC),
 5050 bruce                     159 ECB             :                        CurrentMemoryContext);
                                160                 : 
                                161                 :         /*
                                162                 :          * Check opclass capability to do tri-state or binary logic consistent
                                163                 :          * check.
                                164                 :          */
 3315 heikki.linnakangas        165 GIC        1205 :         if (index_getprocid(index, i + 1, GIN_TRICONSISTENT_PROC) != InvalidOid)
 3315 heikki.linnakangas        166 ECB             :         {
 3315 heikki.linnakangas        167 GIC        1003 :             fmgr_info_copy(&(state->triConsistentFn[i]),
 2118 tgl                       168 CBC        1003 :                            index_getprocinfo(index, i + 1, GIN_TRICONSISTENT_PROC),
 3315 heikki.linnakangas        169 ECB             :                            CurrentMemoryContext);
                                170                 :         }
                                171                 : 
 3315 heikki.linnakangas        172 GIC        1205 :         if (index_getprocid(index, i + 1, GIN_CONSISTENT_PROC) != InvalidOid)
 3315 heikki.linnakangas        173 ECB             :         {
 3315 heikki.linnakangas        174 GIC        1205 :             fmgr_info_copy(&(state->consistentFn[i]),
 2118 tgl                       175 CBC        1205 :                            index_getprocinfo(index, i + 1, GIN_CONSISTENT_PROC),
 3315 heikki.linnakangas        176 ECB             :                            CurrentMemoryContext);
                                177                 :         }
                                178                 : 
 3315 heikki.linnakangas        179 GIC        1205 :         if (state->consistentFn[i].fn_oid == InvalidOid &&
 3315 heikki.linnakangas        180 LBC           0 :             state->triConsistentFn[i].fn_oid == InvalidOid)
 3315 heikki.linnakangas        181 EUB             :         {
 3315 heikki.linnakangas        182 UIC           0 :             elog(ERROR, "missing GIN support function (%d or %d) for attribute %d of index \"%s\"",
 3315 heikki.linnakangas        183 EUB             :                  GIN_CONSISTENT_PROC, GIN_TRICONSISTENT_PROC,
                                184                 :                  i + 1, RelationGetRelationName(index));
                                185                 :         }
                                186                 : 
                                187                 :         /*
                                188                 :          * Check opclass capability to do partial match.
                                189                 :          */
 5050 bruce                     190 GIC        1205 :         if (index_getprocid(index, i + 1, GIN_COMPARE_PARTIAL_PROC) != InvalidOid)
 5385 tgl                       191 ECB             :         {
 5385 tgl                       192 GIC         302 :             fmgr_info_copy(&(state->comparePartialFn[i]),
 2118 tgl                       193 CBC         302 :                            index_getprocinfo(index, i + 1, GIN_COMPARE_PARTIAL_PROC),
 5385 tgl                       194 ECB             :                            CurrentMemoryContext);
 5385 tgl                       195 GIC         302 :             state->canPartialMatch[i] = true;
 5385 tgl                       196 ECB             :         }
                                197                 :         else
                                198                 :         {
 5385 tgl                       199 GIC         903 :             state->canPartialMatch[i] = false;
 5385 tgl                       200 ECB             :         }
                                201                 : 
                                202                 :         /*
                                203                 :          * If the index column has a specified collation, we should honor that
                                204                 :          * while doing comparisons.  However, we may have a collatable storage
                                205                 :          * type for a noncollatable indexed data type (for instance, hstore
                                206                 :          * uses text index entries).  If there's no index collation then
                                207                 :          * specify default collation in case the support functions need
                                208                 :          * collation.  This is harmless if the support functions don't care
                                209                 :          * about collation, so we just do it unconditionally.  (We could
                                210                 :          * alternatively call get_typcollation, but that seems like expensive
                                211                 :          * overkill --- there aren't going to be any cases where a GIN storage
                                212                 :          * type has a nondefault collation.)
                                213                 :          */
 4380 tgl                       214 GIC        1205 :         if (OidIsValid(index->rd_indcollation[i]))
 4370 tgl                       215 CBC         171 :             state->supportCollation[i] = index->rd_indcollation[i];
 4380 tgl                       216 ECB             :         else
 4370 tgl                       217 GIC        1034 :             state->supportCollation[i] = DEFAULT_COLLATION_OID;
 5385 tgl                       218 ECB             :     }
 5385 tgl                       219 GIC        1064 : }
 5385 tgl                       220 ECB             : 
                                221                 : /*
                                222                 :  * Extract attribute (column) number of stored entry from GIN tuple
                                223                 :  */
                                224                 : OffsetNumber
 5385 tgl                       225 GIC     6404657 : gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple)
 5385 tgl                       226 ECB             : {
                                227                 :     OffsetNumber colN;
                                228                 : 
 4475 tgl                       229 GIC     6404657 :     if (ginstate->oneCol)
 4475 tgl                       230 ECB             :     {
                                231                 :         /* column number is not stored explicitly */
 4475 tgl                       232 GIC     2075192 :         colN = FirstOffsetNumber;
 4475 tgl                       233 ECB             :     }
                                234                 :     else
                                235                 :     {
                                236                 :         Datum       res;
                                237                 :         bool        isnull;
                                238                 : 
                                239                 :         /*
                                240                 :          * First attribute is always int16, so we can safely use any tuple
                                241                 :          * descriptor to obtain first attribute of tuple
                                242                 :          */
 5385 tgl                       243 GIC     4329465 :         res = index_getattr(tuple, FirstOffsetNumber, ginstate->tupdesc[0],
 5385 tgl                       244 ECB             :                             &isnull);
 5385 tgl                       245 GIC     4329465 :         Assert(!isnull);
 5441 tgl                       246 ECB             : 
 5385 tgl                       247 GIC     4329465 :         colN = DatumGetUInt16(res);
 5050 bruce                     248 CBC     4329465 :         Assert(colN >= FirstOffsetNumber && colN <= ginstate->origTupdesc->natts);
 5385 tgl                       249 ECB             :     }
                                250                 : 
 5385 tgl                       251 GIC     6404657 :     return colN;
 5385 tgl                       252 ECB             : }
                                253                 : 
                                254                 : /*
                                255                 :  * Extract stored datum (and possible null category) from GIN tuple
                                256                 :  */
                                257                 : Datum
 4475 tgl                       258 GIC     4239522 : gintuple_get_key(GinState *ginstate, IndexTuple tuple,
 4475 tgl                       259 ECB             :                  GinNullCategory *category)
                                260                 : {
                                261                 :     Datum       res;
                                262                 :     bool        isnull;
                                263                 : 
 5050 bruce                     264 GIC     4239522 :     if (ginstate->oneCol)
 5385 tgl                       265 ECB             :     {
                                266                 :         /*
                                267                 :          * Single column index doesn't store attribute numbers in tuples
                                268                 :          */
 5385 tgl                       269 GIC     2075154 :         res = index_getattr(tuple, FirstOffsetNumber, ginstate->origTupdesc,
 5385 tgl                       270 ECB             :                             &isnull);
                                271                 :     }
                                272                 :     else
                                273                 :     {
                                274                 :         /*
                                275                 :          * Since the datum type depends on which index column it's from, we
                                276                 :          * must be careful to use the right tuple descriptor here.
                                277                 :          */
 5385 tgl                       278 GIC     2164368 :         OffsetNumber colN = gintuple_get_attrnum(ginstate, tuple);
 5385 tgl                       279 ECB             : 
 5385 tgl                       280 GIC     2164368 :         res = index_getattr(tuple, OffsetNumberNext(FirstOffsetNumber),
 5385 tgl                       281 CBC     2164368 :                             ginstate->tupdesc[colN - 1],
 5385 tgl                       282 ECB             :                             &isnull);
                                283                 :     }
                                284                 : 
 4475 tgl                       285 GIC     4239522 :     if (isnull)
 4475 tgl                       286 CBC         897 :         *category = GinGetNullCategory(tuple, ginstate);
 4475 tgl                       287 ECB             :     else
 4475 tgl                       288 GIC     4238625 :         *category = GIN_CAT_NORM_KEY;
 5385 tgl                       289 ECB             : 
 5385 tgl                       290 GIC     4239522 :     return res;
 6186 teodor                    291 ECB             : }
                                292                 : 
                                293                 : /*
                                294                 :  * Allocate a new page (either by recycling, or by extending the index file)
                                295                 :  * The returned buffer is already pinned and exclusive-locked
                                296                 :  * Caller is responsible for initializing the page by calling GinInitBuffer
                                297                 :  */
                                298                 : Buffer
 6031 bruce                     299 GIC        3753 : GinNewBuffer(Relation index)
 6031 bruce                     300 ECB             : {
                                301                 :     Buffer      buffer;
                                302                 : 
                                303                 :     /* First, try to get a page from FSM */
                                304                 :     for (;;)
 6031 bruce                     305 UBC           0 :     {
 5304 heikki.linnakangas        306 CBC        3753 :         BlockNumber blkno = GetFreeIndexPage(index);
                                307                 : 
 6186 teodor                    308            3753 :         if (blkno == InvalidBlockNumber)
                                309            3701 :             break;
                                310                 : 
                                311              52 :         buffer = ReadBuffer(index, blkno);
                                312                 : 
                                313                 :         /*
                                314                 :          * We have to guard against the possibility that someone else already
                                315                 :          * recycled this page; the buffer may be locked if so.
                                316                 :          */
 6031 bruce                     317              52 :         if (ConditionalLockBuffer(buffer))
                                318                 :         {
 1578 akorotkov                 319              52 :             if (GinPageIsRecyclable(BufferGetPage(buffer)))
 6031 bruce                     320              52 :                 return buffer;  /* OK to use */
                                321                 : 
 6186 teodor                    322 UBC           0 :             LockBuffer(buffer, GIN_UNLOCK);
                                323                 :         }
                                324                 : 
                                325                 :         /* Can't use it, so release buffer and try again */
                                326               0 :         ReleaseBuffer(buffer);
                                327                 :     }
                                328                 : 
                                329                 :     /* Must extend the file */
    4 andres                    330 GNC        3701 :     buffer = ExtendBufferedRel(EB_REL(index), MAIN_FORKNUM, NULL,
                                331                 :                                EB_LOCK_FIRST);
                                332                 : 
 6186 teodor                    333 GIC        3701 :     return buffer;
 6186 teodor                    334 ECB             : }
                                335                 : 
                                336                 : void
 6031 bruce                     337 CBC       29924 : GinInitPage(Page page, uint32 f, Size pageSize)
 6031 bruce                     338 ECB             : {
 6186 teodor                    339                 :     GinPageOpaque opaque;
                                340                 : 
 6186 teodor                    341 GIC       29924 :     PageInit(page, pageSize, sizeof(GinPageOpaqueData));
 6186 teodor                    342 ECB             : 
 6186 teodor                    343 GIC       29924 :     opaque = GinPageGetOpaque(page);
 6031 bruce                     344 CBC       29924 :     opaque->flags = f;
 6186 teodor                    345           29924 :     opaque->rightlink = InvalidBlockNumber;
 6186 teodor                    346 GIC       29924 : }
                                347                 : 
 6186 teodor                    348 ECB             : void
 6031 bruce                     349 GIC        1945 : GinInitBuffer(Buffer b, uint32 f)
                                350                 : {
 2545 kgrittn                   351 CBC        1945 :     GinInitPage(BufferGetPage(b), f, BufferGetPageSize(b));
 6186 teodor                    352 GIC        1945 : }
 6186 teodor                    353 ECB             : 
                                354                 : void
 5129 tgl                       355 CBC       24111 : GinInitMetabuffer(Buffer b)
                                356                 : {
 5050 bruce                     357 ECB             :     GinMetaPageData *metadata;
 2545 kgrittn                   358 CBC       24111 :     Page        page = BufferGetPage(b);
 5129 tgl                       359 ECB             : 
 5129 tgl                       360 CBC       24111 :     GinInitPage(page, GIN_META, BufferGetPageSize(b));
 5129 tgl                       361 ECB             : 
 5129 tgl                       362 CBC       24111 :     metadata = GinPageGetMeta(page);
 5129 tgl                       363 ECB             : 
 5129 tgl                       364 CBC       24111 :     metadata->head = metadata->tail = InvalidBlockNumber;
                                365           24111 :     metadata->tailFreeSize = 0;
 5129 tgl                       366 GIC       24111 :     metadata->nPendingPages = 0;
                                367           24111 :     metadata->nPendingHeapTuples = 0;
 4557                           368           24111 :     metadata->nTotalPages = 0;
                                369           24111 :     metadata->nEntryPages = 0;
                                370           24111 :     metadata->nDataPages = 0;
                                371           24111 :     metadata->nEntries = 0;
 4475 tgl                       372 CBC       24111 :     metadata->ginVersion = GIN_CURRENT_VERSION;
 1984 tgl                       373 ECB             : 
                                374                 :     /*
                                375                 :      * Set pd_lower just past the end of the metadata.  This is essential,
                                376                 :      * because without doing so, metadata will be lost if xlog.c compresses
                                377                 :      * the page.
                                378                 :      */
 1984 tgl                       379 GIC       24111 :     ((PageHeader) page)->pd_lower =
 1984 tgl                       380 CBC       24111 :         ((char *) metadata + sizeof(GinMetaPageData)) - (char *) page;
 5129 tgl                       381 GIC       24111 : }
                                382                 : 
                                383                 : /*
                                384                 :  * Compare two keys of the same index column
 4475 tgl                       385 ECB             :  */
 6186 teodor                    386                 : int
 4475 tgl                       387 GIC    15768535 : ginCompareEntries(GinState *ginstate, OffsetNumber attnum,
                                388                 :                   Datum a, GinNullCategory categorya,
 4475 tgl                       389 ECB             :                   Datum b, GinNullCategory categoryb)
 6031 bruce                     390                 : {
                                391                 :     /* if not of same null category, sort by that first */
 4475 tgl                       392 GIC    15768535 :     if (categorya != categoryb)
 4475 tgl                       393 CBC      311907 :         return (categorya < categoryb) ? -1 : 1;
 4475 tgl                       394 ECB             : 
                                395                 :     /* all null items in same category are equal */
 4475 tgl                       396 GIC    15456628 :     if (categorya != GIN_CAT_NORM_KEY)
                                397            4148 :         return 0;
                                398                 : 
                                399                 :     /* both not null, so safe to call the compareFn */
 4380                           400        15452480 :     return DatumGetInt32(FunctionCall2Coll(&ginstate->compareFn[attnum - 1],
 2118                           401        15452480 :                                            ginstate->supportCollation[attnum - 1],
 4380 tgl                       402 ECB             :                                            a, b));
                                403                 : }
                                404                 : 
                                405                 : /*
                                406                 :  * Compare two keys of possibly different index columns
 4475                           407                 :  */
 5385                           408                 : int
 4475 tgl                       409 GIC    16035167 : ginCompareAttEntries(GinState *ginstate,
 4475 tgl                       410 ECB             :                      OffsetNumber attnuma, Datum a, GinNullCategory categorya,
                                411                 :                      OffsetNumber attnumb, Datum b, GinNullCategory categoryb)
                                412                 : {
                                413                 :     /* attribute number is the first sort key */
 4475 tgl                       414 GIC    16035167 :     if (attnuma != attnumb)
                                415          268890 :         return (attnuma < attnumb) ? -1 : 1;
                                416                 : 
                                417        15766277 :     return ginCompareEntries(ginstate, attnuma, a, categorya, b, categoryb);
                                418                 : }
                                419                 : 
                                420                 : 
                                421                 : /*
                                422                 :  * Support for sorting key datums in ginExtractEntries
                                423                 :  *
                                424                 :  * Note: we only have to worry about null and not-null keys here;
                                425                 :  * ginExtractEntries never generates more than one placeholder null,
                                426                 :  * so it doesn't have to sort those.
                                427                 :  */
                                428                 : typedef struct
                                429                 : {
                                430                 :     Datum       datum;
                                431                 :     bool        isnull;
                                432                 : } keyEntryData;
                                433                 : 
                                434                 : typedef struct
 6030 tgl                       435 ECB             : {
                                436                 :     FmgrInfo   *cmpDatumFunc;
 4380                           437                 :     Oid         collation;
 4475                           438                 :     bool        haveDups;
                                439                 : } cmpEntriesArg;
                                440                 : 
                                441                 : static int
 4475 tgl                       442 CBC      928437 : cmpEntries(const void *a, const void *b, void *arg)
                                443                 : {
 4475 tgl                       444 GBC      928437 :     const keyEntryData *aa = (const keyEntryData *) a;
                                445          928437 :     const keyEntryData *bb = (const keyEntryData *) b;
 4475 tgl                       446 GIC      928437 :     cmpEntriesArg *data = (cmpEntriesArg *) arg;
 4475 tgl                       447 EUB             :     int         res;
                                448                 : 
 4475 tgl                       449 CBC      928437 :     if (aa->isnull)
 4475 tgl                       450 EUB             :     {
 4475 tgl                       451 UIC           0 :         if (bb->isnull)
 4475 tgl                       452 LBC           0 :             res = 0;            /* NULL "=" NULL */
                                453                 :         else
                                454               0 :             res = 1;            /* NULL ">" not-NULL */
                                455                 :     }
 4475 tgl                       456 GIC      928437 :     else if (bb->isnull)
 4475 tgl                       457 UIC           0 :         res = -1;               /* not-NULL "<" NULL */
                                458                 :     else
 4380 tgl                       459 GIC      928437 :         res = DatumGetInt32(FunctionCall2Coll(data->cmpDatumFunc,
                                460                 :                                               data->collation,
 4380 tgl                       461 CBC      928437 :                                               aa->datum, bb->datum));
 4475 tgl                       462 ECB             : 
                                463                 :     /*
 4382 bruce                     464                 :      * Detect if we have any duplicates.  If there are equal keys, qsort must
                                465                 :      * compare them at some point, else it wouldn't know whether one should go
                                466                 :      * before or after the other.
                                467                 :      */
 6031 bruce                     468 GIC      928437 :     if (res == 0)
 4475 tgl                       469           15502 :         data->haveDups = true;
                                470                 : 
 6186 teodor                    471          928437 :     return res;
                                472                 : }
                                473                 : 
                                474                 : 
 4475 tgl                       475 ECB             : /*
                                476                 :  * Extract the index key values from an indexable item
                                477                 :  *
                                478                 :  * The resulting key values are sorted, and any duplicates are removed.
                                479                 :  * This avoids generating redundant index entries.
                                480                 :  */
                                481                 : Datum *
 4475 tgl                       482 GIC      642573 : ginExtractEntries(GinState *ginstate, OffsetNumber attnum,
                                483                 :                   Datum value, bool isNull,
                                484                 :                   int32 *nentries, GinNullCategory **categories)
                                485                 : {
                                486                 :     Datum      *entries;
 4475 tgl                       487 ECB             :     bool       *nullFlags;
                                488                 :     int32       i;
                                489                 : 
                                490                 :     /*
                                491                 :      * We don't call the extractValueFn on a null item.  Instead generate a
                                492                 :      * placeholder.
                                493                 :      */
 4475 tgl                       494 CBC      642573 :     if (isNull)
                                495                 :     {
 4475 tgl                       496 GIC        3311 :         *nentries = 1;
                                497            3311 :         entries = (Datum *) palloc(sizeof(Datum));
 4475 tgl                       498 CBC        3311 :         entries[0] = (Datum) 0;
 4475 tgl                       499 GIC        3311 :         *categories = (GinNullCategory *) palloc(sizeof(GinNullCategory));
 4475 tgl                       500 CBC        3311 :         (*categories)[0] = GIN_CAT_NULL_ITEM;
                                501            3311 :         return entries;
                                502                 :     }
                                503                 : 
                                504                 :     /* OK, call the opclass's extractValueFn */
 4475 tgl                       505 GIC      639262 :     nullFlags = NULL;           /* in case extractValue doesn't set it */
                                506                 :     entries = (Datum *)
 4370                           507         1278524 :         DatumGetPointer(FunctionCall3Coll(&ginstate->extractValueFn[attnum - 1],
 2118                           508          639262 :                                           ginstate->supportCollation[attnum - 1],
 4370 tgl                       509 ECB             :                                           value,
                                510                 :                                           PointerGetDatum(nentries),
                                511                 :                                           PointerGetDatum(&nullFlags)));
 4475                           512                 : 
                                513                 :     /*
                                514                 :      * Generate a placeholder if the item contained no keys.
                                515                 :      */
 4475 tgl                       516 CBC      639262 :     if (entries == NULL || *nentries <= 0)
                                517                 :     {
 4475 tgl                       518 GIC         888 :         *nentries = 1;
                                519             888 :         entries = (Datum *) palloc(sizeof(Datum));
                                520             888 :         entries[0] = (Datum) 0;
                                521             888 :         *categories = (GinNullCategory *) palloc(sizeof(GinNullCategory));
                                522             888 :         (*categories)[0] = GIN_CAT_EMPTY_ITEM;
 4475 tgl                       523 CBC         888 :         return entries;
 4475 tgl                       524 ECB             :     }
                                525                 : 
                                526                 :     /*
                                527                 :      * If the extractValueFn didn't create a nullFlags array, create one,
                                528                 :      * assuming that everything's non-null.
                                529                 :      */
 4475 tgl                       530 GIC      638374 :     if (nullFlags == NULL)
                                531          110371 :         nullFlags = (bool *) palloc0(*nentries * sizeof(bool));
                                532                 : 
 4475 tgl                       533 ECB             :     /*
                                534                 :      * If there's more than one key, sort and unique-ify.
                                535                 :      *
                                536                 :      * XXX Using qsort here is notationally painful, and the overhead is
                                537                 :      * pretty bad too.  For small numbers of keys it'd likely be better to use
 4382 bruce                     538                 :      * a simple insertion sort.
 4475 tgl                       539                 :      */
 4475 tgl                       540 GIC      638374 :     if (*nentries > 1)
 6031 bruce                     541 ECB             :     {
 4475 tgl                       542                 :         keyEntryData *keydata;
                                543                 :         cmpEntriesArg arg;
                                544                 : 
 4475 tgl                       545 CBC      259268 :         keydata = (keyEntryData *) palloc(*nentries * sizeof(keyEntryData));
                                546         1179622 :         for (i = 0; i < *nentries; i++)
 4475 tgl                       547 ECB             :         {
 4475 tgl                       548 CBC      920354 :             keydata[i].datum = entries[i];
 4475 tgl                       549 GIC      920354 :             keydata[i].isnull = nullFlags[i];
                                550                 :         }
 4475 tgl                       551 ECB             : 
 4475 tgl                       552 GIC      259268 :         arg.cmpDatumFunc = &ginstate->compareFn[attnum - 1];
 4370                           553          259268 :         arg.collation = ginstate->supportCollation[attnum - 1];
 4475                           554          259268 :         arg.haveDups = false;
                                555          259268 :         qsort_arg(keydata, *nentries, sizeof(keyEntryData),
                                556                 :                   cmpEntries, &arg);
 6186 teodor                    557 ECB             : 
 4475 tgl                       558 CBC      259268 :         if (arg.haveDups)
 4475 tgl                       559 ECB             :         {
                                560                 :             /* there are duplicates, must get rid of 'em */
                                561                 :             int32       j;
                                562                 : 
 4475 tgl                       563 CBC        7514 :             entries[0] = keydata[0].datum;
                                564            7514 :             nullFlags[0] = keydata[0].isnull;
                                565            7514 :             j = 1;
 4475 tgl                       566 GIC       33965 :             for (i = 1; i < *nentries; i++)
                                567                 :             {
 4382 bruce                     568 CBC       26451 :                 if (cmpEntries(&keydata[i - 1], &keydata[i], &arg) != 0)
                                569                 :                 {
 4475 tgl                       570 GIC       18745 :                     entries[j] = keydata[i].datum;
                                571           18745 :                     nullFlags[j] = keydata[i].isnull;
                                572           18745 :                     j++;
 4475 tgl                       573 ECB             :                 }
                                574                 :             }
 4475 tgl                       575 CBC        7514 :             *nentries = j;
 4475 tgl                       576 ECB             :         }
                                577                 :         else
                                578                 :         {
                                579                 :             /* easy, no duplicates */
 4475 tgl                       580 CBC     1138143 :             for (i = 0; i < *nentries; i++)
                                581                 :             {
 4475 tgl                       582 GIC      886389 :                 entries[i] = keydata[i].datum;
                                583          886389 :                 nullFlags[i] = keydata[i].isnull;
                                584                 :             }
                                585                 :         }
 6186 teodor                    586 ECB             : 
 4475 tgl                       587 CBC      259268 :         pfree(keydata);
 6186 teodor                    588 ECB             :     }
                                589                 : 
 1930 peter_e                   590                 :     /*
                                591                 :      * Create GinNullCategory representation from nullFlags.
                                592                 :      */
 1930 peter_e                   593 GIC      638374 :     *categories = (GinNullCategory *) palloc0(*nentries * sizeof(GinNullCategory));
 1930 peter_e                   594 CBC     1930128 :     for (i = 0; i < *nentries; i++)
 1930 peter_e                   595 GIC     1291754 :         (*categories)[i] = (nullFlags[i] ? GIN_CAT_NULL_KEY : GIN_CAT_NORM_KEY);
                                596                 : 
 6186 teodor                    597          638374 :     return entries;
                                598                 : }
                                599                 : 
                                600                 : bytea *
 2639 tgl                       601             253 : ginoptions(Datum reloptions, bool validate)
 6125 bruce                     602 ECB             : {
                                603                 :     static const relopt_parse_elt tab[] = {
                                604                 :         {"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)},
                                605                 :         {"gin_pending_list_limit", RELOPT_TYPE_INT, offsetof(GinOptions,
                                606                 :                                                              pendingListCleanupSize)}
                                607                 :     };
                                608                 : 
 1251 michael                   609 GIC         253 :     return (bytea *) build_reloptions(reloptions, validate,
                                610                 :                                       RELOPT_KIND_GIN,
                                611                 :                                       sizeof(GinOptions),
                                612                 :                                       tab, lengthof(tab));
                                613                 : }
                                614                 : 
 4557 tgl                       615 ECB             : /*
                                616                 :  * Fetch index's statistical data into *stats
                                617                 :  *
                                618                 :  * Note: in the result, nPendingPages can be trusted to be up-to-date,
                                619                 :  * as can ginVersion; but the other fields are as of the last VACUUM.
                                620                 :  */
                                621                 : void
 4557 tgl                       622 CBC        1088 : ginGetStats(Relation index, GinStatsData *stats)
 4557 tgl                       623 ECB             : {
 4382 bruce                     624                 :     Buffer      metabuffer;
                                625                 :     Page        metapage;
                                626                 :     GinMetaPageData *metadata;
 4557 tgl                       627                 : 
 4557 tgl                       628 CBC        1088 :     metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO);
                                629            1088 :     LockBuffer(metabuffer, GIN_SHARE);
 2545 kgrittn                   630            1088 :     metapage = BufferGetPage(metabuffer);
 4557 tgl                       631            1088 :     metadata = GinPageGetMeta(metapage);
                                632                 : 
                                633            1088 :     stats->nPendingPages = metadata->nPendingPages;
                                634            1088 :     stats->nTotalPages = metadata->nTotalPages;
 4557 tgl                       635 GIC        1088 :     stats->nEntryPages = metadata->nEntryPages;
                                636            1088 :     stats->nDataPages = metadata->nDataPages;
                                637            1088 :     stats->nEntries = metadata->nEntries;
 4475                           638            1088 :     stats->ginVersion = metadata->ginVersion;
                                639                 : 
 4557                           640            1088 :     UnlockReleaseBuffer(metabuffer);
                                641            1088 : }
 4557 tgl                       642 ECB             : 
                                643                 : /*
                                644                 :  * Write the given statistics to the index's metapage
                                645                 :  *
                                646                 :  * Note: nPendingPages and ginVersion are *not* copied over
                                647                 :  */
                                648                 : void
 1467 heikki.linnakangas        649 CBC         179 : ginUpdateStats(Relation index, const GinStatsData *stats, bool is_build)
 4557 tgl                       650 ECB             : {
 4382 bruce                     651                 :     Buffer      metabuffer;
                                652                 :     Page        metapage;
                                653                 :     GinMetaPageData *metadata;
                                654                 : 
 4557 tgl                       655 CBC         179 :     metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO);
                                656             179 :     LockBuffer(metabuffer, GIN_EXCLUSIVE);
 2545 kgrittn                   657             179 :     metapage = BufferGetPage(metabuffer);
 4557 tgl                       658             179 :     metadata = GinPageGetMeta(metapage);
                                659                 : 
 4557 tgl                       660 GIC         179 :     START_CRIT_SECTION();
                                661                 : 
                                662             179 :     metadata->nTotalPages = stats->nTotalPages;
                                663             179 :     metadata->nEntryPages = stats->nEntryPages;
                                664             179 :     metadata->nDataPages = stats->nDataPages;
                                665             179 :     metadata->nEntries = stats->nEntries;
                                666                 : 
 1984 tgl                       667 ECB             :     /*
                                668                 :      * Set pd_lower just past the end of the metadata.  This is essential,
                                669                 :      * because without doing so, metadata will be lost if xlog.c compresses
                                670                 :      * the page.  (We must do this here because pre-v11 versions of PG did not
                                671                 :      * set the metapage's pd_lower correctly, so a pg_upgraded index might
                                672                 :      * contain the wrong value.)
                                673                 :      */
 1984 tgl                       674 GIC         179 :     ((PageHeader) metapage)->pd_lower =
                                675             179 :         ((char *) metadata + sizeof(GinMetaPageData)) - (char *) metapage;
                                676                 : 
 4557 tgl                       677 CBC         179 :     MarkBufferDirty(metabuffer);
 4557 tgl                       678 ECB             : 
 1467 heikki.linnakangas        679 CBC         179 :     if (RelationNeedsWAL(index) && !is_build)
 4557 tgl                       680 ECB             :     {
                                681                 :         XLogRecPtr  recptr;
 4382 bruce                     682                 :         ginxlogUpdateMeta data;
 4557 tgl                       683                 : 
  277 rhaas                     684 GNC          24 :         data.locator = index->rd_locator;
 4557 tgl                       685 GIC          24 :         data.ntuples = 0;
 4557 tgl                       686 CBC          24 :         data.newRightlink = data.prevTail = InvalidBlockNumber;
                                687              24 :         memcpy(&data.metadata, metadata, sizeof(GinMetaPageData));
                                688                 : 
 3062 heikki.linnakangas        689 GIC          24 :         XLogBeginInsert();
 3062 heikki.linnakangas        690 CBC          24 :         XLogRegisterData((char *) &data, sizeof(ginxlogUpdateMeta));
 1984 tgl                       691 GIC          24 :         XLogRegisterBuffer(0, metabuffer, REGBUF_WILL_INIT | REGBUF_STANDARD);
 4557 tgl                       692 ECB             : 
 3062 heikki.linnakangas        693 CBC          24 :         recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_UPDATE_META_PAGE);
 4557 tgl                       694 GIC          24 :         PageSetLSN(metapage, recptr);
                                695                 :     }
                                696                 : 
                                697             179 :     UnlockReleaseBuffer(metabuffer);
                                698                 : 
                                699             179 :     END_CRIT_SECTION();
                                700             179 : }
        

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