nabstime.c 37.8 KB
Newer Older
1
/*-------------------------------------------------------------------------
2
 *
3
 * nabstime.c
4 5 6
 *	  Utilities for the built-in type "AbsoluteTime".
 *	  Functions for the built-in type "RelativeTime".
 *	  Functions for the built-in type "TimeInterval".
7
 *
P
 
PostgreSQL Daemon 已提交
8
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
9
 * Portions Copyright (c) 1994, Regents of the University of California
10 11
 *
 *
12
 * IDENTIFICATION
13
 *	  $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.131 2005/05/24 02:09:45 momjian Exp $
14 15
 *
 *-------------------------------------------------------------------------
16
 */
17 18
#include "postgres.h"

19
#include <ctype.h>
20 21
#include <float.h>
#include <limits.h>
22
#include <time.h>
23
#include <sys/time.h>
24

25
#include "access/xact.h"
26
#include "libpq/pqformat.h"
B
Bruce Momjian 已提交
27
#include "miscadmin.h"
28
#include "pgtime.h"
B
Bruce Momjian 已提交
29
#include "utils/builtins.h"
30
#include "utils/timestamp.h"
31

32 33
#define MIN_DAYNUM -24856		/* December 13, 1901 */
#define MAX_DAYNUM 24854		/* January 18, 2038 */
34

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
#define INVALID_RELTIME_STR		"Undefined RelTime"
#define INVALID_RELTIME_STR_LEN (sizeof(INVALID_RELTIME_STR)-1)
#define RELTIME_LABEL			'@'
#define RELTIME_PAST			"ago"
#define DIRMAXLEN				(sizeof(RELTIME_PAST)-1)

/*
 * Unix epoch is Jan  1 00:00:00 1970.
 * Postgres knows about times sixty-eight years on either side of that
 * for these 4-byte types.
 *
 * "tinterval" is two 4-byte fields.
 * Definitions for parsing tinterval.
 */

#define IsSpace(C)				((C) == ' ')

#define T_INTERVAL_INVAL   0	/* data represents no valid interval */
#define T_INTERVAL_VALID   1	/* data represents a valid interval */
/*
 * ['Mon May 10 23:59:12 1943 PST' 'Sun Jan 14 03:14:21 1973 PST']
 * 0		1		  2			3		  4			5		  6
 * 1234567890123456789012345678901234567890123456789012345678901234
 *
 * we allocate some extra -- timezones are usually 3 characters but
 * this is not in the POSIX standard...
 */
#define T_INTERVAL_LEN					80
#define INVALID_INTERVAL_STR			"Undefined Range"
#define INVALID_INTERVAL_STR_LEN		(sizeof(INVALID_INTERVAL_STR)-1)

66 67 68 69 70 71 72 73
#define ABSTIMEMIN(t1, t2) \
	(DatumGetBool(DirectFunctionCall2(abstimele, \
				  AbsoluteTimeGetDatum(t1), \
				  AbsoluteTimeGetDatum(t2))) ? (t1) : (t2))
#define ABSTIMEMAX(t1, t2) \
	(DatumGetBool(DirectFunctionCall2(abstimelt, \
				  AbsoluteTimeGetDatum(t1), \
				  AbsoluteTimeGetDatum(t2))) ? (t2) : (t1))
74 75 76 77 78 79


/*
 * Function prototypes -- internal to this file only
 */

80 81
static AbsoluteTime tm2abstime(struct pg_tm * tm, int tz);
static void reltime2tm(RelativeTime time, struct pg_tm * tm);
82 83 84
static int istinterval(char *i_string,
			AbsoluteTime *i_start,
			AbsoluteTime *i_end);
85

86

B
Bruce Momjian 已提交
87
/*
88 89
 * GetCurrentAbsoluteTime()
 *
90
 * Get the current system time (relative to Unix epoch).
91 92
 */
AbsoluteTime
93
GetCurrentAbsoluteTime(void)
94
{
95
	time_t		now;
96

97
	now = time(NULL);
98
	return (AbsoluteTime) now;
99
}
100 101


102 103
/*
 * GetCurrentAbsoluteTimeUsec()
104
 *
105 106
 * Get the current system time (relative to Unix epoch), including fractional
 * seconds expressed as microseconds.
107 108 109 110
 */
AbsoluteTime
GetCurrentAbsoluteTimeUsec(int *usec)
{
111
	time_t		now;
112
	struct timeval tp;
113

114 115 116 117
	gettimeofday(&tp, NULL);
	now = tp.tv_sec;
	*usec = tp.tv_usec;
	return (AbsoluteTime) now;
118
}
119 120


121 122 123 124 125 126 127 128 129 130 131
/*
 * AbsoluteTimeUsecToTimestampTz()
 *
 * Convert system time including microseconds to TimestampTz representation.
 */
TimestampTz
AbsoluteTimeUsecToTimestampTz(AbsoluteTime sec, int usec)
{
	TimestampTz result;

#ifdef HAVE_INT64_TIMESTAMP
132
	result = ((sec - ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY))
133
			  * USECS_PER_SEC) + usec;
134
#else
135
	result = sec - ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY)
136 137 138 139 140 141 142 143 144 145
		+ (usec / 1000000.0);
#endif

	return result;
}


/*
 * GetCurrentDateTime()
 *
146
 * Get the transaction start time ("now()") broken down as a struct pg_tm.
147
 */
148
void
149
GetCurrentDateTime(struct pg_tm * tm)
150
{
151
	int			tz;
152

153
	abstime2tm(GetCurrentTransactionStartTime(), &tz, tm, NULL);
154
}
155

B
Bruce Momjian 已提交
156
/*
157
 * GetCurrentTimeUsec()
158
 *
159
 * Get the transaction start time ("now()") broken down as a struct pg_tm,
160
 * including fractional seconds and timezone offset.
161
 */
162
void
163
GetCurrentTimeUsec(struct pg_tm * tm, fsec_t *fsec, int *tzp)
164 165 166 167 168
{
	int			tz;
	int			usec;

	abstime2tm(GetCurrentTransactionStartTimeUsec(&usec), &tz, tm, NULL);
169
	/* Note: don't pass NULL tzp to abstime2tm; affects behavior */
170 171
	if (tzp != NULL)
		*tzp = tz;
172 173 174
#ifdef HAVE_INT64_TIMESTAMP
	*fsec = usec;
#else
175
	*fsec = usec / 1000000.0;
176
#endif
177
}
178 179


180
void
181
abstime2tm(AbsoluteTime _time, int *tzp, struct pg_tm * tm, char **tzn)
182
{
183
	pg_time_t	time = (pg_time_t) _time;
B
Bruce Momjian 已提交
184
	struct pg_tm *tx;
185

186 187 188 189
	/*
	 * If HasCTZSet is true then we have a brute force time zone
	 * specified. Go ahead and rotate to the local time zone since we will
	 * later bypass any calls which adjust the tm fields.
190 191 192
	 */
	if (HasCTZSet && (tzp != NULL))
		time -= CTimeZone;
193

194
	if (!HasCTZSet && tzp != NULL)
195
		tx = pg_localtime(&time,global_timezone);
196
	else
197
		tx = pg_gmtime(&time);
198

199 200 201 202 203 204 205
	tm->tm_year = tx->tm_year + 1900;
	tm->tm_mon = tx->tm_mon + 1;
	tm->tm_mday = tx->tm_mday;
	tm->tm_hour = tx->tm_hour;
	tm->tm_min = tx->tm_min;
	tm->tm_sec = tx->tm_sec;
	tm->tm_isdst = tx->tm_isdst;
206

207 208 209 210
	tm->tm_gmtoff = tx->tm_gmtoff;
	tm->tm_zone = tx->tm_zone;

	if (tzp != NULL)
B
Hi,  
Bruce Momjian 已提交
211
	{
212 213 214
		/*
		 * We have a brute force time zone per SQL99? Then use it without
		 * change since we have already rotated to the time zone.
215
		 */
216 217 218 219
		if (HasCTZSet)
		{
			*tzp = CTimeZone;
			tm->tm_gmtoff = CTimeZone;
220
			tm->tm_isdst = 0;
221 222 223 224 225 226
			tm->tm_zone = NULL;
			if (tzn != NULL)
				*tzn = NULL;
		}
		else
		{
227
			*tzp = -tm->tm_gmtoff;		/* tm_gmtoff is Sun/DEC-ism */
228

229 230 231 232
			/*
			 * XXX FreeBSD man pages indicate that this should work - tgl
			 * 97/04/23
			 */
233 234 235
			if (tzn != NULL)
			{
				/*
236 237 238
				 * Copy no more than MAXTZLEN bytes of timezone to tzn, in
				 * case it contains an error message, which doesn't fit in
				 * the buffer
239 240 241
				 */
				StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1);
				if (strlen(tm->tm_zone) > MAXTZLEN)
242 243
					ereport(WARNING,
							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
244
							 errmsg("invalid time zone name: \"%s\"",
245
									tm->tm_zone)));
246 247
			}
		}
B
Hi,  
Bruce Momjian 已提交
248
	}
249 250
	else
		tm->tm_isdst = -1;
251
}
252 253


254 255 256 257
/* tm2abstime()
 * Convert a tm structure to abstime.
 * Note that tm has full year (not 1900-based) and 1-based month.
 */
258
static AbsoluteTime
259
tm2abstime(struct pg_tm * tm, int tz)
260
{
261 262
	int			day;
	AbsoluteTime sec;
263

264 265 266 267
	/* validate, before going out of range on some members */
	if (tm->tm_year < 1901 || tm->tm_year > 2038
		|| tm->tm_mon < 1 || tm->tm_mon > 12
		|| tm->tm_mday < 1 || tm->tm_mday > 31
268
		|| tm->tm_hour < 0 || tm->tm_hour > 23
269
		|| tm->tm_min < 0 || tm->tm_min > 59
270
		|| tm->tm_sec < 0 || tm->tm_sec > 60)
271
		return INVALID_ABSTIME;
272

273
	day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;
274

275
	/* check for time out of range */
276
	if (day < MIN_DAYNUM || day > MAX_DAYNUM)
277
		return INVALID_ABSTIME;
278

279 280
	/* convert to seconds */
	sec = tm->tm_sec + tz + (tm->tm_min + (day * 24 + tm->tm_hour) * 60) * 60;
281

282 283 284
	/* check for overflow */
	if ((day == MAX_DAYNUM && sec < 0) ||
		(day == MIN_DAYNUM && sec > 0))
285
		return INVALID_ABSTIME;
286

287 288
	/* check for reserved values (e.g. "current" on edge of usual range */
	if (!AbsoluteTimeIsReal(sec))
289
		return INVALID_ABSTIME;
290

291
	return sec;
292
}
293 294


295
/* abstimein()
296
 * Decode date/time string and return abstime.
297
 */
298
Datum
299
abstimein(PG_FUNCTION_ARGS)
300
{
301
	char	   *str = PG_GETARG_CSTRING(0);
302
	AbsoluteTime result;
303
	fsec_t		fsec;
304
	int			tz = 0;
B
Bruce Momjian 已提交
305
	struct pg_tm date,
306
			   *tm = &date;
307
	int			dterr;
308 309 310 311 312
	char	   *field[MAXDATEFIELDS];
	char		lowstr[MAXDATELEN + 1];
	int			dtype;
	int			nf,
				ftype[MAXDATEFIELDS];
313

314
	if (strlen(str) >= sizeof(lowstr))
315 316 317 318 319 320 321
		dterr = DTERR_BAD_FORMAT;
	else
		dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
	if (dterr == 0)
		dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
	if (dterr != 0)
		DateTimeParseError(dterr, str, "abstime");
322

323 324
	switch (dtype)
	{
325 326 327
		case DTK_DATE:
			result = tm2abstime(tm, tz);
			break;
328

329
		case DTK_EPOCH:
330 331 332 333 334

			/*
			 * Don't bother retaining this as a reserved value, but
			 * instead just set to the actual epoch time (1970-01-01)
			 */
335
			result = 0;
336
			break;
337

338 339 340
		case DTK_LATE:
			result = NOEND_ABSTIME;
			break;
341

342 343 344
		case DTK_EARLY:
			result = NOSTART_ABSTIME;
			break;
345

346 347 348
		case DTK_INVALID:
			result = INVALID_ABSTIME;
			break;
349

350
		default:
351 352
			elog(ERROR, "unexpected dtype %d while parsing abstime \"%s\"",
				 dtype, str);
353 354
			result = INVALID_ABSTIME;
			break;
355
	};
356

357 358
	PG_RETURN_ABSOLUTETIME(result);
}
359

360

361
/* abstimeout()
362 363
 * Given an AbsoluteTime return the English text version of the date
 */
364
Datum
365
abstimeout(PG_FUNCTION_ARGS)
366
{
367
	AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
368 369 370
	char	   *result;
	int			tz;
	double		fsec = 0;
B
Bruce Momjian 已提交
371
	struct pg_tm tt,
372 373 374 375
			   *tm = &tt;
	char		buf[MAXDATELEN + 1];
	char		zone[MAXDATELEN + 1],
			   *tzn = zone;
376 377 378

	switch (time)
	{
379 380 381 382
			/*
			 * Note that timestamp no longer supports 'invalid'. Retain
			 * 'invalid' for abstime for now, but dump it someday.
			 */
383 384 385 386 387 388 389 390 391 392
		case INVALID_ABSTIME:
			strcpy(buf, INVALID);
			break;
		case NOEND_ABSTIME:
			strcpy(buf, LATE);
			break;
		case NOSTART_ABSTIME:
			strcpy(buf, EARLY);
			break;
		default:
393
			abstime2tm(time, &tz, tm, &tzn);
394 395
			EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
			break;
396
	}
397

398 399 400
	result = pstrdup(buf);
	PG_RETURN_CSTRING(result);
}
401

402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
/*
 *		abstimerecv			- converts external binary format to abstime
 */
Datum
abstimerecv(PG_FUNCTION_ARGS)
{
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);

	PG_RETURN_ABSOLUTETIME((AbsoluteTime) pq_getmsgint(buf, sizeof(AbsoluteTime)));
}

/*
 *		abstimesend			- converts abstime to binary format
 */
Datum
abstimesend(PG_FUNCTION_ARGS)
{
	AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
	StringInfoData buf;

	pq_begintypsend(&buf);
	pq_sendint(&buf, time, sizeof(time));
	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}

427

428 429
/* abstime_finite()
 */
430 431
Datum
abstime_finite(PG_FUNCTION_ARGS)
432
{
B
Bruce Momjian 已提交
433
	AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
434

435 436 437
	PG_RETURN_BOOL(abstime != INVALID_ABSTIME &&
				   abstime != NOSTART_ABSTIME &&
				   abstime != NOEND_ABSTIME);
438
}
439 440


441
/*
442
 * abstime comparison routines
443
 */
444 445 446
static int
abstime_cmp_internal(AbsoluteTime a, AbsoluteTime b)
{
447
	/*
B
Bruce Momjian 已提交
448 449 450
	 * We consider all INVALIDs to be equal and larger than any
	 * non-INVALID. This is somewhat arbitrary; the important thing is to
	 * have a consistent sort order.
451
	 */
452 453
	if (a == INVALID_ABSTIME)
	{
454 455 456 457
		if (b == INVALID_ABSTIME)
			return 0;			/* INVALID = INVALID */
		else
			return 1;			/* INVALID > non-INVALID */
458
	}
459 460

	if (b == INVALID_ABSTIME)
461
		return -1;				/* non-INVALID < INVALID */
462 463

#if 0
464
	/* CURRENT is no longer stored internally... */
465 466 467 468 469 470 471 472 473 474 475
	/* XXX this is broken, should go away: */
	if (a == CURRENT_ABSTIME)
		a = GetCurrentTransactionStartTime();
	if (b == CURRENT_ABSTIME)
		b = GetCurrentTransactionStartTime();
#endif

	if (a > b)
		return 1;
	else if (a == b)
		return 0;
476
	else
477
		return -1;
478 479
}

480 481
Datum
abstimeeq(PG_FUNCTION_ARGS)
482
{
B
Bruce Momjian 已提交
483 484
	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
485

486
	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) == 0);
487 488
}

489 490
Datum
abstimene(PG_FUNCTION_ARGS)
491
{
B
Bruce Momjian 已提交
492 493
	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
494

495
	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) != 0);
496 497
}

498 499
Datum
abstimelt(PG_FUNCTION_ARGS)
500
{
B
Bruce Momjian 已提交
501 502
	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
503

504
	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) < 0);
505 506
}

507 508
Datum
abstimegt(PG_FUNCTION_ARGS)
509
{
B
Bruce Momjian 已提交
510 511
	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
512

513
	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) > 0);
514 515
}

516 517
Datum
abstimele(PG_FUNCTION_ARGS)
518
{
B
Bruce Momjian 已提交
519 520
	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
521

522
	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) <= 0);
523 524
}

525 526
Datum
abstimege(PG_FUNCTION_ARGS)
527
{
B
Bruce Momjian 已提交
528 529
	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
530

531 532 533 534 535 536 537 538
	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) >= 0);
}

Datum
btabstimecmp(PG_FUNCTION_ARGS)
{
	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
539

540
	PG_RETURN_INT32(abstime_cmp_internal(t1, t2));
541
}
542

543

544
/* timestamp_abstime()
545
 * Convert timestamp to abstime.
546
 */
547 548
Datum
timestamp_abstime(PG_FUNCTION_ARGS)
549
{
550
	Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
551
	AbsoluteTime result;
552
	fsec_t		fsec;
553
	int			tz;
B
Bruce Momjian 已提交
554
	struct pg_tm tt,
555
			   *tm = &tt;
556

557
	if (TIMESTAMP_IS_NOBEGIN(timestamp))
558
		result = NOSTART_ABSTIME;
559
	else if (TIMESTAMP_IS_NOEND(timestamp))
560
		result = NOEND_ABSTIME;
561 562 563 564 565
	else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
	{
		tz = DetermineLocalTimeZone(tm);
		result = tm2abstime(tm, tz);
	}
566 567
	else
	{
568 569 570
		ereport(ERROR,
				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
				 errmsg("timestamp out of range")));
571
		result = INVALID_ABSTIME;
572
	}
573

574 575
	PG_RETURN_ABSOLUTETIME(result);
}
576

577 578
/* abstime_timestamp()
 * Convert abstime to timestamp.
579
 */
580 581
Datum
abstime_timestamp(PG_FUNCTION_ARGS)
582
{
B
Bruce Momjian 已提交
583
	AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
584
	Timestamp	result;
B
Bruce Momjian 已提交
585
	struct pg_tm tt,
586 587
			   *tm = &tt;
	int			tz;
588 589
	char		zone[MAXDATELEN + 1],
			   *tzn = zone;
590

591 592
	switch (abstime)
	{
593
		case INVALID_ABSTIME:
594 595
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
596
			 errmsg("cannot convert abstime \"invalid\" to timestamp")));
597
			TIMESTAMP_NOBEGIN(result);
598
			break;
599

600
		case NOSTART_ABSTIME:
601
			TIMESTAMP_NOBEGIN(result);
602
			break;
603

604
		case NOEND_ABSTIME:
605
			TIMESTAMP_NOEND(result);
606
			break;
607

608
		default:
609
			abstime2tm(abstime, &tz, tm, &tzn);
610
			if (tm2timestamp(tm, 0, NULL, &result) != 0)
611 612 613
				ereport(ERROR,
						(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
						 errmsg("timestamp out of range")));
614
			break;
615 616 617 618
	};

	PG_RETURN_TIMESTAMP(result);
}
619

620 621 622 623 624 625 626

/* timestamptz_abstime()
 * Convert timestamp with time zone to abstime.
 */
Datum
timestamptz_abstime(PG_FUNCTION_ARGS)
{
627
	TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
628
	AbsoluteTime result;
629
	fsec_t		fsec;
B
Bruce Momjian 已提交
630
	struct pg_tm tt,
631 632 633 634 635 636 637 638 639 640
			   *tm = &tt;

	if (TIMESTAMP_IS_NOBEGIN(timestamp))
		result = NOSTART_ABSTIME;
	else if (TIMESTAMP_IS_NOEND(timestamp))
		result = NOEND_ABSTIME;
	else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
		result = tm2abstime(tm, 0);
	else
	{
641 642 643
		ereport(ERROR,
				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
				 errmsg("timestamp out of range")));
644 645 646 647 648 649 650
		result = INVALID_ABSTIME;
	}

	PG_RETURN_ABSOLUTETIME(result);
}

/* abstime_timestamptz()
651
 * Convert abstime to timestamp with time zone.
652 653 654 655 656
 */
Datum
abstime_timestamptz(PG_FUNCTION_ARGS)
{
	AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
657
	TimestampTz result;
B
Bruce Momjian 已提交
658
	struct pg_tm tt,
659 660 661 662
			   *tm = &tt;
	int			tz;
	char		zone[MAXDATELEN + 1],
			   *tzn = zone;
663 664 665 666

	switch (abstime)
	{
		case INVALID_ABSTIME:
667 668
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
669
			 errmsg("cannot convert abstime \"invalid\" to timestamp")));
670 671 672 673 674 675 676 677 678
			TIMESTAMP_NOBEGIN(result);
			break;

		case NOSTART_ABSTIME:
			TIMESTAMP_NOBEGIN(result);
			break;

		case NOEND_ABSTIME:
			TIMESTAMP_NOEND(result);
679
			break;
680

681
		default:
682 683
			abstime2tm(abstime, &tz, tm, &tzn);
			if (tm2timestamp(tm, 0, &tz, &result) != 0)
684 685 686
				ereport(ERROR,
						(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
						 errmsg("timestamp out of range")));
687
			break;
688
	};
689

690 691
	PG_RETURN_TIMESTAMP(result);
}
692 693 694 695 696 697 698 699 700


/*****************************************************************************
 *	 USER I/O ROUTINES														 *
 *****************************************************************************/

/*
 *		reltimein		- converts a reltime string in an internal format
 */
701 702
Datum
reltimein(PG_FUNCTION_ARGS)
703
{
B
Bruce Momjian 已提交
704
	char	   *str = PG_GETARG_CSTRING(0);
705
	RelativeTime result;
B
Bruce Momjian 已提交
706
	struct pg_tm tt,
707
			   *tm = &tt;
708
	fsec_t		fsec;
709
	int			dtype;
710
	int			dterr;
711 712 713 714 715
	char	   *field[MAXDATEFIELDS];
	int			nf,
				ftype[MAXDATEFIELDS];
	char		lowstr[MAXDATELEN + 1];

716
	if (strlen(str) >= sizeof(lowstr))
717 718 719 720 721 722 723 724 725 726 727
		dterr = DTERR_BAD_FORMAT;
	else
		dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
	if (dterr == 0)
		dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
	if (dterr != 0)
	{
		if (dterr == DTERR_FIELD_OVERFLOW)
			dterr = DTERR_INTERVAL_OVERFLOW;
		DateTimeParseError(dterr, str, "reltime");
	}
728 729 730 731

	switch (dtype)
	{
		case DTK_DELTA:
732 733
			result = ((tm->tm_hour * 60 + tm->tm_min) * 60) + tm->tm_sec;
			result += tm->tm_year * 36525 * 864 + ((tm->tm_mon * 30) + tm->tm_mday) * SECS_PER_DAY;
734
			break;
735 736

		default:
737 738
			elog(ERROR, "unexpected dtype %d while parsing reltime \"%s\"",
				 dtype, str);
739 740
			result = INVALID_RELTIME;
			break;
741 742
	}

743
	PG_RETURN_RELATIVETIME(result);
744
}
745 746 747 748

/*
 *		reltimeout		- converts the internal format to a reltime string
 */
749 750
Datum
reltimeout(PG_FUNCTION_ARGS)
751
{
752
	RelativeTime time = PG_GETARG_RELATIVETIME(0);
753
	char	   *result;
B
Bruce Momjian 已提交
754
	struct pg_tm tt,
755 756 757
			   *tm = &tt;
	char		buf[MAXDATELEN + 1];

758
	reltime2tm(time, tm);
759
	EncodeInterval(tm, 0, DateStyle, buf);
760

761 762 763
	result = pstrdup(buf);
	PG_RETURN_CSTRING(result);
}
764

765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
/*
 *		reltimerecv			- converts external binary format to reltime
 */
Datum
reltimerecv(PG_FUNCTION_ARGS)
{
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);

	PG_RETURN_RELATIVETIME((RelativeTime) pq_getmsgint(buf, sizeof(RelativeTime)));
}

/*
 *		reltimesend			- converts reltime to binary format
 */
Datum
reltimesend(PG_FUNCTION_ARGS)
{
	RelativeTime time = PG_GETARG_RELATIVETIME(0);
	StringInfoData buf;

	pq_begintypsend(&buf);
	pq_sendint(&buf, time, sizeof(time));
	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}

790 791

static void
792
reltime2tm(RelativeTime time, struct pg_tm * tm)
793
{
B
Bruce Momjian 已提交
794
	double		dtime = time;
795 796 797

	FMODULO(dtime, tm->tm_year, 31557600);
	FMODULO(dtime, tm->tm_mon, 2592000);
798
	FMODULO(dtime, tm->tm_mday, SECS_PER_DAY);
799 800 801
	FMODULO(dtime, tm->tm_hour, 3600);
	FMODULO(dtime, tm->tm_min, 60);
	FMODULO(dtime, tm->tm_sec, 1);
802
}
803 804 805


/*
806
 *		tintervalin		- converts an interval string to internal format
807
 */
808 809
Datum
tintervalin(PG_FUNCTION_ARGS)
810
{
811 812
	char	   *intervalstr = PG_GETARG_CSTRING(0);
	TimeInterval interval;
813 814 815 816 817 818
	AbsoluteTime i_start,
				i_end,
				t1,
				t2;

	interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
819

820
	if (istinterval(intervalstr, &t1, &t2) == 0)
821 822
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
823
				 errmsg("invalid input syntax for type tinterval: \"%s\"",
824
						intervalstr)));
825

826
	if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
827 828
		interval  ->status = T_INTERVAL_INVAL;	/* undefined  */

829
	else
830
		interval  ->status = T_INTERVAL_VALID;
831 832 833

	i_start = ABSTIMEMIN(t1, t2);
	i_end = ABSTIMEMAX(t1, t2);
834 835
	interval  ->data[0] = i_start;
	interval  ->data[1] = i_end;
836

837
	PG_RETURN_TIMEINTERVAL(interval);
838 839 840 841 842 843
}


/*
 *		tintervalout	- converts an internal interval format to a string
 */
844 845
Datum
tintervalout(PG_FUNCTION_ARGS)
846
{
847
	TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
848 849 850
	char	   *i_str,
			   *p;

851
	i_str = (char *) palloc(T_INTERVAL_LEN);	/* ["..." "..."] */
852 853 854 855 856
	strcpy(i_str, "[\"");
	if (interval->status == T_INTERVAL_INVAL)
		strcat(i_str, INVALID_INTERVAL_STR);
	else
	{
857
		p = DatumGetCString(DirectFunctionCall1(abstimeout,
B
Bruce Momjian 已提交
858
							   AbsoluteTimeGetDatum(interval->data[0])));
859 860 861
		strcat(i_str, p);
		pfree(p);
		strcat(i_str, "\" \"");
862
		p = DatumGetCString(DirectFunctionCall1(abstimeout,
B
Bruce Momjian 已提交
863
							   AbsoluteTimeGetDatum(interval->data[1])));
864 865 866
		strcat(i_str, p);
		pfree(p);
	}
867
	strcat(i_str, "\"]");
868
	PG_RETURN_CSTRING(i_str);
869 870
}

871 872 873 874 875 876 877 878 879 880 881
/*
 *		tintervalrecv			- converts external binary format to tinterval
 */
Datum
tintervalrecv(PG_FUNCTION_ARGS)
{
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
	TimeInterval interval;

	interval = (TimeInterval) palloc(sizeof(TimeIntervalData));

882 883
	interval  ->status = pq_getmsgint(buf, sizeof(interval->status));

884 885
	if (!(interval->status == T_INTERVAL_INVAL ||
		  interval->status == T_INTERVAL_VALID))
886 887
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
B
Bruce Momjian 已提交
888
			  errmsg("invalid status in external \"tinterval\" value")));
889

890 891
	interval  ->data[0] = pq_getmsgint(buf, sizeof(interval->data[0]));
	interval  ->data[1] = pq_getmsgint(buf, sizeof(interval->data[1]));
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911

	PG_RETURN_TIMEINTERVAL(interval);
}

/*
 *		tintervalsend			- converts tinterval to binary format
 */
Datum
tintervalsend(PG_FUNCTION_ARGS)
{
	TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
	StringInfoData buf;

	pq_begintypsend(&buf);
	pq_sendint(&buf, interval->status, sizeof(interval->status));
	pq_sendint(&buf, interval->data[0], sizeof(interval->data[0]));
	pq_sendint(&buf, interval->data[1], sizeof(interval->data[1]));
	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}

912 913 914 915 916

/*****************************************************************************
 *	 PUBLIC ROUTINES														 *
 *****************************************************************************/

917 918
Datum
interval_reltime(PG_FUNCTION_ARGS)
919
{
920
	Interval   *interval = PG_GETARG_INTERVAL_P(0);
921 922 923
	RelativeTime time;
	int			year,
				month;
B
Bruce Momjian 已提交
924

925 926
#ifdef HAVE_INT64_TIMESTAMP
	int64		span;
B
Bruce Momjian 已提交
927

928
#else
929
	double		span;
930
#endif
931

932 933 934 935 936
	if (interval->month == 0)
	{
		year = 0;
		month = 0;
	}
937
	else if (abs(interval->month) >=12)
938 939 940 941
	{
		year = (interval->month / 12);
		month = (interval->month % 12);
	}
942 943
	else
	{
944 945 946
		year = 0;
		month = interval->month;
	}
947

948
#ifdef HAVE_INT64_TIMESTAMP
949 950
	span = ((INT64CONST(365250000) * year + INT64CONST(30000000) * month) *
			INT64CONST(86400)) + interval->time;
951
	span /= USECS_PER_SEC;
952
#else
953
	span = (365.25 * year + 30.0 * month) * SECS_PER_DAY + interval->time;
954
#endif
955

956
	if (span < INT_MIN || span > INT_MAX)
957 958 959
		time = INVALID_RELTIME;
	else
		time = span;
960

961 962
	PG_RETURN_RELATIVETIME(time);
}
963 964


965 966
Datum
reltime_interval(PG_FUNCTION_ARGS)
967
{
968
	RelativeTime reltime = PG_GETARG_RELATIVETIME(0);
969 970 971 972
	Interval   *result;
	int			year,
				month;

973
	result = (Interval *) palloc(sizeof(Interval));
974 975 976 977

	switch (reltime)
	{
		case INVALID_RELTIME:
978 979
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
980
			  errmsg("cannot convert reltime \"invalid\" to interval")));
981 982
			result->time = 0;
			result->month = 0;
983 984 985
			break;

		default:
986 987 988
#ifdef HAVE_INT64_TIMESTAMP
			year = (reltime / (36525 * 864));
			reltime -= (year * (36525 * 864));
989 990
			month = (reltime / (30 * SECS_PER_DAY));
			reltime -= (month * (30 * SECS_PER_DAY));
991

992
			result->time = (reltime * USECS_PER_SEC);
993
#else
994 995
			TMODULO(reltime, year, 36525 * 864);
			TMODULO(reltime, month, 30 * SECS_PER_DAY);
996 997

			result->time = reltime;
998
#endif
999
			result->month = 12 * year + month;
1000
			break;
1001 1002
	}

1003 1004
	PG_RETURN_INTERVAL_P(result);
}
1005 1006 1007 1008 1009


/*
 *		mktinterval		- creates a time interval with endpoints t1 and t2
 */
1010 1011
Datum
mktinterval(PG_FUNCTION_ARGS)
1012
{
1013 1014
	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
1015 1016
	AbsoluteTime tstart = ABSTIMEMIN(t1, t2);
	AbsoluteTime tend = ABSTIMEMAX(t1, t2);
1017 1018 1019
	TimeInterval interval;

	interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
1020

1021
	if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
1022 1023
		interval  ->status = T_INTERVAL_INVAL;

1024 1025
	else
	{
1026 1027 1028
		interval  ->status = T_INTERVAL_VALID;
		interval  ->data[0] = tstart;
		interval  ->data[1] = tend;
1029 1030
	}

1031
	PG_RETURN_TIMEINTERVAL(interval);
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
}

/*
 *		timepl, timemi and abstimemi use the formula
 *				abstime + reltime = abstime
 *		so		abstime - reltime = abstime
 *		and		abstime - abstime = reltime
 */

/*
1042
 *		timepl			- returns the value of (abstime t1 + reltime t2)
1043
 */
1044 1045
Datum
timepl(PG_FUNCTION_ARGS)
1046
{
B
Bruce Momjian 已提交
1047 1048
	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1049

1050 1051
	if (AbsoluteTimeIsReal(t1) &&
		RelativeTimeIsValid(t2) &&
1052 1053
		((t2 > 0 && t1 < NOEND_ABSTIME - t2) ||
		(t2 <= 0 && t1 > NOSTART_ABSTIME - t2)))		/* prevent overflow */
1054
		PG_RETURN_ABSOLUTETIME(t1 + t2);
1055

1056
	PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1057 1058 1059 1060 1061 1062
}


/*
 *		timemi			- returns the value of (abstime t1 - reltime t2)
 */
1063 1064
Datum
timemi(PG_FUNCTION_ARGS)
1065
{
B
Bruce Momjian 已提交
1066 1067
	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1068

1069 1070
	if (AbsoluteTimeIsReal(t1) &&
		RelativeTimeIsValid(t2) &&
1071 1072
		((t2 > 0 && t1 > NOSTART_ABSTIME + t2) ||
		 (t2 <= 0 && t1 < NOEND_ABSTIME + t2)))	/* prevent overflow */
1073
		PG_RETURN_ABSOLUTETIME(t1 - t2);
1074

1075
	PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1076 1077 1078 1079
}


/*
1080
 *		intinterval		- returns true iff absolute date is in the interval
1081
 */
1082 1083
Datum
intinterval(PG_FUNCTION_ARGS)
1084
{
B
Bruce Momjian 已提交
1085 1086
	AbsoluteTime t = PG_GETARG_ABSOLUTETIME(0);
	TimeInterval interval = PG_GETARG_TIMEINTERVAL(1);
1087

1088
	if (interval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME)
1089 1090
	{
		if (DatumGetBool(DirectFunctionCall2(abstimege,
B
Bruce Momjian 已提交
1091 1092
											 AbsoluteTimeGetDatum(t),
							 AbsoluteTimeGetDatum(interval->data[0]))) &&
1093
			DatumGetBool(DirectFunctionCall2(abstimele,
B
Bruce Momjian 已提交
1094 1095
											 AbsoluteTimeGetDatum(t),
							   AbsoluteTimeGetDatum(interval->data[1]))))
1096 1097 1098
			PG_RETURN_BOOL(true);
	}
	PG_RETURN_BOOL(false);
1099 1100 1101 1102 1103
}

/*
 *		tintervalrel		- returns  relative time corresponding to interval
 */
1104 1105
Datum
tintervalrel(PG_FUNCTION_ARGS)
1106
{
1107
	TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
1108 1109
	AbsoluteTime t1 = interval->data[0];
	AbsoluteTime t2 = interval->data[1];
1110 1111 1112 1113

	if (interval->status != T_INTERVAL_VALID)
		PG_RETURN_RELATIVETIME(INVALID_RELTIME);

1114 1115 1116 1117 1118
	if (AbsoluteTimeIsReal(t1) &&
		AbsoluteTimeIsReal(t2))
		PG_RETURN_RELATIVETIME(t2 - t1);

	PG_RETURN_RELATIVETIME(INVALID_RELTIME);
1119 1120
}

1121

1122 1123 1124 1125 1126
/*
 *		timenow			- returns  time "now", internal format
 *
 *		Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992
 */
1127 1128
Datum
timenow(PG_FUNCTION_ARGS)
1129 1130 1131 1132
{
	time_t		sec;

	if (time(&sec) < 0)
1133
		PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1134

1135
	PG_RETURN_ABSOLUTETIME((AbsoluteTime) sec);
1136 1137 1138
}

/*
1139
 * reltime comparison routines
1140
 */
1141 1142 1143 1144
static int
reltime_cmp_internal(RelativeTime a, RelativeTime b)
{
	/*
B
Bruce Momjian 已提交
1145 1146 1147
	 * We consider all INVALIDs to be equal and larger than any
	 * non-INVALID. This is somewhat arbitrary; the important thing is to
	 * have a consistent sort order.
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
	 */
	if (a == INVALID_RELTIME)
	{
		if (b == INVALID_RELTIME)
			return 0;			/* INVALID = INVALID */
		else
			return 1;			/* INVALID > non-INVALID */
	}

	if (b == INVALID_RELTIME)
		return -1;				/* non-INVALID < INVALID */

	if (a > b)
		return 1;
	else if (a == b)
		return 0;
	else
		return -1;
}

1168 1169
Datum
reltimeeq(PG_FUNCTION_ARGS)
1170
{
B
Bruce Momjian 已提交
1171 1172
	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1173

1174
	PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) == 0);
1175 1176
}

1177 1178
Datum
reltimene(PG_FUNCTION_ARGS)
1179
{
B
Bruce Momjian 已提交
1180 1181
	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1182

1183
	PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) != 0);
1184 1185
}

1186 1187
Datum
reltimelt(PG_FUNCTION_ARGS)
1188
{
B
Bruce Momjian 已提交
1189 1190
	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1191

1192
	PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) < 0);
1193 1194
}

1195 1196
Datum
reltimegt(PG_FUNCTION_ARGS)
1197
{
B
Bruce Momjian 已提交
1198 1199
	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1200

1201
	PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) > 0);
1202 1203
}

1204 1205
Datum
reltimele(PG_FUNCTION_ARGS)
1206
{
B
Bruce Momjian 已提交
1207 1208
	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1209

1210
	PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) <= 0);
1211 1212
}

1213 1214
Datum
reltimege(PG_FUNCTION_ARGS)
1215
{
B
Bruce Momjian 已提交
1216 1217
	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1218

1219 1220 1221 1222 1223 1224 1225 1226 1227 1228
	PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) >= 0);
}

Datum
btreltimecmp(PG_FUNCTION_ARGS)
{
	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);

	PG_RETURN_INT32(reltime_cmp_internal(t1, t2));
1229 1230 1231 1232
}


/*
1233
 *		tintervalsame	- returns true iff interval i1 is same as interval i2
1234 1235
 *		Check begin and end time.
 */
1236 1237
Datum
tintervalsame(PG_FUNCTION_ARGS)
1238
{
B
Bruce Momjian 已提交
1239 1240
	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1241

1242
	if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1243 1244 1245
		PG_RETURN_BOOL(false);

	if (DatumGetBool(DirectFunctionCall2(abstimeeq,
1246 1247
									   AbsoluteTimeGetDatum(i1->data[0]),
								   AbsoluteTimeGetDatum(i2->data[0]))) &&
1248
		DatumGetBool(DirectFunctionCall2(abstimeeq,
1249 1250
									   AbsoluteTimeGetDatum(i1->data[1]),
									 AbsoluteTimeGetDatum(i2->data[1]))))
1251 1252 1253
		PG_RETURN_BOOL(true);
	PG_RETURN_BOOL(false);
}
1254 1255

/*
1256 1257 1258
 * tinterval comparison routines
 *
 * Note: comparison is based on the lengths of the intervals, not on
B
Bruce Momjian 已提交
1259
 * endpoint value.	This is pretty bogus, but since it's only a legacy
1260
 * datatype I'm not going to propose changing it.
1261
 */
1262 1263
static int
tinterval_cmp_internal(TimeInterval a, TimeInterval b)
1264
{
1265 1266 1267 1268
	bool		a_invalid;
	bool		b_invalid;
	AbsoluteTime a_len;
	AbsoluteTime b_len;
1269

1270
	/*
B
Bruce Momjian 已提交
1271 1272 1273
	 * We consider all INVALIDs to be equal and larger than any
	 * non-INVALID. This is somewhat arbitrary; the important thing is to
	 * have a consistent sort order.
1274
	 */
1275 1276 1277 1278 1279 1280
	a_invalid = a->status == T_INTERVAL_INVAL ||
				a->data[0] == INVALID_ABSTIME ||
				a->data[1] == INVALID_ABSTIME;
	b_invalid = b->status == T_INTERVAL_INVAL ||
				b->data[0] == INVALID_ABSTIME ||
				b->data[1] == INVALID_ABSTIME;
1281 1282 1283 1284 1285 1286 1287 1288

	if (a_invalid)
	{
		if (b_invalid)
			return 0;			/* INVALID = INVALID */
		else
			return 1;			/* INVALID > non-INVALID */
	}
1289

1290 1291
	if (b_invalid)
		return -1;				/* non-INVALID < INVALID */
1292

1293 1294
	a_len = a->data[1] - a->data[0];
	b_len = b->data[1] - b->data[0];
1295

1296 1297 1298 1299 1300 1301
	if (a_len > b_len)
		return 1;
	else if (a_len == b_len)
		return 0;
	else
		return -1;
1302
}
1303

1304
Datum
1305
tintervaleq(PG_FUNCTION_ARGS)
1306
{
B
Bruce Momjian 已提交
1307 1308
	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1309

1310 1311
	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) == 0);
}
1312

1313 1314 1315 1316 1317
Datum
tintervalne(PG_FUNCTION_ARGS)
{
	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1318

1319
	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) != 0);
1320
}
1321

1322 1323
Datum
tintervallt(PG_FUNCTION_ARGS)
1324
{
B
Bruce Momjian 已提交
1325 1326
	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1327

1328
	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) < 0);
1329
}
1330

1331 1332
Datum
tintervalle(PG_FUNCTION_ARGS)
1333
{
B
Bruce Momjian 已提交
1334 1335
	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1336

1337
	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) <= 0);
1338
}
1339

1340 1341
Datum
tintervalgt(PG_FUNCTION_ARGS)
1342
{
B
Bruce Momjian 已提交
1343 1344
	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1345

1346
	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) > 0);
1347
}
1348

1349 1350
Datum
tintervalge(PG_FUNCTION_ARGS)
1351
{
B
Bruce Momjian 已提交
1352 1353
	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1354

1355 1356
	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) >= 0);
}
1357

1358 1359 1360 1361 1362
Datum
bttintervalcmp(PG_FUNCTION_ARGS)
{
	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1363

1364
	PG_RETURN_INT32(tinterval_cmp_internal(i1, i2));
1365
}
1366 1367 1368


/*
1369
 *		tintervalleneq	- returns true iff length of interval i is equal to
1370
 *								reltime t
1371 1372 1373 1374 1375 1376 1377 1378 1379 1380
 *		tintervallenne	- returns true iff length of interval i is not equal
 *								to reltime t
 *		tintervallenlt	- returns true iff length of interval i is less than
 *								reltime t
 *		tintervallengt	- returns true iff length of interval i is greater
 *								than reltime t
 *		tintervallenle	- returns true iff length of interval i is less or
 *								equal than reltime t
 *		tintervallenge	- returns true iff length of interval i is greater or
 *								equal than reltime t
1381
 */
1382 1383
Datum
tintervalleneq(PG_FUNCTION_ARGS)
1384
{
1385 1386
	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1387 1388
	RelativeTime rt;

1389 1390 1391
	if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
		PG_RETURN_BOOL(false);
	rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1392
											   TimeIntervalGetDatum(i)));
1393
	PG_RETURN_BOOL(rt != INVALID_RELTIME && rt == t);
1394 1395
}

1396 1397
Datum
tintervallenne(PG_FUNCTION_ARGS)
1398
{
1399 1400
	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1401 1402
	RelativeTime rt;

1403 1404 1405
	if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
		PG_RETURN_BOOL(false);
	rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
B
Bruce Momjian 已提交
1406
											   TimeIntervalGetDatum(i)));
1407
	PG_RETURN_BOOL(rt != INVALID_RELTIME && rt != t);
1408 1409
}

1410 1411
Datum
tintervallenlt(PG_FUNCTION_ARGS)
1412
{
1413 1414
	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1415 1416
	RelativeTime rt;

1417 1418 1419
	if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
		PG_RETURN_BOOL(false);
	rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
B
Bruce Momjian 已提交
1420
											   TimeIntervalGetDatum(i)));
1421
	PG_RETURN_BOOL(rt != INVALID_RELTIME && rt < t);
1422 1423
}

1424 1425
Datum
tintervallengt(PG_FUNCTION_ARGS)
1426
{
1427 1428
	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1429 1430
	RelativeTime rt;

1431 1432 1433
	if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
		PG_RETURN_BOOL(false);
	rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
B
Bruce Momjian 已提交
1434
											   TimeIntervalGetDatum(i)));
1435
	PG_RETURN_BOOL(rt != INVALID_RELTIME && rt > t);
1436 1437
}

1438 1439
Datum
tintervallenle(PG_FUNCTION_ARGS)
1440
{
1441 1442
	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1443 1444
	RelativeTime rt;

1445 1446 1447
	if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
		PG_RETURN_BOOL(false);
	rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
B
Bruce Momjian 已提交
1448
											   TimeIntervalGetDatum(i)));
1449
	PG_RETURN_BOOL(rt != INVALID_RELTIME && rt <= t);
1450 1451
}

1452 1453
Datum
tintervallenge(PG_FUNCTION_ARGS)
1454
{
1455 1456
	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1457 1458
	RelativeTime rt;

1459 1460 1461
	if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
		PG_RETURN_BOOL(false);
	rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
B
Bruce Momjian 已提交
1462
											   TimeIntervalGetDatum(i)));
1463
	PG_RETURN_BOOL(rt != INVALID_RELTIME && rt >= t);
1464 1465 1466
}

/*
1467
 *		tintervalct		- returns true iff interval i1 contains interval i2
1468
 */
1469 1470
Datum
tintervalct(PG_FUNCTION_ARGS)
1471
{
B
Bruce Momjian 已提交
1472 1473
	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1474

1475
	if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1476 1477
		PG_RETURN_BOOL(false);
	if (DatumGetBool(DirectFunctionCall2(abstimele,
B
Bruce Momjian 已提交
1478 1479
									   AbsoluteTimeGetDatum(i1->data[0]),
								   AbsoluteTimeGetDatum(i2->data[0]))) &&
1480
		DatumGetBool(DirectFunctionCall2(abstimege,
B
Bruce Momjian 已提交
1481 1482
									   AbsoluteTimeGetDatum(i1->data[1]),
									 AbsoluteTimeGetDatum(i2->data[1]))))
1483 1484
		PG_RETURN_BOOL(true);
	PG_RETURN_BOOL(false);
1485 1486 1487
}

/*
1488
 *		tintervalov		- returns true iff interval i1 (partially) overlaps i2
1489
 */
1490 1491
Datum
tintervalov(PG_FUNCTION_ARGS)
1492
{
B
Bruce Momjian 已提交
1493 1494
	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1495

1496
	if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1497 1498
		PG_RETURN_BOOL(false);
	if (DatumGetBool(DirectFunctionCall2(abstimelt,
1499 1500
									   AbsoluteTimeGetDatum(i1->data[1]),
								   AbsoluteTimeGetDatum(i2->data[0]))) ||
1501
		DatumGetBool(DirectFunctionCall2(abstimegt,
1502 1503
									   AbsoluteTimeGetDatum(i1->data[0]),
									 AbsoluteTimeGetDatum(i2->data[1]))))
1504 1505
		PG_RETURN_BOOL(false);
	PG_RETURN_BOOL(true);
1506 1507 1508 1509 1510
}

/*
 *		tintervalstart	- returns  the start of interval i
 */
1511 1512
Datum
tintervalstart(PG_FUNCTION_ARGS)
1513
{
B
Bruce Momjian 已提交
1514
	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1515

1516
	if (i->status == T_INTERVAL_INVAL)
1517 1518
		PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
	PG_RETURN_ABSOLUTETIME(i->data[0]);
1519 1520 1521 1522 1523
}

/*
 *		tintervalend		- returns  the end of interval i
 */
1524 1525
Datum
tintervalend(PG_FUNCTION_ARGS)
1526
{
B
Bruce Momjian 已提交
1527
	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1528

1529
	if (i->status == T_INTERVAL_INVAL)
1530 1531
		PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
	PG_RETURN_ABSOLUTETIME(i->data[1]);
1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576
}


/*****************************************************************************
 *	 PRIVATE ROUTINES														 *
 *****************************************************************************/

/*
 *		istinterval		- returns 1, iff i_string is a valid interval descr.
 *								  0, iff i_string is NOT a valid interval desc.
 *								  2, iff any time is INVALID_ABSTIME
 *
 *		output parameter:
 *				i_start, i_end: interval margins
 *
 *		Time interval:
 *		`[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]'
 *
 *		OR	`Undefined Range'	(see also INVALID_INTERVAL_STR)
 *
 *		where <AbsTime> satisfies the syntax of absolute time.
 *
 *		e.g.  [  '  Jan 18 1902'   'Jan 1 00:00:00 1970']
 */
static int
istinterval(char *i_string,
			AbsoluteTime *i_start,
			AbsoluteTime *i_end)
{
	char	   *p,
			   *p1;
	char		c;

	p = i_string;
	/* skip leading blanks up to '[' */
	while ((c = *p) != '\0')
	{
		if (IsSpace(c))
			p++;
		else if (c != '[')
			return 0;			/* syntax error */
		else
			break;
	}
	p++;
1577
	/* skip leading blanks up to '"' */
1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602
	while ((c = *p) != '\0')
	{
		if (IsSpace(c))
			p++;
		else if (c != '"')
			return 0;			/* syntax error */
		else
			break;
	}
	p++;
	if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0)
		return 0;				/* undefined range, handled like a syntax
								 * err. */
	/* search for the end of the first date and change it to a NULL */
	p1 = p;
	while ((c = *p1) != '\0')
	{
		if (c == '"')
		{
			*p1 = '\0';
			break;
		}
		p1++;
	}
	/* get the first date */
1603
	*i_start = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
B
Bruce Momjian 已提交
1604
													CStringGetDatum(p)));
1605
	/* rechange NULL at the end of the first date to a '"' */
1606 1607
	*p1 = '"';
	p = ++p1;
1608
	/* skip blanks up to '"', beginning of second date */
1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630
	while ((c = *p) != '\0')
	{
		if (IsSpace(c))
			p++;
		else if (c != '"')
			return 0;			/* syntax error */
		else
			break;
	}
	p++;
	/* search for the end of the second date and change it to a NULL */
	p1 = p;
	while ((c = *p1) != '\0')
	{
		if (c == '"')
		{
			*p1 = '\0';
			break;
		}
		p1++;
	}
	/* get the second date */
1631
	*i_end = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
B
Bruce Momjian 已提交
1632
													CStringGetDatum(p)));
1633
	/* rechange NULL at the end of the first date to a '"' */
1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665
	*p1 = '"';
	p = ++p1;
	/* skip blanks up to ']' */
	while ((c = *p) != '\0')
	{
		if (IsSpace(c))
			p++;
		else if (c != ']')
			return 0;			/* syntax error */
		else
			break;
	}
	p++;
	c = *p;
	if (c != '\0')
		return 0;				/* syntax error */
	/* it seems to be a valid interval */
	return 1;
}


/*****************************************************************************
 *
 *****************************************************************************/

/*
 * timeofday -
 *	   returns the current time as a text. similar to timenow() but returns
 *	   seconds with more precision (up to microsecs). (I need this to compare
 *	   the Wisconsin benchmark with Illustra whose TimeNow() shows current
 *	   time with precision up to microsecs.)			  - ay 3/95
 */
1666 1667
Datum
timeofday(PG_FUNCTION_ARGS)
1668 1669 1670
{
	struct timeval tp;
	struct timezone tpz;
1671 1672
	char		templ[128];
	char		buf[128];
1673
	text	   *result;
1674
	int			len;
1675
	pg_time_t	tt;
1676 1677

	gettimeofday(&tp, &tpz);
1678
	tt = (pg_time_t) tp.tv_sec;
1679
	pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
1680
				pg_localtime(&tt,global_timezone));
1681
	snprintf(buf, sizeof(buf), templ, tp.tv_usec);
1682 1683

	len = VARHDRSZ + strlen(buf);
1684
	result = (text *) palloc(len);
J
TOAST  
Jan Wieck 已提交
1685
	VARATT_SIZEP(result) = len;
1686 1687
	memcpy(VARDATA(result), buf, strlen(buf));
	PG_RETURN_TEXT_P(result);
1688
}