YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/postgres/src/backend/utils/adt/nabstime.c
Line
Count
Source (jump to first uncovered line)
1
/*-------------------------------------------------------------------------
2
 *
3
 * nabstime.c
4
 *    Utilities for the built-in type "AbsoluteTime".
5
 *    Functions for the built-in type "RelativeTime".
6
 *    Functions for the built-in type "TimeInterval".
7
 *
8
 * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
9
 * Portions Copyright (c) 1994, Regents of the University of California
10
 *
11
 *
12
 * IDENTIFICATION
13
 *    src/backend/utils/adt/nabstime.c
14
 *
15
 *-------------------------------------------------------------------------
16
 */
17
#include "postgres.h"
18
19
#include <ctype.h>
20
#include <float.h>
21
#include <limits.h>
22
#include <math.h>
23
#include <time.h>
24
#include <sys/time.h>
25
26
#include "libpq/pqformat.h"
27
#include "miscadmin.h"
28
#include "utils/builtins.h"
29
#include "utils/datetime.h"
30
#include "utils/nabstime.h"
31
32
6
#define MIN_DAYNUM (-24856)    /* December 13, 1901 */
33
4
#define MAX_DAYNUM 24854    /* January 18, 2038 */
34
35
/*
36
 * Unix epoch is Jan  1 00:00:00 1970.
37
 * Postgres knows about times sixty-eight years on either side of that
38
 * for these 4-byte types.
39
 *
40
 * "tinterval" is two 4-byte fields.
41
 * Definitions for parsing tinterval.
42
 */
43
44
5
#define IsSpace(C)        ((C) == ' ')
45
46
1
#define T_INTERVAL_INVAL   0  /* data represents no valid tinterval */
47
1
#define T_INTERVAL_VALID   1  /* data represents a valid tinterval */
48
/*
49
 * ['Mon May 10 23:59:12 1943 PST' 'Sun Jan 14 03:14:21 1973 PST']
50
 * 0    1     2     3     4     5     6
51
 * 1234567890123456789012345678901234567890123456789012345678901234
52
 *
53
 * we allocate some extra -- timezones are usually 3 characters but
54
 * this is not in the POSIX standard...
55
 */
56
1
#define T_INTERVAL_LEN          80
57
2
#define INVALID_INTERVAL_STR      "Undefined Range"
58
#define INVALID_INTERVAL_STR_LEN    (sizeof(INVALID_INTERVAL_STR)-1)
59
60
#define ABSTIMEMIN(t1, t2) \
61
1
  (DatumGetBool(DirectFunctionCall2(abstimele, \
62
1
          AbsoluteTimeGetDatum(t1), \
63
1
          AbsoluteTimeGetDatum(t2))) ? (t1) : 
(t2)0
)
64
#define ABSTIMEMAX(t1, t2) \
65
1
  (DatumGetBool(DirectFunctionCall2(abstimelt, \
66
1
          AbsoluteTimeGetDatum(t1), \
67
1
          AbsoluteTimeGetDatum(t2))) ? (t2) : 
(t1)0
)
68
69
70
/*
71
 * Function prototypes -- internal to this file only
72
 */
73
74
static AbsoluteTime tm2abstime(struct pg_tm *tm, int tz);
75
static void reltime2tm(RelativeTime time, struct pg_tm *tm);
76
static void parsetinterval(char *i_string,
77
         AbsoluteTime *i_start,
78
         AbsoluteTime *i_end);
79
80
81
/*
82
 * GetCurrentAbsoluteTime()
83
 *
84
 * Get the current system time (relative to Unix epoch).
85
 *
86
 * NB: this will overflow in 2038; it should be gone long before that.
87
 */
88
AbsoluteTime
89
GetCurrentAbsoluteTime(void)
90
0
{
91
0
  time_t    now;
92
93
0
  now = time(NULL);
94
0
  return (AbsoluteTime) now;
95
0
}
96
97
98
void
99
abstime2tm(AbsoluteTime _time, int *tzp, struct pg_tm *tm, char **tzn)
100
2
{
101
2
  pg_time_t time = (pg_time_t) _time;
102
2
  struct pg_tm *tx;
103
104
2
  if (tzp != NULL)
105
2
    tx = pg_localtime(&time, session_timezone);
106
0
  else
107
0
    tx = pg_gmtime(&time);
108
109
2
  if (tx == NULL)
110
0
    elog(ERROR, "could not convert abstime to timestamp: %m");
111
112
2
  tm->tm_year = tx->tm_year + 1900;
113
2
  tm->tm_mon = tx->tm_mon + 1;
114
2
  tm->tm_mday = tx->tm_mday;
115
2
  tm->tm_hour = tx->tm_hour;
116
2
  tm->tm_min = tx->tm_min;
117
2
  tm->tm_sec = tx->tm_sec;
118
2
  tm->tm_isdst = tx->tm_isdst;
119
120
2
  tm->tm_gmtoff = tx->tm_gmtoff;
121
2
  tm->tm_zone = tx->tm_zone;
122
123
2
  if (tzp != NULL)
124
2
  {
125
2
    *tzp = -tm->tm_gmtoff;  /* tm_gmtoff is Sun/DEC-ism */
126
127
    /*
128
     * XXX FreeBSD man pages indicate that this should work - tgl 97/04/23
129
     */
130
2
    if (tzn != NULL)
131
2
    {
132
      /*
133
       * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it
134
       * contains an error message, which doesn't fit in the buffer
135
       */
136
2
      StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1);
137
2
      if (strlen(tm->tm_zone) > MAXTZLEN)
138
2
        ereport(WARNING,
139
2
            (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
140
2
             errmsg("invalid time zone name: \"%s\"",
141
2
                tm->tm_zone)));
142
2
    }
143
2
  }
144
0
  else
145
0
    tm->tm_isdst = -1;
146
2
}
147
148
149
/* tm2abstime()
150
 * Convert a tm structure to abstime.
151
 * Note that tm has full year (not 1900-based) and 1-based month.
152
 */
153
static AbsoluteTime
154
tm2abstime(struct pg_tm *tm, int tz)
155
2
{
156
2
  int     day;
157
2
  AbsoluteTime sec;
158
159
  /* validate, before going out of range on some members */
160
2
  if (tm->tm_year < 1901 || tm->tm_year > 2038 ||
161
2
    tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR ||
162
2
    tm->tm_mday < 1 || tm->tm_mday > 31 ||
163
2
    tm->tm_hour < 0 ||
164
2
    tm->tm_hour > HOURS_PER_DAY || /* test for > 24:00:00 */
165
2
    (tm->tm_hour == HOURS_PER_DAY && 
(0
tm->tm_min > 00
||
tm->tm_sec > 00
)) ||
166
2
    tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
167
2
    tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE)
168
0
    return INVALID_ABSTIME;
169
170
2
  day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;
171
172
  /* check for time out of range */
173
2
  if (day < MIN_DAYNUM || day > MAX_DAYNUM)
174
0
    return INVALID_ABSTIME;
175
176
  /* convert to seconds */
177
2
  sec = tm->tm_sec + tz + (tm->tm_min + (day * HOURS_PER_DAY + tm->tm_hour) * MINS_PER_HOUR) * SECS_PER_MINUTE;
178
179
  /*
180
   * check for overflow.  We need a little slop here because the H/M/S plus
181
   * TZ offset could add up to more than 1 day.
182
   */
183
2
  if ((day >= MAX_DAYNUM - 10 && 
sec < 00
) ||
184
2
    (day <= MIN_DAYNUM + 10 && 
sec > 00
))
185
0
    return INVALID_ABSTIME;
186
187
  /* check for reserved values (e.g. "current" on edge of usual range */
188
2
  if (!AbsoluteTimeIsReal(sec))
189
0
    return INVALID_ABSTIME;
190
191
2
  return sec;
192
2
}
193
194
195
/* abstimein()
196
 * Decode date/time string and return abstime.
197
 */
198
Datum
199
abstimein(PG_FUNCTION_ARGS)
200
2
{
201
2
  char     *str = PG_GETARG_CSTRING(0);
202
2
  AbsoluteTime result;
203
2
  fsec_t    fsec;
204
2
  int     tz = 0;
205
2
  struct pg_tm date,
206
2
         *tm = &date;
207
2
  int     dterr;
208
2
  char     *field[MAXDATEFIELDS];
209
2
  char    workbuf[MAXDATELEN + 1];
210
2
  int     dtype;
211
2
  int     nf,
212
2
        ftype[MAXDATEFIELDS];
213
214
2
  dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
215
2
              field, ftype, MAXDATEFIELDS, &nf);
216
2
  if (dterr == 0)
217
2
    dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
218
2
  if (dterr != 0)
219
0
    DateTimeParseError(dterr, str, "abstime");
220
221
2
  switch (dtype)
222
2
  {
223
2
    case DTK_DATE:
224
2
      result = tm2abstime(tm, tz);
225
2
      break;
226
227
0
    case DTK_EPOCH:
228
229
      /*
230
       * Don't bother retaining this as a reserved value, but instead
231
       * just set to the actual epoch time (1970-01-01)
232
       */
233
0
      result = 0;
234
0
      break;
235
236
0
    case DTK_LATE:
237
0
      result = NOEND_ABSTIME;
238
0
      break;
239
240
0
    case DTK_EARLY:
241
0
      result = NOSTART_ABSTIME;
242
0
      break;
243
244
0
    case DTK_INVALID:
245
0
      result = INVALID_ABSTIME;
246
0
      break;
247
248
0
    default:
249
0
      elog(ERROR, "unexpected dtype %d while parsing abstime \"%s\"",
250
0
         dtype, str);
251
0
      result = INVALID_ABSTIME;
252
0
      break;
253
2
  };
254
255
2
  PG_RETURN_ABSOLUTETIME(result);
256
2
}
257
258
259
/* abstimeout()
260
 * Given an AbsoluteTime return the English text version of the date
261
 */
262
Datum
263
abstimeout(PG_FUNCTION_ARGS)
264
2
{
265
2
  AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
266
2
  char     *result;
267
2
  int     tz;
268
2
  double    fsec = 0;
269
2
  struct pg_tm tt,
270
2
         *tm = &tt;
271
2
  char    buf[MAXDATELEN + 1];
272
2
  char    zone[MAXDATELEN + 1],
273
2
         *tzn = zone;
274
275
2
  switch (time)
276
2
  {
277
      /*
278
       * Note that timestamp no longer supports 'invalid'. Retain
279
       * 'invalid' for abstime for now, but dump it someday.
280
       */
281
0
    case INVALID_ABSTIME:
282
0
      strcpy(buf, INVALID);
283
0
      break;
284
0
    case NOEND_ABSTIME:
285
0
      strcpy(buf, LATE);
286
0
      break;
287
0
    case NOSTART_ABSTIME:
288
0
      strcpy(buf, EARLY);
289
0
      break;
290
2
    default:
291
2
      abstime2tm(time, &tz, tm, &tzn);
292
2
      EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf);
293
2
      break;
294
2
  }
295
296
2
  result = pstrdup(buf);
297
2
  PG_RETURN_CSTRING(result);
298
2
}
299
300
/*
301
 *    abstimerecv     - converts external binary format to abstime
302
 */
303
Datum
304
abstimerecv(PG_FUNCTION_ARGS)
305
0
{
306
0
  StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
307
308
0
  PG_RETURN_ABSOLUTETIME((AbsoluteTime) pq_getmsgint(buf, sizeof(AbsoluteTime)));
309
0
}
310
311
/*
312
 *    abstimesend     - converts abstime to binary format
313
 */
314
Datum
315
abstimesend(PG_FUNCTION_ARGS)
316
0
{
317
0
  AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
318
0
  StringInfoData buf;
319
320
0
  pq_begintypsend(&buf);
321
0
  pq_sendint32(&buf, time);
322
0
  PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
323
0
}
324
325
326
/* abstime_finite()
327
 */
328
Datum
329
abstime_finite(PG_FUNCTION_ARGS)
330
0
{
331
0
  AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
332
333
0
  PG_RETURN_BOOL(abstime != INVALID_ABSTIME &&
334
0
           abstime != NOSTART_ABSTIME &&
335
0
           abstime != NOEND_ABSTIME);
336
0
}
337
338
339
/*
340
 * abstime comparison routines
341
 */
342
static int
343
abstime_cmp_internal(AbsoluteTime a, AbsoluteTime b)
344
2
{
345
  /*
346
   * We consider all INVALIDs to be equal and larger than any non-INVALID.
347
   * This is somewhat arbitrary; the important thing is to have a consistent
348
   * sort order.
349
   */
350
2
  if (a == INVALID_ABSTIME)
351
0
  {
352
0
    if (b == INVALID_ABSTIME)
353
0
      return 0;     /* INVALID = INVALID */
354
0
    else
355
0
      return 1;     /* INVALID > non-INVALID */
356
0
  }
357
358
2
  if (b == INVALID_ABSTIME)
359
0
    return -1;       /* non-INVALID < INVALID */
360
361
2
  if (a > b)
362
0
    return 1;
363
2
  else if (a == b)
364
0
    return 0;
365
2
  else
366
2
    return -1;
367
2
}
368
369
Datum
370
abstimeeq(PG_FUNCTION_ARGS)
371
0
{
372
0
  AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
373
0
  AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
374
375
0
  PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) == 0);
376
0
}
377
378
Datum
379
abstimene(PG_FUNCTION_ARGS)
380
0
{
381
0
  AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
382
0
  AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
383
384
0
  PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) != 0);
385
0
}
386
387
Datum
388
abstimelt(PG_FUNCTION_ARGS)
389
1
{
390
1
  AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
391
1
  AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
392
393
1
  PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) < 0);
394
1
}
395
396
Datum
397
abstimegt(PG_FUNCTION_ARGS)
398
0
{
399
0
  AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
400
0
  AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
401
402
0
  PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) > 0);
403
0
}
404
405
Datum
406
abstimele(PG_FUNCTION_ARGS)
407
1
{
408
1
  AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
409
1
  AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
410
411
1
  PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) <= 0);
412
1
}
413
414
Datum
415
abstimege(PG_FUNCTION_ARGS)
416
0
{
417
0
  AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
418
0
  AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
419
420
0
  PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) >= 0);
421
0
}
422
423
Datum
424
btabstimecmp(PG_FUNCTION_ARGS)
425
0
{
426
0
  AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
427
0
  AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
428
429
0
  PG_RETURN_INT32(abstime_cmp_internal(t1, t2));
430
0
}
431
432
433
/* timestamp_abstime()
434
 * Convert timestamp to abstime.
435
 */
436
Datum
437
timestamp_abstime(PG_FUNCTION_ARGS)
438
0
{
439
0
  Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
440
0
  AbsoluteTime result;
441
0
  fsec_t    fsec;
442
0
  int     tz;
443
0
  struct pg_tm tt,
444
0
         *tm = &tt;
445
446
0
  if (TIMESTAMP_IS_NOBEGIN(timestamp))
447
0
    result = NOSTART_ABSTIME;
448
0
  else if (TIMESTAMP_IS_NOEND(timestamp))
449
0
    result = NOEND_ABSTIME;
450
0
  else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
451
0
  {
452
0
    tz = DetermineTimeZoneOffset(tm, session_timezone);
453
0
    result = tm2abstime(tm, tz);
454
0
  }
455
0
  else
456
0
  {
457
0
    ereport(ERROR,
458
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
459
0
         errmsg("timestamp out of range")));
460
0
    result = INVALID_ABSTIME;
461
0
  }
462
463
0
  PG_RETURN_ABSOLUTETIME(result);
464
0
}
465
466
/* abstime_timestamp()
467
 * Convert abstime to timestamp.
468
 */
469
Datum
470
abstime_timestamp(PG_FUNCTION_ARGS)
471
0
{
472
0
  AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
473
0
  Timestamp result;
474
0
  struct pg_tm tt,
475
0
         *tm = &tt;
476
0
  int     tz;
477
0
  char    zone[MAXDATELEN + 1],
478
0
         *tzn = zone;
479
480
0
  switch (abstime)
481
0
  {
482
0
    case INVALID_ABSTIME:
483
0
      ereport(ERROR,
484
0
          (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
485
0
           errmsg("cannot convert abstime \"invalid\" to timestamp")));
486
0
      TIMESTAMP_NOBEGIN(result);
487
0
      break;
488
489
0
    case NOSTART_ABSTIME:
490
0
      TIMESTAMP_NOBEGIN(result);
491
0
      break;
492
493
0
    case NOEND_ABSTIME:
494
0
      TIMESTAMP_NOEND(result);
495
0
      break;
496
497
0
    default:
498
0
      abstime2tm(abstime, &tz, tm, &tzn);
499
0
      if (tm2timestamp(tm, 0, NULL, &result) != 0)
500
0
        ereport(ERROR,
501
0
            (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
502
0
             errmsg("timestamp out of range")));
503
0
      break;
504
0
  };
505
506
0
  PG_RETURN_TIMESTAMP(result);
507
0
}
508
509
510
/* timestamptz_abstime()
511
 * Convert timestamp with time zone to abstime.
512
 */
513
Datum
514
timestamptz_abstime(PG_FUNCTION_ARGS)
515
0
{
516
0
  TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
517
0
  AbsoluteTime result;
518
0
  fsec_t    fsec;
519
0
  struct pg_tm tt,
520
0
         *tm = &tt;
521
522
0
  if (TIMESTAMP_IS_NOBEGIN(timestamp))
523
0
    result = NOSTART_ABSTIME;
524
0
  else if (TIMESTAMP_IS_NOEND(timestamp))
525
0
    result = NOEND_ABSTIME;
526
0
  else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
527
0
    result = tm2abstime(tm, 0);
528
0
  else
529
0
  {
530
0
    ereport(ERROR,
531
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
532
0
         errmsg("timestamp out of range")));
533
0
    result = INVALID_ABSTIME;
534
0
  }
535
536
0
  PG_RETURN_ABSOLUTETIME(result);
537
0
}
538
539
/* abstime_timestamptz()
540
 * Convert abstime to timestamp with time zone.
541
 */
542
Datum
543
abstime_timestamptz(PG_FUNCTION_ARGS)
544
0
{
545
0
  AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
546
0
  TimestampTz result;
547
0
  struct pg_tm tt,
548
0
         *tm = &tt;
549
0
  int     tz;
550
0
  char    zone[MAXDATELEN + 1],
551
0
         *tzn = zone;
552
553
0
  switch (abstime)
554
0
  {
555
0
    case INVALID_ABSTIME:
556
0
      ereport(ERROR,
557
0
          (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
558
0
           errmsg("cannot convert abstime \"invalid\" to timestamp")));
559
0
      TIMESTAMP_NOBEGIN(result);
560
0
      break;
561
562
0
    case NOSTART_ABSTIME:
563
0
      TIMESTAMP_NOBEGIN(result);
564
0
      break;
565
566
0
    case NOEND_ABSTIME:
567
0
      TIMESTAMP_NOEND(result);
568
0
      break;
569
570
0
    default:
571
0
      abstime2tm(abstime, &tz, tm, &tzn);
572
0
      if (tm2timestamp(tm, 0, &tz, &result) != 0)
573
0
        ereport(ERROR,
574
0
            (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
575
0
             errmsg("timestamp out of range")));
576
0
      break;
577
0
  };
578
579
0
  PG_RETURN_TIMESTAMP(result);
580
0
}
581
582
583
/*****************************************************************************
584
 *   USER I/O ROUTINES                             *
585
 *****************************************************************************/
586
587
/*
588
 *    reltimein   - converts a reltime string in an internal format
589
 */
590
Datum
591
reltimein(PG_FUNCTION_ARGS)
592
0
{
593
0
  char     *str = PG_GETARG_CSTRING(0);
594
0
  RelativeTime result;
595
0
  struct pg_tm tt,
596
0
         *tm = &tt;
597
0
  fsec_t    fsec;
598
0
  int     dtype;
599
0
  int     dterr;
600
0
  char     *field[MAXDATEFIELDS];
601
0
  int     nf,
602
0
        ftype[MAXDATEFIELDS];
603
0
  char    workbuf[MAXDATELEN + 1];
604
605
0
  dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
606
0
              field, ftype, MAXDATEFIELDS, &nf);
607
0
  if (dterr == 0)
608
0
    dterr = DecodeInterval(field, ftype, nf, INTERVAL_FULL_RANGE,
609
0
                 &dtype, tm, &fsec);
610
611
  /* if those functions think it's a bad format, try ISO8601 style */
612
0
  if (dterr == DTERR_BAD_FORMAT)
613
0
    dterr = DecodeISO8601Interval(str,
614
0
                    &dtype, tm, &fsec);
615
616
0
  if (dterr != 0)
617
0
  {
618
0
    if (dterr == DTERR_FIELD_OVERFLOW)
619
0
      dterr = DTERR_INTERVAL_OVERFLOW;
620
0
    DateTimeParseError(dterr, str, "reltime");
621
0
  }
622
623
0
  switch (dtype)
624
0
  {
625
0
    case DTK_DELTA:
626
0
      result = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec;
627
0
      result += tm->tm_year * SECS_PER_YEAR + ((tm->tm_mon * DAYS_PER_MONTH) + tm->tm_mday) * SECS_PER_DAY;
628
0
      break;
629
630
0
    default:
631
0
      elog(ERROR, "unexpected dtype %d while parsing reltime \"%s\"",
632
0
         dtype, str);
633
0
      result = INVALID_RELTIME;
634
0
      break;
635
0
  }
636
637
0
  PG_RETURN_RELATIVETIME(result);
638
0
}
639
640
/*
641
 *    reltimeout    - converts the internal format to a reltime string
642
 */
643
Datum
644
reltimeout(PG_FUNCTION_ARGS)
645
0
{
646
0
  RelativeTime time = PG_GETARG_RELATIVETIME(0);
647
0
  char     *result;
648
0
  struct pg_tm tt,
649
0
         *tm = &tt;
650
0
  char    buf[MAXDATELEN + 1];
651
652
0
  reltime2tm(time, tm);
653
0
  EncodeInterval(tm, 0, IntervalStyle, buf);
654
655
0
  result = pstrdup(buf);
656
0
  PG_RETURN_CSTRING(result);
657
0
}
658
659
/*
660
 *    reltimerecv     - converts external binary format to reltime
661
 */
662
Datum
663
reltimerecv(PG_FUNCTION_ARGS)
664
0
{
665
0
  StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
666
667
0
  PG_RETURN_RELATIVETIME((RelativeTime) pq_getmsgint(buf, sizeof(RelativeTime)));
668
0
}
669
670
/*
671
 *    reltimesend     - converts reltime to binary format
672
 */
673
Datum
674
reltimesend(PG_FUNCTION_ARGS)
675
0
{
676
0
  RelativeTime time = PG_GETARG_RELATIVETIME(0);
677
0
  StringInfoData buf;
678
679
0
  pq_begintypsend(&buf);
680
0
  pq_sendint32(&buf, time);
681
0
  PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
682
0
}
683
684
685
static void
686
reltime2tm(RelativeTime time, struct pg_tm *tm)
687
0
{
688
0
  double    dtime = time;
689
690
0
  FMODULO(dtime, tm->tm_year, 31557600);
691
0
  FMODULO(dtime, tm->tm_mon, 2592000);
692
0
  FMODULO(dtime, tm->tm_mday, SECS_PER_DAY);
693
0
  FMODULO(dtime, tm->tm_hour, SECS_PER_HOUR);
694
0
  FMODULO(dtime, tm->tm_min, SECS_PER_MINUTE);
695
0
  FMODULO(dtime, tm->tm_sec, 1);
696
0
}
697
698
699
/*
700
 *    tintervalin   - converts a tinterval string to internal format
701
 */
702
Datum
703
tintervalin(PG_FUNCTION_ARGS)
704
1
{
705
1
  char     *tintervalstr = PG_GETARG_CSTRING(0);
706
1
  TimeInterval tinterval;
707
1
  AbsoluteTime i_start,
708
1
        i_end,
709
1
        t1,
710
1
        t2;
711
712
1
  parsetinterval(tintervalstr, &t1, &t2);
713
714
1
  tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData));
715
716
1
  if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
717
0
    tinterval->status = T_INTERVAL_INVAL; /* undefined  */
718
1
  else
719
1
    tinterval->status = T_INTERVAL_VALID;
720
721
1
  i_start = ABSTIMEMIN(t1, t2);
722
1
  i_end = ABSTIMEMAX(t1, t2);
723
1
  tinterval->data[0] = i_start;
724
1
  tinterval->data[1] = i_end;
725
726
1
  PG_RETURN_TIMEINTERVAL(tinterval);
727
1
}
728
729
730
/*
731
 *    tintervalout  - converts an internal tinterval format to a string
732
 */
733
Datum
734
tintervalout(PG_FUNCTION_ARGS)
735
1
{
736
1
  TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0);
737
1
  char     *i_str,
738
1
         *p;
739
740
1
  i_str = (char *) palloc(T_INTERVAL_LEN);  /* ["..." "..."] */
741
1
  strcpy(i_str, "[\"");
742
1
  if (tinterval->status == T_INTERVAL_INVAL)
743
0
    strcat(i_str, INVALID_INTERVAL_STR);
744
1
  else
745
1
  {
746
1
    p = DatumGetCString(DirectFunctionCall1(abstimeout,
747
1
                        AbsoluteTimeGetDatum(tinterval->data[0])));
748
1
    strcat(i_str, p);
749
1
    pfree(p);
750
1
    strcat(i_str, "\" \"");
751
1
    p = DatumGetCString(DirectFunctionCall1(abstimeout,
752
1
                        AbsoluteTimeGetDatum(tinterval->data[1])));
753
1
    strcat(i_str, p);
754
1
    pfree(p);
755
1
  }
756
1
  strcat(i_str, "\"]");
757
1
  PG_RETURN_CSTRING(i_str);
758
1
}
759
760
/*
761
 *    tintervalrecv     - converts external binary format to tinterval
762
 */
763
Datum
764
tintervalrecv(PG_FUNCTION_ARGS)
765
0
{
766
0
  StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
767
0
  TimeInterval tinterval;
768
0
  int32   status;
769
770
0
  tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData));
771
772
0
  tinterval->status = pq_getmsgint(buf, sizeof(tinterval->status));
773
0
  tinterval->data[0] = pq_getmsgint(buf, sizeof(tinterval->data[0]));
774
0
  tinterval->data[1] = pq_getmsgint(buf, sizeof(tinterval->data[1]));
775
776
0
  if (tinterval->data[0] == INVALID_ABSTIME ||
777
0
    tinterval->data[1] == INVALID_ABSTIME)
778
0
    status = T_INTERVAL_INVAL; /* undefined  */
779
0
  else
780
0
    status = T_INTERVAL_VALID;
781
782
0
  if (status != tinterval->status)
783
0
    ereport(ERROR,
784
0
        (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
785
0
         errmsg("invalid status in external \"tinterval\" value")));
786
787
0
  PG_RETURN_TIMEINTERVAL(tinterval);
788
0
}
789
790
/*
791
 *    tintervalsend     - converts tinterval to binary format
792
 */
793
Datum
794
tintervalsend(PG_FUNCTION_ARGS)
795
0
{
796
0
  TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0);
797
0
  StringInfoData buf;
798
799
0
  pq_begintypsend(&buf);
800
0
  pq_sendint32(&buf, tinterval->status);
801
0
  pq_sendint32(&buf, tinterval->data[0]);
802
0
  pq_sendint32(&buf, tinterval->data[1]);
803
0
  PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
804
0
}
805
806
807
/*****************************************************************************
808
 *   PUBLIC ROUTINES                             *
809
 *****************************************************************************/
810
811
Datum
812
interval_reltime(PG_FUNCTION_ARGS)
813
0
{
814
0
  Interval   *interval = PG_GETARG_INTERVAL_P(0);
815
0
  RelativeTime time;
816
0
  int     year,
817
0
        month,
818
0
        day;
819
0
  TimeOffset  span;
820
821
0
  year = interval->month / MONTHS_PER_YEAR;
822
0
  month = interval->month % MONTHS_PER_YEAR;
823
0
  day = interval->day;
824
825
0
  span = ((INT64CONST(365250000) * year + INT64CONST(30000000) * month +
826
0
       INT64CONST(1000000) * day) * INT64CONST(86400)) +
827
0
    interval->time;
828
0
  span /= USECS_PER_SEC;
829
830
0
  if (span < INT_MIN || span > INT_MAX)
831
0
    time = INVALID_RELTIME;
832
0
  else
833
0
    time = span;
834
835
0
  PG_RETURN_RELATIVETIME(time);
836
0
}
837
838
839
Datum
840
reltime_interval(PG_FUNCTION_ARGS)
841
0
{
842
0
  RelativeTime reltime = PG_GETARG_RELATIVETIME(0);
843
0
  Interval   *result;
844
0
  int     year,
845
0
        month,
846
0
        day;
847
848
0
  result = (Interval *) palloc(sizeof(Interval));
849
850
0
  switch (reltime)
851
0
  {
852
0
    case INVALID_RELTIME:
853
0
      ereport(ERROR,
854
0
          (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
855
0
           errmsg("cannot convert reltime \"invalid\" to interval")));
856
0
      result->time = 0;
857
0
      result->day = 0;
858
0
      result->month = 0;
859
0
      break;
860
861
0
    default:
862
0
      year = reltime / SECS_PER_YEAR;
863
0
      reltime -= year * SECS_PER_YEAR;
864
0
      month = reltime / (DAYS_PER_MONTH * SECS_PER_DAY);
865
0
      reltime -= month * (DAYS_PER_MONTH * SECS_PER_DAY);
866
0
      day = reltime / SECS_PER_DAY;
867
0
      reltime -= day * SECS_PER_DAY;
868
869
0
      result->time = (reltime * USECS_PER_SEC);
870
0
      result->month = MONTHS_PER_YEAR * year + month;
871
0
      result->day = day;
872
0
      break;
873
0
  }
874
875
0
  PG_RETURN_INTERVAL_P(result);
876
0
}
877
878
879
/*
880
 *    mktinterval   - creates a time interval with endpoints t1 and t2
881
 */
882
Datum
883
mktinterval(PG_FUNCTION_ARGS)
884
0
{
885
0
  AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
886
0
  AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
887
0
  AbsoluteTime tstart = ABSTIMEMIN(t1, t2);
888
0
  AbsoluteTime tend = ABSTIMEMAX(t1, t2);
889
0
  TimeInterval tinterval;
890
891
0
  tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData));
892
893
0
  if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
894
0
    tinterval->status = T_INTERVAL_INVAL;
895
896
0
  else
897
0
  {
898
0
    tinterval->status = T_INTERVAL_VALID;
899
0
    tinterval->data[0] = tstart;
900
0
    tinterval->data[1] = tend;
901
0
  }
902
903
0
  PG_RETURN_TIMEINTERVAL(tinterval);
904
0
}
905
906
/*
907
 *    timepl, timemi and abstimemi use the formula
908
 *        abstime + reltime = abstime
909
 *    so    abstime - reltime = abstime
910
 *    and   abstime - abstime = reltime
911
 */
912
913
/*
914
 *    timepl      - returns the value of (abstime t1 + reltime t2)
915
 */
916
Datum
917
timepl(PG_FUNCTION_ARGS)
918
0
{
919
0
  AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
920
0
  RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
921
922
0
  if (AbsoluteTimeIsReal(t1) &&
923
0
    RelativeTimeIsValid(t2) &&
924
0
    ((t2 > 0 && t1 < NOEND_ABSTIME - t2) ||
925
0
     (t2 <= 0 && t1 > NOSTART_ABSTIME - t2)))  /* prevent overflow */
926
0
    PG_RETURN_ABSOLUTETIME(t1 + t2);
927
928
0
  PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
929
0
}
930
931
932
/*
933
 *    timemi      - returns the value of (abstime t1 - reltime t2)
934
 */
935
Datum
936
timemi(PG_FUNCTION_ARGS)
937
0
{
938
0
  AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
939
0
  RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
940
941
0
  if (AbsoluteTimeIsReal(t1) &&
942
0
    RelativeTimeIsValid(t2) &&
943
0
    ((t2 > 0 && t1 > NOSTART_ABSTIME + t2) ||
944
0
     (t2 <= 0 && t1 < NOEND_ABSTIME + t2))) /* prevent overflow */
945
0
    PG_RETURN_ABSOLUTETIME(t1 - t2);
946
947
0
  PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
948
0
}
949
950
951
/*
952
 *    intinterval   - returns true iff absolute date is in the tinterval
953
 */
954
Datum
955
intinterval(PG_FUNCTION_ARGS)
956
0
{
957
0
  AbsoluteTime t = PG_GETARG_ABSOLUTETIME(0);
958
0
  TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(1);
959
960
0
  if (tinterval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME)
961
0
  {
962
0
    if (DatumGetBool(DirectFunctionCall2(abstimege,
963
0
                       AbsoluteTimeGetDatum(t),
964
0
                       AbsoluteTimeGetDatum(tinterval->data[0]))) &&
965
0
      DatumGetBool(DirectFunctionCall2(abstimele,
966
0
                       AbsoluteTimeGetDatum(t),
967
0
                       AbsoluteTimeGetDatum(tinterval->data[1]))))
968
0
      PG_RETURN_BOOL(true);
969
0
  }
970
0
  PG_RETURN_BOOL(false);
971
0
}
972
973
/*
974
 *    tintervalrel    - returns  relative time corresponding to tinterval
975
 */
976
Datum
977
tintervalrel(PG_FUNCTION_ARGS)
978
0
{
979
0
  TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0);
980
0
  AbsoluteTime t1 = tinterval->data[0];
981
0
  AbsoluteTime t2 = tinterval->data[1];
982
983
0
  if (tinterval->status != T_INTERVAL_VALID)
984
0
    PG_RETURN_RELATIVETIME(INVALID_RELTIME);
985
986
0
  if (AbsoluteTimeIsReal(t1) &&
987
0
    AbsoluteTimeIsReal(t2))
988
0
    PG_RETURN_RELATIVETIME(t2 - t1);
989
990
0
  PG_RETURN_RELATIVETIME(INVALID_RELTIME);
991
0
}
992
993
994
/*
995
 *    timenow     - returns  time "now", internal format
996
 *
997
 *    Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992
998
 */
999
Datum
1000
timenow(PG_FUNCTION_ARGS)
1001
0
{
1002
0
  PG_RETURN_ABSOLUTETIME(GetCurrentAbsoluteTime());
1003
0
}
1004
1005
/*
1006
 * reltime comparison routines
1007
 */
1008
static int
1009
reltime_cmp_internal(RelativeTime a, RelativeTime b)
1010
0
{
1011
  /*
1012
   * We consider all INVALIDs to be equal and larger than any non-INVALID.
1013
   * This is somewhat arbitrary; the important thing is to have a consistent
1014
   * sort order.
1015
   */
1016
0
  if (a == INVALID_RELTIME)
1017
0
  {
1018
0
    if (b == INVALID_RELTIME)
1019
0
      return 0;     /* INVALID = INVALID */
1020
0
    else
1021
0
      return 1;     /* INVALID > non-INVALID */
1022
0
  }
1023
1024
0
  if (b == INVALID_RELTIME)
1025
0
    return -1;       /* non-INVALID < INVALID */
1026
1027
0
  if (a > b)
1028
0
    return 1;
1029
0
  else if (a == b)
1030
0
    return 0;
1031
0
  else
1032
0
    return -1;
1033
0
}
1034
1035
Datum
1036
reltimeeq(PG_FUNCTION_ARGS)
1037
0
{
1038
0
  RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1039
0
  RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1040
1041
0
  PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) == 0);
1042
0
}
1043
1044
Datum
1045
reltimene(PG_FUNCTION_ARGS)
1046
0
{
1047
0
  RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1048
0
  RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1049
1050
0
  PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) != 0);
1051
0
}
1052
1053
Datum
1054
reltimelt(PG_FUNCTION_ARGS)
1055
0
{
1056
0
  RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1057
0
  RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1058
1059
0
  PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) < 0);
1060
0
}
1061
1062
Datum
1063
reltimegt(PG_FUNCTION_ARGS)
1064
0
{
1065
0
  RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1066
0
  RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1067
1068
0
  PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) > 0);
1069
0
}
1070
1071
Datum
1072
reltimele(PG_FUNCTION_ARGS)
1073
0
{
1074
0
  RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1075
0
  RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1076
1077
0
  PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) <= 0);
1078
0
}
1079
1080
Datum
1081
reltimege(PG_FUNCTION_ARGS)
1082
0
{
1083
0
  RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1084
0
  RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1085
1086
0
  PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) >= 0);
1087
0
}
1088
1089
Datum
1090
btreltimecmp(PG_FUNCTION_ARGS)
1091
0
{
1092
0
  RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1093
0
  RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1094
1095
0
  PG_RETURN_INT32(reltime_cmp_internal(t1, t2));
1096
0
}
1097
1098
1099
/*
1100
 *    tintervalsame - returns true iff tinterval i1 is same as tinterval i2
1101
 *    Check begin and end time.
1102
 */
1103
Datum
1104
tintervalsame(PG_FUNCTION_ARGS)
1105
0
{
1106
0
  TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1107
0
  TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1108
1109
0
  if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1110
0
    PG_RETURN_BOOL(false);
1111
1112
0
  if (DatumGetBool(DirectFunctionCall2(abstimeeq,
1113
0
                     AbsoluteTimeGetDatum(i1->data[0]),
1114
0
                     AbsoluteTimeGetDatum(i2->data[0]))) &&
1115
0
    DatumGetBool(DirectFunctionCall2(abstimeeq,
1116
0
                     AbsoluteTimeGetDatum(i1->data[1]),
1117
0
                     AbsoluteTimeGetDatum(i2->data[1]))))
1118
0
    PG_RETURN_BOOL(true);
1119
0
  PG_RETURN_BOOL(false);
1120
0
}
1121
1122
/*
1123
 * tinterval comparison routines
1124
 *
1125
 * Note: comparison is based only on the lengths of the tintervals, not on
1126
 * endpoint values (as long as they're not INVALID).  This is pretty bogus,
1127
 * but since it's only a legacy datatype, we're not going to change it.
1128
 *
1129
 * Some other bogus things that won't be changed for compatibility reasons:
1130
 * 1. The interval length computations overflow at 2^31 seconds, causing
1131
 * intervals longer than that to sort oddly compared to those shorter.
1132
 * 2. infinity and minus infinity (NOEND_ABSTIME and NOSTART_ABSTIME) are
1133
 * just ordinary integers.  Since this code doesn't handle them specially,
1134
 * it's possible for [a b] to be considered longer than [c infinity] for
1135
 * finite abstimes a, b, c.  In combination with the previous point, the
1136
 * interval [-infinity infinity] is treated as being shorter than many finite
1137
 * intervals :-(
1138
 *
1139
 * If tinterval is ever reimplemented atop timestamp, it'd be good to give
1140
 * some consideration to avoiding these problems.
1141
 */
1142
static int
1143
tinterval_cmp_internal(TimeInterval a, TimeInterval b)
1144
0
{
1145
0
  bool    a_invalid;
1146
0
  bool    b_invalid;
1147
0
  AbsoluteTime a_len;
1148
0
  AbsoluteTime b_len;
1149
1150
  /*
1151
   * We consider all INVALIDs to be equal and larger than any non-INVALID.
1152
   * This is somewhat arbitrary; the important thing is to have a consistent
1153
   * sort order.
1154
   */
1155
0
  a_invalid = a->status == T_INTERVAL_INVAL ||
1156
0
    a->data[0] == INVALID_ABSTIME ||
1157
0
    a->data[1] == INVALID_ABSTIME;
1158
0
  b_invalid = b->status == T_INTERVAL_INVAL ||
1159
0
    b->data[0] == INVALID_ABSTIME ||
1160
0
    b->data[1] == INVALID_ABSTIME;
1161
1162
0
  if (a_invalid)
1163
0
  {
1164
0
    if (b_invalid)
1165
0
      return 0;     /* INVALID = INVALID */
1166
0
    else
1167
0
      return 1;     /* INVALID > non-INVALID */
1168
0
  }
1169
1170
0
  if (b_invalid)
1171
0
    return -1;       /* non-INVALID < INVALID */
1172
1173
0
  a_len = a->data[1] - a->data[0];
1174
0
  b_len = b->data[1] - b->data[0];
1175
1176
0
  if (a_len > b_len)
1177
0
    return 1;
1178
0
  else if (a_len == b_len)
1179
0
    return 0;
1180
0
  else
1181
0
    return -1;
1182
0
}
1183
1184
Datum
1185
tintervaleq(PG_FUNCTION_ARGS)
1186
0
{
1187
0
  TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1188
0
  TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1189
1190
0
  PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) == 0);
1191
0
}
1192
1193
Datum
1194
tintervalne(PG_FUNCTION_ARGS)
1195
0
{
1196
0
  TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1197
0
  TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1198
1199
0
  PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) != 0);
1200
0
}
1201
1202
Datum
1203
tintervallt(PG_FUNCTION_ARGS)
1204
0
{
1205
0
  TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1206
0
  TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1207
1208
0
  PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) < 0);
1209
0
}
1210
1211
Datum
1212
tintervalle(PG_FUNCTION_ARGS)
1213
0
{
1214
0
  TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1215
0
  TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1216
1217
0
  PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) <= 0);
1218
0
}
1219
1220
Datum
1221
tintervalgt(PG_FUNCTION_ARGS)
1222
0
{
1223
0
  TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1224
0
  TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1225
1226
0
  PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) > 0);
1227
0
}
1228
1229
Datum
1230
tintervalge(PG_FUNCTION_ARGS)
1231
0
{
1232
0
  TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1233
0
  TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1234
1235
0
  PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) >= 0);
1236
0
}
1237
1238
Datum
1239
bttintervalcmp(PG_FUNCTION_ARGS)
1240
0
{
1241
0
  TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1242
0
  TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1243
1244
0
  PG_RETURN_INT32(tinterval_cmp_internal(i1, i2));
1245
0
}
1246
1247
1248
/*
1249
 *    tintervalleneq  - returns true iff length of tinterval i is equal to
1250
 *                reltime t
1251
 *    tintervallenne  - returns true iff length of tinterval i is not equal
1252
 *                to reltime t
1253
 *    tintervallenlt  - returns true iff length of tinterval i is less than
1254
 *                reltime t
1255
 *    tintervallengt  - returns true iff length of tinterval i is greater
1256
 *                than reltime t
1257
 *    tintervallenle  - returns true iff length of tinterval i is less or
1258
 *                equal than reltime t
1259
 *    tintervallenge  - returns true iff length of tinterval i is greater or
1260
 *                equal than reltime t
1261
 */
1262
Datum
1263
tintervalleneq(PG_FUNCTION_ARGS)
1264
0
{
1265
0
  TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1266
0
  RelativeTime t = PG_GETARG_RELATIVETIME(1);
1267
0
  RelativeTime rt;
1268
1269
0
  if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1270
0
    PG_RETURN_BOOL(false);
1271
0
  rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1272
0
                          TimeIntervalGetDatum(i)));
1273
0
  PG_RETURN_BOOL(rt != INVALID_RELTIME && rt == t);
1274
0
}
1275
1276
Datum
1277
tintervallenne(PG_FUNCTION_ARGS)
1278
0
{
1279
0
  TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1280
0
  RelativeTime t = PG_GETARG_RELATIVETIME(1);
1281
0
  RelativeTime rt;
1282
1283
0
  if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1284
0
    PG_RETURN_BOOL(false);
1285
0
  rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1286
0
                          TimeIntervalGetDatum(i)));
1287
0
  PG_RETURN_BOOL(rt != INVALID_RELTIME && rt != t);
1288
0
}
1289
1290
Datum
1291
tintervallenlt(PG_FUNCTION_ARGS)
1292
0
{
1293
0
  TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1294
0
  RelativeTime t = PG_GETARG_RELATIVETIME(1);
1295
0
  RelativeTime rt;
1296
1297
0
  if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1298
0
    PG_RETURN_BOOL(false);
1299
0
  rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1300
0
                          TimeIntervalGetDatum(i)));
1301
0
  PG_RETURN_BOOL(rt != INVALID_RELTIME && rt < t);
1302
0
}
1303
1304
Datum
1305
tintervallengt(PG_FUNCTION_ARGS)
1306
0
{
1307
0
  TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1308
0
  RelativeTime t = PG_GETARG_RELATIVETIME(1);
1309
0
  RelativeTime rt;
1310
1311
0
  if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1312
0
    PG_RETURN_BOOL(false);
1313
0
  rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1314
0
                          TimeIntervalGetDatum(i)));
1315
0
  PG_RETURN_BOOL(rt != INVALID_RELTIME && rt > t);
1316
0
}
1317
1318
Datum
1319
tintervallenle(PG_FUNCTION_ARGS)
1320
0
{
1321
0
  TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1322
0
  RelativeTime t = PG_GETARG_RELATIVETIME(1);
1323
0
  RelativeTime rt;
1324
1325
0
  if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1326
0
    PG_RETURN_BOOL(false);
1327
0
  rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1328
0
                          TimeIntervalGetDatum(i)));
1329
0
  PG_RETURN_BOOL(rt != INVALID_RELTIME && rt <= t);
1330
0
}
1331
1332
Datum
1333
tintervallenge(PG_FUNCTION_ARGS)
1334
0
{
1335
0
  TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1336
0
  RelativeTime t = PG_GETARG_RELATIVETIME(1);
1337
0
  RelativeTime rt;
1338
1339
0
  if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1340
0
    PG_RETURN_BOOL(false);
1341
0
  rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1342
0
                          TimeIntervalGetDatum(i)));
1343
0
  PG_RETURN_BOOL(rt != INVALID_RELTIME && rt >= t);
1344
0
}
1345
1346
/*
1347
 *    tintervalct   - returns true iff tinterval i1 contains tinterval i2
1348
 */
1349
Datum
1350
tintervalct(PG_FUNCTION_ARGS)
1351
0
{
1352
0
  TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1353
0
  TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1354
1355
0
  if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1356
0
    PG_RETURN_BOOL(false);
1357
0
  if (DatumGetBool(DirectFunctionCall2(abstimele,
1358
0
                     AbsoluteTimeGetDatum(i1->data[0]),
1359
0
                     AbsoluteTimeGetDatum(i2->data[0]))) &&
1360
0
    DatumGetBool(DirectFunctionCall2(abstimege,
1361
0
                     AbsoluteTimeGetDatum(i1->data[1]),
1362
0
                     AbsoluteTimeGetDatum(i2->data[1]))))
1363
0
    PG_RETURN_BOOL(true);
1364
0
  PG_RETURN_BOOL(false);
1365
0
}
1366
1367
/*
1368
 *    tintervalov   - returns true iff tinterval i1 (partially) overlaps i2
1369
 */
1370
Datum
1371
tintervalov(PG_FUNCTION_ARGS)
1372
0
{
1373
0
  TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1374
0
  TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1375
1376
0
  if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1377
0
    PG_RETURN_BOOL(false);
1378
0
  if (DatumGetBool(DirectFunctionCall2(abstimelt,
1379
0
                     AbsoluteTimeGetDatum(i1->data[1]),
1380
0
                     AbsoluteTimeGetDatum(i2->data[0]))) ||
1381
0
    DatumGetBool(DirectFunctionCall2(abstimegt,
1382
0
                     AbsoluteTimeGetDatum(i1->data[0]),
1383
0
                     AbsoluteTimeGetDatum(i2->data[1]))))
1384
0
    PG_RETURN_BOOL(false);
1385
0
  PG_RETURN_BOOL(true);
1386
0
}
1387
1388
/*
1389
 *    tintervalstart  - returns  the start of tinterval i
1390
 */
1391
Datum
1392
tintervalstart(PG_FUNCTION_ARGS)
1393
0
{
1394
0
  TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1395
1396
0
  if (i->status == T_INTERVAL_INVAL)
1397
0
    PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1398
0
  PG_RETURN_ABSOLUTETIME(i->data[0]);
1399
0
}
1400
1401
/*
1402
 *    tintervalend    - returns  the end of tinterval i
1403
 */
1404
Datum
1405
tintervalend(PG_FUNCTION_ARGS)
1406
0
{
1407
0
  TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1408
1409
0
  if (i->status == T_INTERVAL_INVAL)
1410
0
    PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1411
0
  PG_RETURN_ABSOLUTETIME(i->data[1]);
1412
0
}
1413
1414
1415
/*****************************************************************************
1416
 *   PRIVATE ROUTINES                            *
1417
 *****************************************************************************/
1418
1419
/*
1420
 *    parsetinterval -- parse a tinterval string
1421
 *
1422
 *    output parameters:
1423
 *        i_start, i_end: tinterval margins
1424
 *
1425
 *    Time interval:
1426
 *    `[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]'
1427
 *
1428
 *    OR  `Undefined Range' (see also INVALID_INTERVAL_STR)
1429
 *
1430
 *    where <AbsTime> satisfies the syntax of absolute time.
1431
 *
1432
 *    e.g.  [  '  Jan 18 1902'   'Jan 1 00:00:00 1970']
1433
 */
1434
static void
1435
parsetinterval(char *i_string,
1436
         AbsoluteTime *i_start,
1437
         AbsoluteTime *i_end)
1438
1
{
1439
1
  char     *p,
1440
1
         *p1;
1441
1
  char    c;
1442
1443
1
  p = i_string;
1444
  /* skip leading blanks up to '[' */
1445
1
  while ((c = *p) != '\0')
1446
1
  {
1447
1
    if (IsSpace(c))
1448
0
      p++;
1449
1
    else if (c != '[')
1450
0
      goto bogus;     /* syntax error */
1451
1
    else
1452
1
      break;
1453
1
  }
1454
1
  if (c == '\0')
1455
0
    goto bogus;       /* syntax error */
1456
1
  p++;
1457
  /* skip leading blanks up to '"' */
1458
1
  while ((c = *p) != '\0')
1459
1
  {
1460
1
    if (IsSpace(c))
1461
0
      p++;
1462
1
    else if (c != '"')
1463
0
      goto bogus;     /* syntax error */
1464
1
    else
1465
1
      break;
1466
1
  }
1467
1
  if (c == '\0')
1468
0
    goto bogus;       /* syntax error */
1469
1
  p++;
1470
1
  if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0)
1471
0
    goto bogus;       /* undefined range, handled like a syntax err. */
1472
  /* search for the end of the first date and change it to a \0 */
1473
1
  p1 = p;
1474
20
  while ((c = *p1) != '\0')
1475
20
  {
1476
20
    if (c == '"')
1477
1
      break;
1478
19
    p1++;
1479
19
  }
1480
1
  if (c == '\0')
1481
0
    goto bogus;       /* syntax error */
1482
1
  *p1 = '\0';
1483
  /* get the first date */
1484
1
  *i_start = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
1485
1
                            CStringGetDatum(p)));
1486
  /* undo change to \0 */
1487
1
  *p1 = c;
1488
1
  p = ++p1;
1489
  /* skip blanks up to '"', beginning of second date */
1490
2
  while ((c = *p) != '\0')
1491
2
  {
1492
2
    if (IsSpace(c))
1493
1
      p++;
1494
1
    else if (c != '"')
1495
0
      goto bogus;     /* syntax error */
1496
1
    else
1497
1
      break;
1498
2
  }
1499
1
  if (c == '\0')
1500
0
    goto bogus;       /* syntax error */
1501
1
  p++;
1502
  /* search for the end of the second date and change it to a \0 */
1503
1
  p1 = p;
1504
20
  while ((c = *p1) != '\0')
1505
20
  {
1506
20
    if (c == '"')
1507
1
      break;
1508
19
    p1++;
1509
19
  }
1510
1
  if (c == '\0')
1511
0
    goto bogus;       /* syntax error */
1512
1
  *p1 = '\0';
1513
  /* get the second date */
1514
1
  *i_end = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
1515
1
                            CStringGetDatum(p)));
1516
  /* undo change to \0 */
1517
1
  *p1 = c;
1518
1
  p = ++p1;
1519
  /* skip blanks up to ']' */
1520
1
  while ((c = *p) != '\0')
1521
1
  {
1522
1
    if (IsSpace(c))
1523
0
      p++;
1524
1
    else if (c != ']')
1525
0
      goto bogus;     /* syntax error */
1526
1
    else
1527
1
      break;
1528
1
  }
1529
1
  if (c == '\0')
1530
0
    goto bogus;       /* syntax error */
1531
1
  p++;
1532
1
  c = *p;
1533
1
  if (c != '\0')
1534
0
    goto bogus;       /* syntax error */
1535
1536
  /* it seems to be a valid tinterval */
1537
1
  return;
1538
1539
1
bogus:
1540
0
  ereport(ERROR,
1541
0
      (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
1542
0
       errmsg("invalid input syntax for type %s: \"%s\"",
1543
0
          "tinterval", i_string)));
1544
0
  *i_start = *i_end = INVALID_ABSTIME; /* keep compiler quiet */
1545
0
}
1546
1547
1548
/*****************************************************************************
1549
 *
1550
 *****************************************************************************/
1551
1552
/*
1553
 * timeofday -
1554
 *     returns the current time as a text. similar to timenow() but returns
1555
 *     seconds with more precision (up to microsecs). (I need this to compare
1556
 *     the Wisconsin benchmark with Illustra whose TimeNow() shows current
1557
 *     time with precision up to microsecs.)        - ay 3/95
1558
 */
1559
Datum
1560
timeofday(PG_FUNCTION_ARGS)
1561
0
{
1562
0
  struct timeval tp;
1563
0
  char    templ[128];
1564
0
  char    buf[128];
1565
0
  pg_time_t tt;
1566
1567
0
  gettimeofday(&tp, NULL);
1568
0
  tt = (pg_time_t) tp.tv_sec;
1569
0
  pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
1570
0
        pg_localtime(&tt, session_timezone));
1571
0
  snprintf(buf, sizeof(buf), templ, tp.tv_usec);
1572
1573
0
  PG_RETURN_TEXT_P(cstring_to_text(buf));
1574
0
}