LCOV - differential code coverage report
Current view: top level - src/backend/access/brin - brin_minmax.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: bed3ffbf9d952be6c7d739d068cdce44c046dfb7 vs 574581b50ac9c63dd9e4abebb731a3b67e5b50f6 Lines: 97.4 % 117 114 3 5 109 5
Current Date: 2026-05-05 10:23:31 +0900 Functions: 100.0 % 5 5 2 3
Baseline: lcov-20260505-025707-baseline Branches: 72.2 % 54 39 15 39
Baseline Date: 2026-05-05 10:27:06 +0900 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 100.0 % 5 5 5
(360..) days: 97.3 % 112 109 3 109
Function coverage date bins:
(360..) days: 100.0 % 5 5 2 3
Branch coverage date bins:
(360..) days: 72.2 % 54 39 15 39

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*
                                  2                 :                :  * brin_minmax.c
                                  3                 :                :  *      Implementation of Min/Max opclass for BRIN
                                  4                 :                :  *
                                  5                 :                :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
                                  6                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  7                 :                :  *
                                  8                 :                :  * IDENTIFICATION
                                  9                 :                :  *    src/backend/access/brin/brin_minmax.c
                                 10                 :                :  */
                                 11                 :                : #include "postgres.h"
                                 12                 :                : 
                                 13                 :                : #include "access/brin_internal.h"
                                 14                 :                : #include "access/brin_tuple.h"
                                 15                 :                : #include "access/stratnum.h"
                                 16                 :                : #include "catalog/pg_amop.h"
                                 17                 :                : #include "utils/datum.h"
                                 18                 :                : #include "utils/fmgrprotos.h"
                                 19                 :                : #include "utils/lsyscache.h"
                                 20                 :                : #include "utils/rel.h"
                                 21                 :                : #include "utils/syscache.h"
                                 22                 :                : 
                                 23                 :                : typedef struct MinmaxOpaque
                                 24                 :                : {
                                 25                 :                :     Oid         cached_subtype;
                                 26                 :                :     FmgrInfo    strategy_procinfos[BTMaxStrategyNumber];
                                 27                 :                : } MinmaxOpaque;
                                 28                 :                : 
                                 29                 :                : static FmgrInfo *minmax_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno,
                                 30                 :                :                                               Oid subtype, uint16 strategynum);
                                 31                 :                : 
                                 32                 :                : 
                                 33                 :                : Datum
 4172 tgl@sss.pgh.pa.us          34                 :CBC       27337 : brin_minmax_opcinfo(PG_FUNCTION_ARGS)
                                 35                 :                : {
 4197 alvherre@alvh.no-ip.       36                 :          27337 :     Oid         typoid = PG_GETARG_OID(0);
                                 37                 :                :     BrinOpcInfo *result;
                                 38                 :                : 
                                 39                 :                :     /*
                                 40                 :                :      * opaque->strategy_procinfos is initialized lazily; here it is set to
                                 41                 :                :      * all-uninitialized by palloc0 which sets fn_oid to InvalidOid.
                                 42                 :                :      */
                                 43                 :                : 
                                 44                 :          27337 :     result = palloc0(MAXALIGN(SizeofBrinOpcInfo(2)) +
                                 45                 :                :                      sizeof(MinmaxOpaque));
                                 46                 :          27337 :     result->oi_nstored = 2;
 1869 tomas.vondra@postgre       47                 :          27337 :     result->oi_regular_nulls = true;
 4197 alvherre@alvh.no-ip.       48                 :          27337 :     result->oi_opaque = (MinmaxOpaque *)
                                 49                 :          27337 :         MAXALIGN((char *) result + SizeofBrinOpcInfo(2));
 4016                            50                 :          27337 :     result->oi_typcache[0] = result->oi_typcache[1] =
                                 51                 :          27337 :         lookup_type_cache(typoid, 0);
                                 52                 :                : 
 4197                            53                 :          27337 :     PG_RETURN_POINTER(result);
                                 54                 :                : }
                                 55                 :                : 
                                 56                 :                : /*
                                 57                 :                :  * Examine the given index tuple (which contains partial status of a certain
                                 58                 :                :  * page range) by comparing it to the given value that comes from another heap
                                 59                 :                :  * tuple.  If the new value is outside the min/max range specified by the
                                 60                 :                :  * existing tuple values, update the index tuple and return true.  Otherwise,
                                 61                 :                :  * return false and do not modify in this case.
                                 62                 :                :  */
                                 63                 :                : Datum
 4172 tgl@sss.pgh.pa.us          64                 :         586086 : brin_minmax_add_value(PG_FUNCTION_ARGS)
                                 65                 :                : {
 4197 alvherre@alvh.no-ip.       66                 :         586086 :     BrinDesc   *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
                                 67                 :         586086 :     BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
                                 68                 :         586086 :     Datum       newval = PG_GETARG_DATUM(2);
  270 peter@eisentraut.org       69                 :GNC      586086 :     bool        isnull PG_USED_FOR_ASSERTS_ONLY = PG_GETARG_BOOL(3);
 4197 alvherre@alvh.no-ip.       70                 :CBC      586086 :     Oid         colloid = PG_GET_COLLATION();
                                 71                 :                :     FmgrInfo   *cmpFn;
                                 72                 :                :     Datum       compar;
                                 73                 :         586086 :     bool        updated = false;
                                 74                 :                :     Form_pg_attribute attr;
                                 75                 :                :     AttrNumber  attno;
                                 76                 :                : 
 1869 tomas.vondra@postgre       77         [ -  + ]:         586086 :     Assert(!isnull);
                                 78                 :                : 
 4197 alvherre@alvh.no-ip.       79                 :         586086 :     attno = column->bv_attno;
 3180 andres@anarazel.de         80                 :         586086 :     attr = TupleDescAttr(bdesc->bd_tupdesc, attno - 1);
                                 81                 :                : 
                                 82                 :                :     /*
                                 83                 :                :      * If the recorded value is null, store the new value (which we know to be
                                 84                 :                :      * not null) as both minimum and maximum, and we're done.
                                 85                 :                :      */
 4197 alvherre@alvh.no-ip.       86         [ +  + ]:         586086 :     if (column->bv_allnulls)
                                 87                 :                :     {
                                 88                 :          13456 :         column->bv_values[0] = datumCopy(newval, attr->attbyval, attr->attlen);
                                 89                 :          13456 :         column->bv_values[1] = datumCopy(newval, attr->attbyval, attr->attlen);
                                 90                 :          13456 :         column->bv_allnulls = false;
                                 91                 :          13456 :         PG_RETURN_BOOL(true);
                                 92                 :                :     }
                                 93                 :                : 
                                 94                 :                :     /*
                                 95                 :                :      * Otherwise, need to compare the new value with the existing boundaries
                                 96                 :                :      * and update them accordingly.  First check if it's less than the
                                 97                 :                :      * existing minimum.
                                 98                 :                :      */
 4016                            99                 :         572630 :     cmpFn = minmax_get_strategy_procinfo(bdesc, attno, attr->atttypid,
                                100                 :                :                                          BTLessStrategyNumber);
 4197                           101                 :         572630 :     compar = FunctionCall2Coll(cmpFn, colloid, newval, column->bv_values[0]);
                                102         [ +  + ]:         572630 :     if (DatumGetBool(compar))
                                103                 :                :     {
                                104         [ +  + ]:           1113 :         if (!attr->attbyval)
                                105                 :            833 :             pfree(DatumGetPointer(column->bv_values[0]));
                                106                 :           1113 :         column->bv_values[0] = datumCopy(newval, attr->attbyval, attr->attlen);
                                107                 :           1113 :         updated = true;
                                108                 :                :     }
                                109                 :                : 
                                110                 :                :     /*
                                111                 :                :      * And now compare it to the existing maximum.
                                112                 :                :      */
 4016                           113                 :         572630 :     cmpFn = minmax_get_strategy_procinfo(bdesc, attno, attr->atttypid,
                                114                 :                :                                          BTGreaterStrategyNumber);
 4197                           115                 :         572630 :     compar = FunctionCall2Coll(cmpFn, colloid, newval, column->bv_values[1]);
                                116         [ +  + ]:         572630 :     if (DatumGetBool(compar))
                                117                 :                :     {
                                118         [ +  + ]:         252063 :         if (!attr->attbyval)
                                119                 :          80488 :             pfree(DatumGetPointer(column->bv_values[1]));
                                120                 :         252063 :         column->bv_values[1] = datumCopy(newval, attr->attbyval, attr->attlen);
                                121                 :         252063 :         updated = true;
                                122                 :                :     }
                                123                 :                : 
                                124                 :         572630 :     PG_RETURN_BOOL(updated);
                                125                 :                : }
                                126                 :                : 
                                127                 :                : /*
                                128                 :                :  * Given an index tuple corresponding to a certain page range and a scan key,
                                129                 :                :  * return whether the scan key is consistent with the index tuple's min/max
                                130                 :                :  * values.  Return true if so, false otherwise.
                                131                 :                :  *
                                132                 :                :  * We're no longer dealing with NULL keys in the consistent function, that is
                                133                 :                :  * now handled by the AM code. That means we should not get any all-NULL ranges
                                134                 :                :  * either, because those can't be consistent with regular (not [IS] NULL) keys.
                                135                 :                :  */
                                136                 :                : Datum
 4172 tgl@sss.pgh.pa.us         137                 :          70088 : brin_minmax_consistent(PG_FUNCTION_ARGS)
                                138                 :                : {
 4197 alvherre@alvh.no-ip.      139                 :          70088 :     BrinDesc   *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
                                140                 :          70088 :     BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
 1866 tomas.vondra@postgre      141                 :          70088 :     ScanKey     key = (ScanKey) PG_GETARG_POINTER(2);
                                142                 :          70088 :     Oid         colloid = PG_GET_COLLATION(),
                                143                 :                :                 subtype;
                                144                 :                :     AttrNumber  attno;
                                145                 :                :     Datum       value;
                                146                 :                :     Datum       matches;
                                147                 :                :     FmgrInfo   *finfo;
                                148                 :                : 
                                149                 :                :     /* This opclass uses the old signature with only three arguments. */
                                150         [ -  + ]:          70088 :     Assert(PG_NARGS() == 3);
                                151                 :                : 
                                152                 :                :     /* Should not be dealing with all-NULL ranges. */
                                153         [ -  + ]:          70088 :     Assert(!column->bv_allnulls);
                                154                 :                : 
                                155                 :          70088 :     attno = key->sk_attno;
                                156                 :          70088 :     subtype = key->sk_subtype;
                                157                 :          70088 :     value = key->sk_argument;
 4197 alvherre@alvh.no-ip.      158   [ +  +  +  - ]:          70088 :     switch (key->sk_strategy)
                                159                 :                :     {
                                160                 :          28004 :         case BTLessStrategyNumber:
                                161                 :                :         case BTLessEqualStrategyNumber:
 4016                           162                 :          28004 :             finfo = minmax_get_strategy_procinfo(bdesc, attno, subtype,
                                163                 :          28004 :                                                  key->sk_strategy);
                                164                 :          28004 :             matches = FunctionCall2Coll(finfo, colloid, column->bv_values[0],
                                165                 :                :                                         value);
 4197                           166                 :          28004 :             break;
                                167                 :          12484 :         case BTEqualStrategyNumber:
                                168                 :                : 
                                169                 :                :             /*
                                170                 :                :              * In the equality case (WHERE col = someval), we want to return
                                171                 :                :              * the current page range if the minimum value in the range <=
                                172                 :                :              * scan key, and the maximum value >= scan key.
                                173                 :                :              */
 4016                           174                 :          12484 :             finfo = minmax_get_strategy_procinfo(bdesc, attno, subtype,
                                175                 :                :                                                  BTLessEqualStrategyNumber);
                                176                 :          12484 :             matches = FunctionCall2Coll(finfo, colloid, column->bv_values[0],
                                177                 :                :                                         value);
 4197                           178         [ +  + ]:          12484 :             if (!DatumGetBool(matches))
                                179                 :           6296 :                 break;
                                180                 :                :             /* max() >= scankey */
 4016                           181                 :           6188 :             finfo = minmax_get_strategy_procinfo(bdesc, attno, subtype,
                                182                 :                :                                                  BTGreaterEqualStrategyNumber);
                                183                 :           6188 :             matches = FunctionCall2Coll(finfo, colloid, column->bv_values[1],
                                184                 :                :                                         value);
 4197                           185                 :           6188 :             break;
                                186                 :          29600 :         case BTGreaterEqualStrategyNumber:
                                187                 :                :         case BTGreaterStrategyNumber:
 4016                           188                 :          29600 :             finfo = minmax_get_strategy_procinfo(bdesc, attno, subtype,
                                189                 :          29600 :                                                  key->sk_strategy);
                                190                 :          29600 :             matches = FunctionCall2Coll(finfo, colloid, column->bv_values[1],
                                191                 :                :                                         value);
 4197                           192                 :          29600 :             break;
 4197 alvherre@alvh.no-ip.      193                 :UBC           0 :         default:
                                194                 :                :             /* shouldn't happen */
                                195         [ #  # ]:              0 :             elog(ERROR, "invalid strategy number %d", key->sk_strategy);
                                196                 :                :             matches = 0;
                                197                 :                :             break;
                                198                 :                :     }
                                199                 :                : 
 1866 tomas.vondra@postgre      200                 :CBC       70088 :     PG_RETURN_DATUM(matches);
                                201                 :                : }
                                202                 :                : 
                                203                 :                : /*
                                204                 :                :  * Given two BrinValues, update the first of them as a union of the summary
                                205                 :                :  * values contained in both.  The second one is untouched.
                                206                 :                :  */
                                207                 :                : Datum
 4172 tgl@sss.pgh.pa.us         208                 :             48 : brin_minmax_union(PG_FUNCTION_ARGS)
                                209                 :                : {
 4197 alvherre@alvh.no-ip.      210                 :             48 :     BrinDesc   *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
                                211                 :             48 :     BrinValues *col_a = (BrinValues *) PG_GETARG_POINTER(1);
                                212                 :             48 :     BrinValues *col_b = (BrinValues *) PG_GETARG_POINTER(2);
                                213                 :             48 :     Oid         colloid = PG_GET_COLLATION();
                                214                 :                :     AttrNumber  attno;
                                215                 :                :     Form_pg_attribute attr;
                                216                 :                :     FmgrInfo   *finfo;
                                217                 :                :     bool        needsadj;
                                218                 :                : 
                                219         [ -  + ]:             48 :     Assert(col_a->bv_attno == col_b->bv_attno);
 1869 tomas.vondra@postgre      220   [ +  -  -  + ]:             48 :     Assert(!col_a->bv_allnulls && !col_b->bv_allnulls);
                                221                 :                : 
 4197 alvherre@alvh.no-ip.      222                 :             48 :     attno = col_a->bv_attno;
 3180 andres@anarazel.de        223                 :             48 :     attr = TupleDescAttr(bdesc->bd_tupdesc, attno - 1);
                                224                 :                : 
                                225                 :                :     /* Adjust minimum, if B's min is less than A's min */
 4016 alvherre@alvh.no-ip.      226                 :             48 :     finfo = minmax_get_strategy_procinfo(bdesc, attno, attr->atttypid,
                                227                 :                :                                          BTLessStrategyNumber);
  270 peter@eisentraut.org      228                 :GNC          48 :     needsadj = DatumGetBool(FunctionCall2Coll(finfo, colloid, col_b->bv_values[0],
                                229                 :             48 :                                               col_a->bv_values[0]));
 4197 alvherre@alvh.no-ip.      230         [ +  + ]:CBC          48 :     if (needsadj)
                                231                 :                :     {
                                232         [ +  + ]:             29 :         if (!attr->attbyval)
                                233                 :             18 :             pfree(DatumGetPointer(col_a->bv_values[0]));
                                234                 :             29 :         col_a->bv_values[0] = datumCopy(col_b->bv_values[0],
                                235                 :             29 :                                         attr->attbyval, attr->attlen);
                                236                 :                :     }
                                237                 :                : 
                                238                 :                :     /* Adjust maximum, if B's max is greater than A's max */
 4016                           239                 :             48 :     finfo = minmax_get_strategy_procinfo(bdesc, attno, attr->atttypid,
                                240                 :                :                                          BTGreaterStrategyNumber);
  270 peter@eisentraut.org      241                 :GNC          48 :     needsadj = DatumGetBool(FunctionCall2Coll(finfo, colloid, col_b->bv_values[1],
                                242                 :             48 :                                               col_a->bv_values[1]));
 4197 alvherre@alvh.no-ip.      243         [ +  + ]:CBC          48 :     if (needsadj)
                                244                 :                :     {
                                245         [ +  + ]:             32 :         if (!attr->attbyval)
                                246                 :             16 :             pfree(DatumGetPointer(col_a->bv_values[1]));
                                247                 :             32 :         col_a->bv_values[1] = datumCopy(col_b->bv_values[1],
                                248                 :             32 :                                         attr->attbyval, attr->attlen);
                                249                 :                :     }
                                250                 :                : 
                                251                 :             48 :     PG_RETURN_VOID();
                                252                 :                : }
                                253                 :                : 
                                254                 :                : /*
                                255                 :                :  * Cache and return the procedure for the given strategy.
                                256                 :                :  *
                                257                 :                :  * Note: this function mirrors inclusion_get_strategy_procinfo; see notes
                                258                 :                :  * there.  If changes are made here, see that function too.
                                259                 :                :  */
                                260                 :                : static FmgrInfo *
 4016                           261                 :        1221632 : minmax_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno, Oid subtype,
                                262                 :                :                              uint16 strategynum)
                                263                 :                : {
                                264                 :                :     MinmaxOpaque *opaque;
                                265                 :                : 
                                266   [ +  -  -  + ]:        1221632 :     Assert(strategynum >= 1 &&
                                267                 :                :            strategynum <= BTMaxStrategyNumber);
                                268                 :                : 
 4197                           269                 :        1221632 :     opaque = (MinmaxOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
                                270                 :                : 
                                271                 :                :     /*
                                272                 :                :      * We cache the procedures for the previous subtype in the opaque struct,
                                273                 :                :      * to avoid repetitive syscache lookups.  If the subtype changed,
                                274                 :                :      * invalidate all the cached entries.
                                275                 :                :      */
 4016                           276         [ +  + ]:        1221632 :     if (opaque->cached_subtype != subtype)
                                277                 :                :     {
                                278                 :                :         uint16      i;
                                279                 :                : 
                                280         [ +  + ]:           9924 :         for (i = 1; i <= BTMaxStrategyNumber; i++)
                                281                 :           8270 :             opaque->strategy_procinfos[i - 1].fn_oid = InvalidOid;
                                282                 :           1654 :         opaque->cached_subtype = subtype;
                                283                 :                :     }
                                284                 :                : 
                                285         [ +  + ]:        1221632 :     if (opaque->strategy_procinfos[strategynum - 1].fn_oid == InvalidOid)
                                286                 :                :     {
                                287                 :                :         Form_pg_attribute attr;
                                288                 :                :         HeapTuple   tuple;
                                289                 :                :         Oid         opfamily,
                                290                 :                :                     oprid;
                                291                 :                : 
                                292                 :           2728 :         opfamily = bdesc->bd_index->rd_opfamily[attno - 1];
 3180 andres@anarazel.de        293                 :           2728 :         attr = TupleDescAttr(bdesc->bd_tupdesc, attno - 1);
 4016 alvherre@alvh.no-ip.      294                 :           2728 :         tuple = SearchSysCache4(AMOPSTRATEGY, ObjectIdGetDatum(opfamily),
                                295                 :                :                                 ObjectIdGetDatum(attr->atttypid),
                                296                 :                :                                 ObjectIdGetDatum(subtype),
                                297                 :                :                                 UInt16GetDatum(strategynum));
                                298                 :                : 
                                299         [ -  + ]:           2728 :         if (!HeapTupleIsValid(tuple))
 4016 alvherre@alvh.no-ip.      300         [ #  # ]:UBC           0 :             elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
                                301                 :                :                  strategynum, attr->atttypid, subtype, opfamily);
                                302                 :                : 
 1137 dgustafsson@postgres      303                 :CBC        2728 :         oprid = DatumGetObjectId(SysCacheGetAttrNotNull(AMOPSTRATEGY, tuple,
                                304                 :                :                                                         Anum_pg_amop_amopopr));
 4016 alvherre@alvh.no-ip.      305                 :           2728 :         ReleaseSysCache(tuple);
 1137 dgustafsson@postgres      306         [ -  + ]:           2728 :         Assert(RegProcedureIsValid(oprid));
                                307                 :                : 
 4016 alvherre@alvh.no-ip.      308                 :           2728 :         fmgr_info_cxt(get_opcode(oprid),
                                309                 :           2728 :                       &opaque->strategy_procinfos[strategynum - 1],
                                310                 :                :                       bdesc->bd_context);
                                311                 :                :     }
                                312                 :                : 
                                313                 :        1221632 :     return &opaque->strategy_procinfos[strategynum - 1];
                                314                 :                : }
        

Generated by: LCOV version 2.5.0-beta