LCOV - code coverage report
Current view: top level - contrib/btree_gist - btree_ts.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 100.0 % 161 161
Test Date: 2026-03-03 11:15:01 Functions: 100.0 % 37 37
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  * contrib/btree_gist/btree_ts.c
       3              :  */
       4              : #include "postgres.h"
       5              : 
       6              : #include <limits.h>
       7              : 
       8              : #include "btree_gist.h"
       9              : #include "btree_utils_num.h"
      10              : #include "utils/fmgrprotos.h"
      11              : #include "utils/timestamp.h"
      12              : #include "utils/float.h"
      13              : #include "utils/rel.h"
      14              : #include "utils/sortsupport.h"
      15              : 
      16              : typedef struct
      17              : {
      18              :     Timestamp   lower;
      19              :     Timestamp   upper;
      20              : } tsKEY;
      21              : 
      22              : /* GiST support functions */
      23            5 : PG_FUNCTION_INFO_V1(gbt_ts_compress);
      24            4 : PG_FUNCTION_INFO_V1(gbt_tstz_compress);
      25            6 : PG_FUNCTION_INFO_V1(gbt_ts_fetch);
      26            6 : PG_FUNCTION_INFO_V1(gbt_ts_union);
      27            6 : PG_FUNCTION_INFO_V1(gbt_ts_picksplit);
      28            5 : PG_FUNCTION_INFO_V1(gbt_ts_consistent);
      29            5 : PG_FUNCTION_INFO_V1(gbt_ts_distance);
      30            4 : PG_FUNCTION_INFO_V1(gbt_tstz_consistent);
      31            4 : PG_FUNCTION_INFO_V1(gbt_tstz_distance);
      32            6 : PG_FUNCTION_INFO_V1(gbt_ts_penalty);
      33            6 : PG_FUNCTION_INFO_V1(gbt_ts_same);
      34            6 : PG_FUNCTION_INFO_V1(gbt_ts_sortsupport);
      35              : 
      36              : 
      37              : /* define for comparison */
      38              : 
      39              : static bool
      40        12969 : gbt_tsgt(const void *a, const void *b, FmgrInfo *flinfo)
      41              : {
      42        12969 :     const Timestamp *aa = (const Timestamp *) a;
      43        12969 :     const Timestamp *bb = (const Timestamp *) b;
      44              : 
      45        12969 :     return DatumGetBool(DirectFunctionCall2(timestamp_gt,
      46              :                                             TimestampGetDatum(*aa),
      47              :                                             TimestampGetDatum(*bb)));
      48              : }
      49              : 
      50              : static bool
      51         2345 : gbt_tsge(const void *a, const void *b, FmgrInfo *flinfo)
      52              : {
      53         2345 :     const Timestamp *aa = (const Timestamp *) a;
      54         2345 :     const Timestamp *bb = (const Timestamp *) b;
      55              : 
      56         2345 :     return DatumGetBool(DirectFunctionCall2(timestamp_ge,
      57              :                                             TimestampGetDatum(*aa),
      58              :                                             TimestampGetDatum(*bb)));
      59              : }
      60              : 
      61              : static bool
      62         5185 : gbt_tseq(const void *a, const void *b, FmgrInfo *flinfo)
      63              : {
      64         5185 :     const Timestamp *aa = (const Timestamp *) a;
      65         5185 :     const Timestamp *bb = (const Timestamp *) b;
      66              : 
      67         5185 :     return DatumGetBool(DirectFunctionCall2(timestamp_eq,
      68              :                                             TimestampGetDatum(*aa),
      69              :                                             TimestampGetDatum(*bb)));
      70              : }
      71              : 
      72              : static bool
      73         1987 : gbt_tsle(const void *a, const void *b, FmgrInfo *flinfo)
      74              : {
      75         1987 :     const Timestamp *aa = (const Timestamp *) a;
      76         1987 :     const Timestamp *bb = (const Timestamp *) b;
      77              : 
      78         1987 :     return DatumGetBool(DirectFunctionCall2(timestamp_le,
      79              :                                             TimestampGetDatum(*aa),
      80              :                                             TimestampGetDatum(*bb)));
      81              : }
      82              : 
      83              : static bool
      84        12431 : gbt_tslt(const void *a, const void *b, FmgrInfo *flinfo)
      85              : {
      86        12431 :     const Timestamp *aa = (const Timestamp *) a;
      87        12431 :     const Timestamp *bb = (const Timestamp *) b;
      88              : 
      89        12431 :     return DatumGetBool(DirectFunctionCall2(timestamp_lt,
      90              :                                             TimestampGetDatum(*aa),
      91              :                                             TimestampGetDatum(*bb)));
      92              : }
      93              : 
      94              : static int
      95         4825 : gbt_tskey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
      96              : {
      97         4825 :     tsKEY      *ia = (tsKEY *) (((const Nsrt *) a)->t);
      98         4825 :     tsKEY      *ib = (tsKEY *) (((const Nsrt *) b)->t);
      99              :     int         res;
     100              : 
     101         4825 :     res = DatumGetInt32(DirectFunctionCall2(timestamp_cmp, TimestampGetDatum(ia->lower), TimestampGetDatum(ib->lower)));
     102         4825 :     if (res == 0)
     103         3738 :         return DatumGetInt32(DirectFunctionCall2(timestamp_cmp, TimestampGetDatum(ia->upper), TimestampGetDatum(ib->upper)));
     104              : 
     105         1087 :     return res;
     106              : }
     107              : 
     108              : static float8
     109          561 : gbt_ts_dist(const void *a, const void *b, FmgrInfo *flinfo)
     110              : {
     111          561 :     const Timestamp *aa = (const Timestamp *) a;
     112          561 :     const Timestamp *bb = (const Timestamp *) b;
     113              :     Interval   *i;
     114              : 
     115          561 :     if (TIMESTAMP_NOT_FINITE(*aa) || TIMESTAMP_NOT_FINITE(*bb))
     116           20 :         return get_float8_infinity();
     117              : 
     118          541 :     i = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
     119              :                                               TimestampGetDatum(*aa),
     120              :                                               TimestampGetDatum(*bb)));
     121          541 :     return fabs(INTERVAL_TO_SEC(i));
     122              : }
     123              : 
     124              : static const gbtree_ninfo tinfo =
     125              : {
     126              :     gbt_t_ts,
     127              :     sizeof(Timestamp),
     128              :     16,                         /* sizeof(gbtreekey16) */
     129              :     gbt_tsgt,
     130              :     gbt_tsge,
     131              :     gbt_tseq,
     132              :     gbt_tsle,
     133              :     gbt_tslt,
     134              :     gbt_tskey_cmp,
     135              :     gbt_ts_dist
     136              : };
     137              : 
     138              : 
     139            4 : PG_FUNCTION_INFO_V1(ts_dist);
     140              : Datum
     141          571 : ts_dist(PG_FUNCTION_ARGS)
     142              : {
     143          571 :     Timestamp   a = PG_GETARG_TIMESTAMP(0);
     144          571 :     Timestamp   b = PG_GETARG_TIMESTAMP(1);
     145              :     Interval   *r;
     146              : 
     147          571 :     if (TIMESTAMP_NOT_FINITE(a) || TIMESTAMP_NOT_FINITE(b))
     148              :     {
     149           24 :         Interval   *p = palloc_object(Interval);
     150              : 
     151           24 :         p->day = INT_MAX;
     152           24 :         p->month = INT_MAX;
     153           24 :         p->time = PG_INT64_MAX;
     154           24 :         PG_RETURN_INTERVAL_P(p);
     155              :     }
     156              :     else
     157          547 :         r = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
     158              :                                                   PG_GETARG_DATUM(0),
     159              :                                                   PG_GETARG_DATUM(1)));
     160          547 :     PG_RETURN_INTERVAL_P(abs_interval(r));
     161              : }
     162              : 
     163            4 : PG_FUNCTION_INFO_V1(tstz_dist);
     164              : Datum
     165          552 : tstz_dist(PG_FUNCTION_ARGS)
     166              : {
     167          552 :     TimestampTz a = PG_GETARG_TIMESTAMPTZ(0);
     168          552 :     TimestampTz b = PG_GETARG_TIMESTAMPTZ(1);
     169              :     Interval   *r;
     170              : 
     171          552 :     if (TIMESTAMP_NOT_FINITE(a) || TIMESTAMP_NOT_FINITE(b))
     172              :     {
     173           18 :         Interval   *p = palloc_object(Interval);
     174              : 
     175           18 :         p->day = INT_MAX;
     176           18 :         p->month = INT_MAX;
     177           18 :         p->time = PG_INT64_MAX;
     178           18 :         PG_RETURN_INTERVAL_P(p);
     179              :     }
     180              : 
     181          534 :     r = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
     182              :                                               PG_GETARG_DATUM(0),
     183              :                                               PG_GETARG_DATUM(1)));
     184          534 :     PG_RETURN_INTERVAL_P(abs_interval(r));
     185              : }
     186              : 
     187              : /**************************************************
     188              :  * GiST support functions
     189              :  **************************************************/
     190              : 
     191              : static inline Timestamp
     192         6625 : tstz_to_ts_gmt(TimestampTz ts)
     193              : {
     194              :     /* No timezone correction is needed, since GMT is offset 0 by definition */
     195         6625 :     return (Timestamp) ts;
     196              : }
     197              : 
     198              : 
     199              : Datum
     200         2612 : gbt_ts_compress(PG_FUNCTION_ARGS)
     201              : {
     202         2612 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     203              : 
     204         2612 :     PG_RETURN_POINTER(gbt_num_compress(entry, &tinfo));
     205              : }
     206              : 
     207              : Datum
     208          551 : gbt_tstz_compress(PG_FUNCTION_ARGS)
     209              : {
     210          551 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     211              :     GISTENTRY  *retval;
     212              : 
     213          551 :     if (entry->leafkey)
     214              :     {
     215          549 :         tsKEY      *r = palloc_object(tsKEY);
     216          549 :         TimestampTz ts = DatumGetTimestampTz(entry->key);
     217              :         Timestamp   gmt;
     218              : 
     219          549 :         gmt = tstz_to_ts_gmt(ts);
     220              : 
     221          549 :         retval = palloc_object(GISTENTRY);
     222          549 :         r->lower = r->upper = gmt;
     223          549 :         gistentryinit(*retval, PointerGetDatum(r),
     224              :                       entry->rel, entry->page,
     225              :                       entry->offset, false);
     226              :     }
     227              :     else
     228            2 :         retval = entry;
     229              : 
     230          551 :     PG_RETURN_POINTER(retval);
     231              : }
     232              : 
     233              : Datum
     234          559 : gbt_ts_fetch(PG_FUNCTION_ARGS)
     235              : {
     236          559 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     237              : 
     238          559 :     PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
     239              : }
     240              : 
     241              : Datum
     242         2204 : gbt_ts_consistent(PG_FUNCTION_ARGS)
     243              : {
     244         2204 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     245         2204 :     Timestamp   query = PG_GETARG_TIMESTAMP(1);
     246         2204 :     StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
     247              : #ifdef NOT_USED
     248              :     Oid         subtype = PG_GETARG_OID(3);
     249              : #endif
     250         2204 :     bool       *recheck = (bool *) PG_GETARG_POINTER(4);
     251         2204 :     tsKEY      *kkk = (tsKEY *) DatumGetPointer(entry->key);
     252              :     GBT_NUMKEY_R key;
     253              : 
     254              :     /* All cases served by this function are exact */
     255         2204 :     *recheck = false;
     256              : 
     257         2204 :     key.lower = (GBT_NUMKEY *) &kkk->lower;
     258         2204 :     key.upper = (GBT_NUMKEY *) &kkk->upper;
     259              : 
     260         2204 :     PG_RETURN_BOOL(gbt_num_consistent(&key, &query, &strategy,
     261              :                                       GIST_LEAF(entry), &tinfo, fcinfo->flinfo));
     262              : }
     263              : 
     264              : Datum
     265          286 : gbt_ts_distance(PG_FUNCTION_ARGS)
     266              : {
     267          286 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     268          286 :     Timestamp   query = PG_GETARG_TIMESTAMP(1);
     269              : #ifdef NOT_USED
     270              :     Oid         subtype = PG_GETARG_OID(3);
     271              : #endif
     272          286 :     tsKEY      *kkk = (tsKEY *) DatumGetPointer(entry->key);
     273              :     GBT_NUMKEY_R key;
     274              : 
     275          286 :     key.lower = (GBT_NUMKEY *) &kkk->lower;
     276          286 :     key.upper = (GBT_NUMKEY *) &kkk->upper;
     277              : 
     278          286 :     PG_RETURN_FLOAT8(gbt_num_distance(&key, &query, GIST_LEAF(entry),
     279              :                                       &tinfo, fcinfo->flinfo));
     280              : }
     281              : 
     282              : Datum
     283         5799 : gbt_tstz_consistent(PG_FUNCTION_ARGS)
     284              : {
     285         5799 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     286         5799 :     TimestampTz query = PG_GETARG_TIMESTAMPTZ(1);
     287         5799 :     StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
     288              : #ifdef NOT_USED
     289              :     Oid         subtype = PG_GETARG_OID(3);
     290              : #endif
     291         5799 :     bool       *recheck = (bool *) PG_GETARG_POINTER(4);
     292         5799 :     char       *kkk = (char *) DatumGetPointer(entry->key);
     293              :     GBT_NUMKEY_R key;
     294              :     Timestamp   qqq;
     295              : 
     296              :     /* All cases served by this function are exact */
     297         5799 :     *recheck = false;
     298              : 
     299         5799 :     key.lower = (GBT_NUMKEY *) &kkk[0];
     300         5799 :     key.upper = (GBT_NUMKEY *) &kkk[MAXALIGN(tinfo.size)];
     301         5799 :     qqq = tstz_to_ts_gmt(query);
     302              : 
     303         5799 :     PG_RETURN_BOOL(gbt_num_consistent(&key, &qqq, &strategy,
     304              :                                       GIST_LEAF(entry), &tinfo, fcinfo->flinfo));
     305              : }
     306              : 
     307              : Datum
     308          277 : gbt_tstz_distance(PG_FUNCTION_ARGS)
     309              : {
     310          277 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     311          277 :     TimestampTz query = PG_GETARG_TIMESTAMPTZ(1);
     312              : #ifdef NOT_USED
     313              :     Oid         subtype = PG_GETARG_OID(3);
     314              : #endif
     315          277 :     char       *kkk = (char *) DatumGetPointer(entry->key);
     316              :     GBT_NUMKEY_R key;
     317              :     Timestamp   qqq;
     318              : 
     319          277 :     key.lower = (GBT_NUMKEY *) &kkk[0];
     320          277 :     key.upper = (GBT_NUMKEY *) &kkk[MAXALIGN(tinfo.size)];
     321          277 :     qqq = tstz_to_ts_gmt(query);
     322              : 
     323          277 :     PG_RETURN_FLOAT8(gbt_num_distance(&key, &qqq, GIST_LEAF(entry),
     324              :                                       &tinfo, fcinfo->flinfo));
     325              : }
     326              : 
     327              : 
     328              : Datum
     329         1858 : gbt_ts_union(PG_FUNCTION_ARGS)
     330              : {
     331         1858 :     GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     332         1858 :     void       *out = palloc(sizeof(tsKEY));
     333              : 
     334         1858 :     *(int *) PG_GETARG_POINTER(1) = sizeof(tsKEY);
     335         1858 :     PG_RETURN_POINTER(gbt_num_union(out, entryvec, &tinfo, fcinfo->flinfo));
     336              : }
     337              : 
     338              : 
     339              : #define penalty_check_max_float(val) \
     340              :     do { \
     341              :         if ( val > FLT_MAX ) \
     342              :                 val = FLT_MAX; \
     343              :         if ( val < -FLT_MAX ) \
     344              :                 val = -FLT_MAX; \
     345              :     } while (0)
     346              : 
     347              : 
     348              : Datum
     349         4113 : gbt_ts_penalty(PG_FUNCTION_ARGS)
     350              : {
     351         4113 :     tsKEY      *origentry = (tsKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
     352         4113 :     tsKEY      *newentry = (tsKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
     353         4113 :     float      *result = (float *) PG_GETARG_POINTER(2);
     354              : 
     355              :     double      orgdbl[2],
     356              :                 newdbl[2];
     357              : 
     358              :     /*
     359              :      * We are always using "double" timestamps here. Precision should be good
     360              :      * enough.
     361              :      */
     362         4113 :     orgdbl[0] = ((double) origentry->lower);
     363         4113 :     orgdbl[1] = ((double) origentry->upper);
     364         4113 :     newdbl[0] = ((double) newentry->lower);
     365         4113 :     newdbl[1] = ((double) newentry->upper);
     366              : 
     367         4113 :     penalty_check_max_float(orgdbl[0]);
     368         4113 :     penalty_check_max_float(orgdbl[1]);
     369         4113 :     penalty_check_max_float(newdbl[0]);
     370         4113 :     penalty_check_max_float(newdbl[1]);
     371              : 
     372         4113 :     penalty_num(result, orgdbl[0], orgdbl[1], newdbl[0], newdbl[1]);
     373              : 
     374         4113 :     PG_RETURN_POINTER(result);
     375              : }
     376              : 
     377              : 
     378              : Datum
     379           21 : gbt_ts_picksplit(PG_FUNCTION_ARGS)
     380              : {
     381           21 :     PG_RETURN_POINTER(gbt_num_picksplit((GistEntryVector *) PG_GETARG_POINTER(0),
     382              :                                         (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
     383              :                                         &tinfo, fcinfo->flinfo));
     384              : }
     385              : 
     386              : Datum
     387         1835 : gbt_ts_same(PG_FUNCTION_ARGS)
     388              : {
     389         1835 :     tsKEY      *b1 = (tsKEY *) PG_GETARG_POINTER(0);
     390         1835 :     tsKEY      *b2 = (tsKEY *) PG_GETARG_POINTER(1);
     391         1835 :     bool       *result = (bool *) PG_GETARG_POINTER(2);
     392              : 
     393         1835 :     *result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
     394         1835 :     PG_RETURN_POINTER(result);
     395              : }
     396              : 
     397              : static int
     398        11115 : gbt_ts_ssup_cmp(Datum x, Datum y, SortSupport ssup)
     399              : {
     400        11115 :     tsKEY      *arg1 = (tsKEY *) DatumGetPointer(x);
     401        11115 :     tsKEY      *arg2 = (tsKEY *) DatumGetPointer(y);
     402              : 
     403              :     /* for leaf items we expect lower == upper, so only compare lower */
     404        11115 :     return DatumGetInt32(DirectFunctionCall2(timestamp_cmp,
     405              :                                              TimestampGetDatum(arg1->lower),
     406              :                                              TimestampGetDatum(arg2->lower)));
     407              : }
     408              : 
     409              : Datum
     410            3 : gbt_ts_sortsupport(PG_FUNCTION_ARGS)
     411              : {
     412            3 :     SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
     413              : 
     414            3 :     ssup->comparator = gbt_ts_ssup_cmp;
     415            3 :     ssup->ssup_extra = NULL;
     416              : 
     417            3 :     PG_RETURN_VOID();
     418              : }
        

Generated by: LCOV version 2.0-1