LCOV - code coverage report
Current view: top level - contrib/btree_gist - btree_utils_num.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 96.5 % 201 194
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 8 8
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 92.8 % 83 77

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * contrib/btree_gist/btree_utils_num.c
       3                 :             :  */
       4                 :             : #include "postgres.h"
       5                 :             : 
       6                 :             : #include "btree_gist.h"
       7                 :             : #include "btree_utils_num.h"
       8                 :             : #include "utils/cash.h"
       9                 :             : #include "utils/date.h"
      10                 :             : #include "utils/timestamp.h"
      11                 :             : 
      12                 :             : 
      13                 :             : GISTENTRY *
      14                 :       12487 : gbt_num_compress(GISTENTRY *entry, const gbtree_ninfo *tinfo)
      15                 :             : {
      16                 :             :     GISTENTRY  *retval;
      17                 :             : 
      18         [ +  + ]:       12487 :     if (entry->leafkey)
      19                 :             :     {
      20                 :             :         union
      21                 :             :         {
      22                 :             :             bool        bo;
      23                 :             :             int16       i2;
      24                 :             :             int32       i4;
      25                 :             :             int64       i8;
      26                 :             :             float4      f4;
      27                 :             :             float8      f8;
      28                 :             :             DateADT     dt;
      29                 :             :             TimeADT     tm;
      30                 :             :             Timestamp   ts;
      31                 :             :             Cash        ch;
      32                 :             :         }           v;
      33                 :             : 
      34                 :       12401 :         GBT_NUMKEY *r = (GBT_NUMKEY *) palloc0(tinfo->indexsize);
      35                 :       12401 :         void       *leaf = NULL;
      36                 :             : 
      37   [ +  +  +  +  :       12401 :         switch (tinfo->t)
          +  +  +  +  +  
                +  +  + ]
      38                 :             :         {
      39                 :           2 :             case gbt_t_bool:
      40                 :           2 :                 v.bo = DatumGetBool(entry->key);
      41                 :           2 :                 leaf = &v.bo;
      42                 :           2 :                 break;
      43                 :         546 :             case gbt_t_int2:
      44                 :         546 :                 v.i2 = DatumGetInt16(entry->key);
      45                 :         546 :                 leaf = &v.i2;
      46                 :         546 :                 break;
      47                 :        1078 :             case gbt_t_int4:
      48                 :        1078 :                 v.i4 = DatumGetInt32(entry->key);
      49                 :        1078 :                 leaf = &v.i4;
      50                 :        1078 :                 break;
      51                 :         547 :             case gbt_t_int8:
      52                 :         547 :                 v.i8 = DatumGetInt64(entry->key);
      53                 :         547 :                 leaf = &v.i8;
      54                 :         547 :                 break;
      55                 :        1532 :             case gbt_t_oid:
      56                 :             :             case gbt_t_enum:
      57                 :        1532 :                 v.i4 = DatumGetObjectId(entry->key);
      58                 :        1532 :                 leaf = &v.i4;
      59                 :        1532 :                 break;
      60                 :        1652 :             case gbt_t_float4:
      61                 :        1652 :                 v.f4 = DatumGetFloat4(entry->key);
      62                 :        1652 :                 leaf = &v.f4;
      63                 :        1652 :                 break;
      64                 :        1643 :             case gbt_t_float8:
      65                 :        1643 :                 v.f8 = DatumGetFloat8(entry->key);
      66                 :        1643 :                 leaf = &v.f8;
      67                 :        1643 :                 break;
      68                 :         544 :             case gbt_t_date:
      69                 :         544 :                 v.dt = DatumGetDateADT(entry->key);
      70                 :         544 :                 leaf = &v.dt;
      71                 :         544 :                 break;
      72                 :         544 :             case gbt_t_time:
      73                 :         544 :                 v.tm = DatumGetTimeADT(entry->key);
      74                 :         544 :                 leaf = &v.tm;
      75                 :         544 :                 break;
      76                 :        2570 :             case gbt_t_ts:
      77                 :        2570 :                 v.ts = DatumGetTimestamp(entry->key);
      78                 :        2570 :                 leaf = &v.ts;
      79                 :        2570 :                 break;
      80                 :         543 :             case gbt_t_cash:
      81                 :         543 :                 v.ch = DatumGetCash(entry->key);
      82                 :         543 :                 leaf = &v.ch;
      83                 :         543 :                 break;
      84                 :        1200 :             default:
      85                 :        1200 :                 leaf = DatumGetPointer(entry->key);
      86                 :             :         }
      87                 :             : 
      88                 :             :         Assert(tinfo->indexsize >= 2 * tinfo->size);
      89                 :             : 
      90                 :       12401 :         memcpy(&r[0], leaf, tinfo->size);
      91                 :       12401 :         memcpy(&r[tinfo->size], leaf, tinfo->size);
      92                 :       12401 :         retval = palloc_object(GISTENTRY);
      93                 :       12401 :         gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page,
      94                 :             :                       entry->offset, false);
      95                 :             :     }
      96                 :             :     else
      97                 :          86 :         retval = entry;
      98                 :             : 
      99                 :       12487 :     return retval;
     100                 :             : }
     101                 :             : 
     102                 :             : /*
     103                 :             :  * Convert a compressed leaf item back to the original type, for index-only
     104                 :             :  * scans.
     105                 :             :  */
     106                 :             : GISTENTRY *
     107                 :        5324 : gbt_num_fetch(GISTENTRY *entry, const gbtree_ninfo *tinfo)
     108                 :             : {
     109                 :             :     GISTENTRY  *retval;
     110                 :             :     Datum       datum;
     111                 :             : 
     112                 :             :     Assert(tinfo->indexsize >= 2 * tinfo->size);
     113                 :             : 
     114                 :             :     /*
     115                 :             :      * Get the original Datum from the stored datum. On leaf entries, the
     116                 :             :      * lower and upper bound are the same. We just grab the lower bound and
     117                 :             :      * return it.
     118                 :             :      */
     119   [ +  +  +  +  :        5324 :     switch (tinfo->t)
          -  +  +  +  +  
                +  +  + ]
     120                 :             :     {
     121                 :           7 :         case gbt_t_bool:
     122                 :           7 :             datum = BoolGetDatum(*(bool *) DatumGetPointer(entry->key));
     123                 :           7 :             break;
     124                 :         273 :         case gbt_t_int2:
     125                 :         273 :             datum = Int16GetDatum(*(int16 *) DatumGetPointer(entry->key));
     126                 :         273 :             break;
     127                 :         273 :         case gbt_t_int4:
     128                 :         273 :             datum = Int32GetDatum(*(int32 *) DatumGetPointer(entry->key));
     129                 :         273 :             break;
     130                 :         274 :         case gbt_t_int8:
     131                 :         274 :             datum = Int64GetDatum(*(int64 *) DatumGetPointer(entry->key));
     132                 :         274 :             break;
     133                 :           0 :         case gbt_t_oid:
     134                 :             :         case gbt_t_enum:
     135                 :           0 :             datum = ObjectIdGetDatum(*(Oid *) DatumGetPointer(entry->key));
     136                 :           0 :             break;
     137                 :         275 :         case gbt_t_float4:
     138                 :         275 :             datum = Float4GetDatum(*(float4 *) DatumGetPointer(entry->key));
     139                 :         275 :             break;
     140                 :         273 :         case gbt_t_float8:
     141                 :         273 :             datum = Float8GetDatum(*(float8 *) DatumGetPointer(entry->key));
     142                 :         273 :             break;
     143                 :         272 :         case gbt_t_date:
     144                 :         272 :             datum = DateADTGetDatum(*(DateADT *) DatumGetPointer(entry->key));
     145                 :         272 :             break;
     146                 :         272 :         case gbt_t_time:
     147                 :         272 :             datum = TimeADTGetDatum(*(TimeADT *) DatumGetPointer(entry->key));
     148                 :         272 :             break;
     149                 :         559 :         case gbt_t_ts:
     150                 :         559 :             datum = TimestampGetDatum(*(Timestamp *) DatumGetPointer(entry->key));
     151                 :         559 :             break;
     152                 :         272 :         case gbt_t_cash:
     153                 :         272 :             datum = CashGetDatum(*(Cash *) DatumGetPointer(entry->key));
     154                 :         272 :             break;
     155                 :        2574 :         default:
     156                 :        2574 :             datum = entry->key;
     157                 :             :     }
     158                 :             : 
     159                 :        5324 :     retval = palloc_object(GISTENTRY);
     160                 :        5324 :     gistentryinit(*retval, datum, entry->rel, entry->page, entry->offset,
     161                 :             :                   false);
     162                 :        5324 :     return retval;
     163                 :             : }
     164                 :             : 
     165                 :             : 
     166                 :             : 
     167                 :             : /*
     168                 :             :  * The GiST union method for numerical values
     169                 :             :  */
     170                 :             : 
     171                 :             : void *
     172                 :        2309 : gbt_num_union(GBT_NUMKEY *out, const GistEntryVector *entryvec, const gbtree_ninfo *tinfo, FmgrInfo *flinfo)
     173                 :             : {
     174                 :             :     int         i,
     175                 :             :                 numranges;
     176                 :             :     GBT_NUMKEY *cur;
     177                 :             :     GBT_NUMKEY_R o,
     178                 :             :                 c;
     179                 :             : 
     180                 :        2309 :     numranges = entryvec->n;
     181                 :        2309 :     cur = (GBT_NUMKEY *) DatumGetPointer((entryvec->vector[0].key));
     182                 :             : 
     183                 :             : 
     184                 :        2309 :     o.lower = &out[0];
     185                 :        2309 :     o.upper = &out[tinfo->size];
     186                 :             : 
     187                 :        2309 :     memcpy(out, cur, 2 * tinfo->size);
     188                 :             : 
     189         [ +  + ]:       24422 :     for (i = 1; i < numranges; i++)
     190                 :             :     {
     191                 :       22113 :         cur = (GBT_NUMKEY *) DatumGetPointer((entryvec->vector[i].key));
     192                 :       22113 :         c.lower = &cur[0];
     193                 :       22113 :         c.upper = &cur[tinfo->size];
     194                 :             :         /* if out->lower > cur->lower, adopt cur as lower */
     195         [ +  + ]:       22113 :         if (tinfo->f_gt(o.lower, c.lower, flinfo))
     196                 :        1283 :             memcpy(unconstify(GBT_NUMKEY *, o.lower), c.lower, tinfo->size);
     197                 :             :         /* if out->upper < cur->upper, adopt cur as upper */
     198         [ +  + ]:       22113 :         if (tinfo->f_lt(o.upper, c.upper, flinfo))
     199                 :       12801 :             memcpy(unconstify(GBT_NUMKEY *, o.upper), c.upper, tinfo->size);
     200                 :             :     }
     201                 :             : 
     202                 :        2309 :     return out;
     203                 :             : }
     204                 :             : 
     205                 :             : 
     206                 :             : 
     207                 :             : /*
     208                 :             :  * The GiST same method for numerical values
     209                 :             :  */
     210                 :             : 
     211                 :             : bool
     212                 :        2250 : gbt_num_same(const GBT_NUMKEY *a, const GBT_NUMKEY *b, const gbtree_ninfo *tinfo, FmgrInfo *flinfo)
     213                 :             : {
     214                 :             :     GBT_NUMKEY_R b1,
     215                 :             :                 b2;
     216                 :             : 
     217                 :        2250 :     b1.lower = &(a[0]);
     218                 :        2250 :     b1.upper = &(a[tinfo->size]);
     219                 :        2250 :     b2.lower = &(b[0]);
     220                 :        2250 :     b2.upper = &(b[tinfo->size]);
     221                 :             : 
     222   [ +  +  +  + ]:        4487 :     return (tinfo->f_eq(b1.lower, b2.lower, flinfo) &&
     223                 :        2237 :             tinfo->f_eq(b1.upper, b2.upper, flinfo));
     224                 :             : }
     225                 :             : 
     226                 :             : 
     227                 :             : void
     228                 :       22043 : gbt_num_bin_union(Datum *u, GBT_NUMKEY *e, const gbtree_ninfo *tinfo, FmgrInfo *flinfo)
     229                 :             : {
     230                 :             :     GBT_NUMKEY_R rd;
     231                 :             : 
     232                 :       22043 :     rd.lower = &e[0];
     233                 :       22043 :     rd.upper = &e[tinfo->size];
     234                 :             : 
     235         [ +  + ]:       22043 :     if (!DatumGetPointer(*u))
     236                 :             :     {
     237                 :         120 :         *u = PointerGetDatum(palloc0(tinfo->indexsize));
     238                 :         120 :         memcpy(&(((GBT_NUMKEY *) DatumGetPointer(*u))[0]), rd.lower, tinfo->size);
     239                 :         120 :         memcpy(&(((GBT_NUMKEY *) DatumGetPointer(*u))[tinfo->size]), rd.upper, tinfo->size);
     240                 :             :     }
     241                 :             :     else
     242                 :             :     {
     243                 :             :         GBT_NUMKEY_R ur;
     244                 :             : 
     245                 :       21923 :         ur.lower = &(((GBT_NUMKEY *) DatumGetPointer(*u))[0]);
     246                 :       21923 :         ur.upper = &(((GBT_NUMKEY *) DatumGetPointer(*u))[tinfo->size]);
     247         [ -  + ]:       21923 :         if (tinfo->f_gt(ur.lower, rd.lower, flinfo))
     248                 :           0 :             memcpy(unconstify(GBT_NUMKEY *, ur.lower), rd.lower, tinfo->size);
     249         [ +  + ]:       21923 :         if (tinfo->f_lt(ur.upper, rd.upper, flinfo))
     250                 :       16039 :             memcpy(unconstify(GBT_NUMKEY *, ur.upper), rd.upper, tinfo->size);
     251                 :             :     }
     252                 :       22043 : }
     253                 :             : 
     254                 :             : 
     255                 :             : 
     256                 :             : /*
     257                 :             :  * The GiST consistent method
     258                 :             :  *
     259                 :             :  * Note: we currently assume that no datatypes that use this routine are
     260                 :             :  * collation-aware; so we don't bother passing collation through.
     261                 :             :  */
     262                 :             : bool
     263                 :       46631 : gbt_num_consistent(const GBT_NUMKEY_R *key,
     264                 :             :                    const void *query,
     265                 :             :                    StrategyNumber strategy,
     266                 :             :                    bool is_leaf,
     267                 :             :                    const gbtree_ninfo *tinfo,
     268                 :             :                    FmgrInfo *flinfo)
     269                 :             : {
     270                 :             :     bool        retval;
     271                 :             : 
     272                 :             :     /*
     273                 :             :      * On leaf pages we directly apply the check "key->lower OP query"; we
     274                 :             :      * need not consider key->upper since it will be equal to key->lower.
     275                 :             :      *
     276                 :             :      * On internal pages we mostly need to check "is lower bound below query?"
     277                 :             :      * and/or "is upper bound above query?", where we must allow equality in
     278                 :             :      * both cases.
     279                 :             :      */
     280                 :             : #define lower_is_below_query() \
     281                 :             :     tinfo->f_le(key->lower, query, flinfo)
     282                 :             : #define upper_is_above_query() \
     283                 :             :     tinfo->f_ge(key->upper, query, flinfo)
     284                 :             : 
     285   [ +  +  +  +  :       46631 :     switch (strategy)
                +  +  - ]
     286                 :             :     {
     287                 :        8495 :         case BTLessEqualStrategyNumber:
     288         [ +  + ]:        8495 :             if (is_leaf)
     289                 :        8435 :                 retval = tinfo->f_le(key->lower, query, flinfo);
     290                 :             :             else
     291                 :          60 :                 retval = lower_is_below_query();
     292                 :        8495 :             break;
     293                 :        8803 :         case BTLessStrategyNumber:
     294         [ +  + ]:        8803 :             if (is_leaf)
     295                 :        8735 :                 retval = tinfo->f_lt(key->lower, query, flinfo);
     296                 :             :             else
     297                 :          68 :                 retval = lower_is_below_query();
     298                 :        8803 :             break;
     299                 :        7707 :         case BTEqualStrategyNumber:
     300         [ +  + ]:        7707 :             if (is_leaf)
     301                 :        7625 :                 retval = tinfo->f_eq(key->lower, query, flinfo);
     302                 :             :             else
     303   [ +  +  +  + ]:          82 :                 retval = lower_is_below_query() && upper_is_above_query();
     304                 :        7707 :             break;
     305                 :       10710 :         case BTGreaterStrategyNumber:
     306         [ +  + ]:       10710 :             if (is_leaf)
     307                 :       10650 :                 retval = tinfo->f_gt(key->lower, query, flinfo);
     308                 :             :             else
     309                 :          60 :                 retval = upper_is_above_query();
     310                 :       10710 :             break;
     311                 :       10710 :         case BTGreaterEqualStrategyNumber:
     312         [ +  + ]:       10710 :             if (is_leaf)
     313                 :       10650 :                 retval = tinfo->f_ge(key->lower, query, flinfo);
     314                 :             :             else
     315                 :          60 :                 retval = upper_is_above_query();
     316                 :       10710 :             break;
     317                 :         206 :         case BtreeGistNotEqualStrategyNumber:
     318         [ +  + ]:         206 :             if (is_leaf)
     319                 :         186 :                 retval = !(tinfo->f_eq(key->lower, query, flinfo));
     320                 :             :             else
     321                 :             :             {
     322                 :             :                 /*
     323                 :             :                  * If the upper/lower bounds are equal, then all entries below
     324                 :             :                  * this node must have exactly that value.  So we can avoid
     325                 :             :                  * descending if the query equals both bounds.  In all other
     326                 :             :                  * cases, we must descend.
     327                 :             :                  */
     328   [ +  +  +  + ]:          39 :                 retval = !(tinfo->f_eq(key->lower, query, flinfo) &&
     329                 :          19 :                            tinfo->f_eq(key->upper, query, flinfo));
     330                 :             :             }
     331                 :         206 :             break;
     332                 :           0 :         default:
     333                 :           0 :             retval = false;
     334                 :             :     }
     335                 :             : 
     336                 :             : #undef lower_is_below_query
     337                 :             : #undef upper_is_above_query
     338                 :             : 
     339                 :       46631 :     return retval;
     340                 :             : }
     341                 :             : 
     342                 :             : 
     343                 :             : /*
     344                 :             :  * The GiST distance method (for KNN-Gist)
     345                 :             :  */
     346                 :             : 
     347                 :             : float8
     348                 :        3071 : gbt_num_distance(const GBT_NUMKEY_R *key,
     349                 :             :                  const void *query,
     350                 :             :                  bool is_leaf,
     351                 :             :                  const gbtree_ninfo *tinfo,
     352                 :             :                  FmgrInfo *flinfo)
     353                 :             : {
     354                 :             :     float8      retval;
     355                 :             : 
     356         [ -  + ]:        3071 :     if (tinfo->f_dist == NULL)
     357         [ #  # ]:           0 :         elog(ERROR, "KNN search is not supported for btree_gist type %d",
     358                 :             :              (int) tinfo->t);
     359         [ +  + ]:        3071 :     if (tinfo->f_le(query, key->lower, flinfo))
     360                 :        1566 :         retval = tinfo->f_dist(query, key->lower, flinfo);
     361         [ +  + ]:        1505 :     else if (tinfo->f_ge(query, key->upper, flinfo))
     362                 :        1493 :         retval = tinfo->f_dist(query, key->upper, flinfo);
     363                 :             :     else
     364                 :          12 :         retval = 0.0;
     365                 :             : 
     366                 :        3071 :     return retval;
     367                 :             : }
     368                 :             : 
     369                 :             : 
     370                 :             : GIST_SPLITVEC *
     371                 :          60 : gbt_num_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v,
     372                 :             :                   const gbtree_ninfo *tinfo, FmgrInfo *flinfo)
     373                 :             : {
     374                 :             :     OffsetNumber i,
     375                 :          60 :                 maxoff = entryvec->n - 1;
     376                 :             :     Nsrt       *arr;
     377                 :             :     int         nbytes;
     378                 :             : 
     379                 :          60 :     arr = (Nsrt *) palloc((maxoff + 1) * sizeof(Nsrt));
     380                 :          60 :     nbytes = (maxoff + 2) * sizeof(OffsetNumber);
     381                 :          60 :     v->spl_left = (OffsetNumber *) palloc(nbytes);
     382                 :          60 :     v->spl_right = (OffsetNumber *) palloc(nbytes);
     383                 :          60 :     v->spl_ldatum = PointerGetDatum(0);
     384                 :          60 :     v->spl_rdatum = PointerGetDatum(0);
     385                 :          60 :     v->spl_nleft = 0;
     386                 :          60 :     v->spl_nright = 0;
     387                 :             : 
     388                 :             :     /* Sort entries */
     389                 :             : 
     390         [ +  + ]:       22103 :     for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
     391                 :             :     {
     392                 :       22043 :         arr[i].t = (GBT_NUMKEY *) DatumGetPointer((entryvec->vector[i].key));
     393                 :       22043 :         arr[i].i = i;
     394                 :             :     }
     395                 :          60 :     qsort_arg(&arr[FirstOffsetNumber], maxoff - FirstOffsetNumber + 1, sizeof(Nsrt), (qsort_arg_comparator) tinfo->f_cmp, flinfo);
     396                 :             : 
     397                 :             :     /* We do simply create two parts */
     398                 :             : 
     399         [ +  + ]:       22103 :     for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
     400                 :             :     {
     401         [ +  + ]:       22043 :         if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
     402                 :             :         {
     403                 :       11017 :             gbt_num_bin_union(&v->spl_ldatum, arr[i].t, tinfo, flinfo);
     404                 :       11017 :             v->spl_left[v->spl_nleft] = arr[i].i;
     405                 :       11017 :             v->spl_nleft++;
     406                 :             :         }
     407                 :             :         else
     408                 :             :         {
     409                 :       11026 :             gbt_num_bin_union(&v->spl_rdatum, arr[i].t, tinfo, flinfo);
     410                 :       11026 :             v->spl_right[v->spl_nright] = arr[i].i;
     411                 :       11026 :             v->spl_nright++;
     412                 :             :         }
     413                 :             :     }
     414                 :             : 
     415                 :          60 :     return v;
     416                 :             : }
        

Generated by: LCOV version 2.0-1