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

Generated by: LCOV version 1.16