nabstime.c 37.7 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.132 2005/05/26 02:04:13 neilc 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
	char	   *field[MAXDATEFIELDS];
309
	char		workbuf[MAXDATELEN + 1];
310 311 312
	int			dtype;
	int			nf,
				ftype[MAXDATEFIELDS];
313

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

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

327
		case DTK_EPOCH:
328 329 330 331 332

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

336 337 338
		case DTK_LATE:
			result = NOEND_ABSTIME;
			break;
339

340 341 342
		case DTK_EARLY:
			result = NOSTART_ABSTIME;
			break;
343

344 345 346
		case DTK_INVALID:
			result = INVALID_ABSTIME;
			break;
347

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

355 356
	PG_RETURN_ABSOLUTETIME(result);
}
357

358

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

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

396 397 398
	result = pstrdup(buf);
	PG_RETURN_CSTRING(result);
}
399

400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
/*
 *		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));
}

425

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

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


439
/*
440
 * abstime comparison routines
441
 */
442 443 444
static int
abstime_cmp_internal(AbsoluteTime a, AbsoluteTime b)
{
445
	/*
B
Bruce Momjian 已提交
446 447 448
	 * 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.
449
	 */
450 451
	if (a == INVALID_ABSTIME)
	{
452 453 454 455
		if (b == INVALID_ABSTIME)
			return 0;			/* INVALID = INVALID */
		else
			return 1;			/* INVALID > non-INVALID */
456
	}
457 458

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

#if 0
462
	/* CURRENT is no longer stored internally... */
463 464 465 466 467 468 469 470 471 472 473
	/* 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;
474
	else
475
		return -1;
476 477
}

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

484
	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) == 0);
485 486
}

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

493
	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) != 0);
494 495
}

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

502
	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) < 0);
503 504
}

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

511
	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) > 0);
512 513
}

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

520
	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) <= 0);
521 522
}

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

529 530 531 532 533 534 535 536
	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);
537

538
	PG_RETURN_INT32(abstime_cmp_internal(t1, t2));
539
}
540

541

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

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

572 573
	PG_RETURN_ABSOLUTETIME(result);
}
574

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

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

598
		case NOSTART_ABSTIME:
599
			TIMESTAMP_NOBEGIN(result);
600
			break;
601

602
		case NOEND_ABSTIME:
603
			TIMESTAMP_NOEND(result);
604
			break;
605

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

	PG_RETURN_TIMESTAMP(result);
}
617

618 619 620 621 622 623 624

/* timestamptz_abstime()
 * Convert timestamp with time zone to abstime.
 */
Datum
timestamptz_abstime(PG_FUNCTION_ARGS)
{
625
	TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
626
	AbsoluteTime result;
627
	fsec_t		fsec;
B
Bruce Momjian 已提交
628
	struct pg_tm tt,
629 630 631 632 633 634 635 636 637 638
			   *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
	{
639 640 641
		ereport(ERROR,
				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
				 errmsg("timestamp out of range")));
642 643 644 645 646 647 648
		result = INVALID_ABSTIME;
	}

	PG_RETURN_ABSOLUTETIME(result);
}

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

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

		case NOSTART_ABSTIME:
			TIMESTAMP_NOBEGIN(result);
			break;

		case NOEND_ABSTIME:
			TIMESTAMP_NOEND(result);
677
			break;
678

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

688 689
	PG_RETURN_TIMESTAMP(result);
}
690 691 692 693 694 695 696 697 698


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

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

714 715
	dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
						  field, ftype, MAXDATEFIELDS, &nf);
716 717 718 719 720 721 722 723
	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");
	}
724 725 726 727

	switch (dtype)
	{
		case DTK_DELTA:
728 729
			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;
730
			break;
731 732

		default:
733 734
			elog(ERROR, "unexpected dtype %d while parsing reltime \"%s\"",
				 dtype, str);
735 736
			result = INVALID_RELTIME;
			break;
737 738
	}

739
	PG_RETURN_RELATIVETIME(result);
740
}
741 742 743 744

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

754
	reltime2tm(time, tm);
755
	EncodeInterval(tm, 0, DateStyle, buf);
756

757 758 759
	result = pstrdup(buf);
	PG_RETURN_CSTRING(result);
}
760

761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785
/*
 *		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));
}

786 787

static void
788
reltime2tm(RelativeTime time, struct pg_tm * tm)
789
{
B
Bruce Momjian 已提交
790
	double		dtime = time;
791 792 793

	FMODULO(dtime, tm->tm_year, 31557600);
	FMODULO(dtime, tm->tm_mon, 2592000);
794
	FMODULO(dtime, tm->tm_mday, SECS_PER_DAY);
795 796 797
	FMODULO(dtime, tm->tm_hour, 3600);
	FMODULO(dtime, tm->tm_min, 60);
	FMODULO(dtime, tm->tm_sec, 1);
798
}
799 800 801


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

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

816
	if (istinterval(intervalstr, &t1, &t2) == 0)
817 818
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
819
				 errmsg("invalid input syntax for type tinterval: \"%s\"",
820
						intervalstr)));
821

822
	if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
823 824
		interval  ->status = T_INTERVAL_INVAL;	/* undefined  */

825
	else
826
		interval  ->status = T_INTERVAL_VALID;
827 828 829

	i_start = ABSTIMEMIN(t1, t2);
	i_end = ABSTIMEMAX(t1, t2);
830 831
	interval  ->data[0] = i_start;
	interval  ->data[1] = i_end;
832

833
	PG_RETURN_TIMEINTERVAL(interval);
834 835 836 837 838 839
}


/*
 *		tintervalout	- converts an internal interval format to a string
 */
840 841
Datum
tintervalout(PG_FUNCTION_ARGS)
842
{
843
	TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
844 845 846
	char	   *i_str,
			   *p;

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

867 868 869 870 871 872 873 874 875 876 877
/*
 *		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));

878 879
	interval  ->status = pq_getmsgint(buf, sizeof(interval->status));

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

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

	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));
}

908 909 910 911 912

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

913 914
Datum
interval_reltime(PG_FUNCTION_ARGS)
915
{
916
	Interval   *interval = PG_GETARG_INTERVAL_P(0);
917 918 919
	RelativeTime time;
	int			year,
				month;
B
Bruce Momjian 已提交
920

921 922
#ifdef HAVE_INT64_TIMESTAMP
	int64		span;
B
Bruce Momjian 已提交
923

924
#else
925
	double		span;
926
#endif
927

928 929 930 931 932
	if (interval->month == 0)
	{
		year = 0;
		month = 0;
	}
933
	else if (abs(interval->month) >=12)
934 935 936 937
	{
		year = (interval->month / 12);
		month = (interval->month % 12);
	}
938 939
	else
	{
940 941 942
		year = 0;
		month = interval->month;
	}
943

944
#ifdef HAVE_INT64_TIMESTAMP
945 946
	span = ((INT64CONST(365250000) * year + INT64CONST(30000000) * month) *
			INT64CONST(86400)) + interval->time;
947
	span /= USECS_PER_SEC;
948
#else
949
	span = (365.25 * year + 30.0 * month) * SECS_PER_DAY + interval->time;
950
#endif
951

952
	if (span < INT_MIN || span > INT_MAX)
953 954 955
		time = INVALID_RELTIME;
	else
		time = span;
956

957 958
	PG_RETURN_RELATIVETIME(time);
}
959 960


961 962
Datum
reltime_interval(PG_FUNCTION_ARGS)
963
{
964
	RelativeTime reltime = PG_GETARG_RELATIVETIME(0);
965 966 967 968
	Interval   *result;
	int			year,
				month;

969
	result = (Interval *) palloc(sizeof(Interval));
970 971 972 973

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

		default:
982 983 984
#ifdef HAVE_INT64_TIMESTAMP
			year = (reltime / (36525 * 864));
			reltime -= (year * (36525 * 864));
985 986
			month = (reltime / (30 * SECS_PER_DAY));
			reltime -= (month * (30 * SECS_PER_DAY));
987

988
			result->time = (reltime * USECS_PER_SEC);
989
#else
990 991
			TMODULO(reltime, year, 36525 * 864);
			TMODULO(reltime, month, 30 * SECS_PER_DAY);
992 993

			result->time = reltime;
994
#endif
995
			result->month = 12 * year + month;
996
			break;
997 998
	}

999 1000
	PG_RETURN_INTERVAL_P(result);
}
1001 1002 1003 1004 1005


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

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

1017
	if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
1018 1019
		interval  ->status = T_INTERVAL_INVAL;

1020 1021
	else
	{
1022 1023 1024
		interval  ->status = T_INTERVAL_VALID;
		interval  ->data[0] = tstart;
		interval  ->data[1] = tend;
1025 1026
	}

1027
	PG_RETURN_TIMEINTERVAL(interval);
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
}

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

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

1046 1047
	if (AbsoluteTimeIsReal(t1) &&
		RelativeTimeIsValid(t2) &&
1048 1049
		((t2 > 0 && t1 < NOEND_ABSTIME - t2) ||
		(t2 <= 0 && t1 > NOSTART_ABSTIME - t2)))		/* prevent overflow */
1050
		PG_RETURN_ABSOLUTETIME(t1 + t2);
1051

1052
	PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1053 1054 1055 1056 1057 1058
}


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

1065 1066
	if (AbsoluteTimeIsReal(t1) &&
		RelativeTimeIsValid(t2) &&
1067 1068
		((t2 > 0 && t1 > NOSTART_ABSTIME + t2) ||
		 (t2 <= 0 && t1 < NOEND_ABSTIME + t2)))	/* prevent overflow */
1069
		PG_RETURN_ABSOLUTETIME(t1 - t2);
1070

1071
	PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1072 1073 1074 1075
}


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

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

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

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

1110 1111 1112 1113 1114
	if (AbsoluteTimeIsReal(t1) &&
		AbsoluteTimeIsReal(t2))
		PG_RETURN_RELATIVETIME(t2 - t1);

	PG_RETURN_RELATIVETIME(INVALID_RELTIME);
1115 1116
}

1117

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

	if (time(&sec) < 0)
1129
		PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1130

1131
	PG_RETURN_ABSOLUTETIME((AbsoluteTime) sec);
1132 1133 1134
}

/*
1135
 * reltime comparison routines
1136
 */
1137 1138 1139 1140
static int
reltime_cmp_internal(RelativeTime a, RelativeTime b)
{
	/*
B
Bruce Momjian 已提交
1141 1142 1143
	 * 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.
1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
	 */
	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;
}

1164 1165
Datum
reltimeeq(PG_FUNCTION_ARGS)
1166
{
B
Bruce Momjian 已提交
1167 1168
	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1169

1170
	PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) == 0);
1171 1172
}

1173 1174
Datum
reltimene(PG_FUNCTION_ARGS)
1175
{
B
Bruce Momjian 已提交
1176 1177
	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1178

1179
	PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) != 0);
1180 1181
}

1182 1183
Datum
reltimelt(PG_FUNCTION_ARGS)
1184
{
B
Bruce Momjian 已提交
1185 1186
	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1187

1188
	PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) < 0);
1189 1190
}

1191 1192
Datum
reltimegt(PG_FUNCTION_ARGS)
1193
{
B
Bruce Momjian 已提交
1194 1195
	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1196

1197
	PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) > 0);
1198 1199
}

1200 1201
Datum
reltimele(PG_FUNCTION_ARGS)
1202
{
B
Bruce Momjian 已提交
1203 1204
	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1205

1206
	PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) <= 0);
1207 1208
}

1209 1210
Datum
reltimege(PG_FUNCTION_ARGS)
1211
{
B
Bruce Momjian 已提交
1212 1213
	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1214

1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
	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));
1225 1226 1227 1228
}


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

1238
	if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1239 1240 1241
		PG_RETURN_BOOL(false);

	if (DatumGetBool(DirectFunctionCall2(abstimeeq,
1242 1243
									   AbsoluteTimeGetDatum(i1->data[0]),
								   AbsoluteTimeGetDatum(i2->data[0]))) &&
1244
		DatumGetBool(DirectFunctionCall2(abstimeeq,
1245 1246
									   AbsoluteTimeGetDatum(i1->data[1]),
									 AbsoluteTimeGetDatum(i2->data[1]))))
1247 1248 1249
		PG_RETURN_BOOL(true);
	PG_RETURN_BOOL(false);
}
1250 1251

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

1266
	/*
B
Bruce Momjian 已提交
1267 1268 1269
	 * 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.
1270
	 */
1271 1272 1273 1274 1275 1276
	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;
1277 1278 1279 1280 1281 1282 1283 1284

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

1286 1287
	if (b_invalid)
		return -1;				/* non-INVALID < INVALID */
1288

1289 1290
	a_len = a->data[1] - a->data[0];
	b_len = b->data[1] - b->data[0];
1291

1292 1293 1294 1295 1296 1297
	if (a_len > b_len)
		return 1;
	else if (a_len == b_len)
		return 0;
	else
		return -1;
1298
}
1299

1300
Datum
1301
tintervaleq(PG_FUNCTION_ARGS)
1302
{
B
Bruce Momjian 已提交
1303 1304
	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1305

1306 1307
	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) == 0);
}
1308

1309 1310 1311 1312 1313
Datum
tintervalne(PG_FUNCTION_ARGS)
{
	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1314

1315
	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) != 0);
1316
}
1317

1318 1319
Datum
tintervallt(PG_FUNCTION_ARGS)
1320
{
B
Bruce Momjian 已提交
1321 1322
	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1323

1324
	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) < 0);
1325
}
1326

1327 1328
Datum
tintervalle(PG_FUNCTION_ARGS)
1329
{
B
Bruce Momjian 已提交
1330 1331
	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1332

1333
	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) <= 0);
1334
}
1335

1336 1337
Datum
tintervalgt(PG_FUNCTION_ARGS)
1338
{
B
Bruce Momjian 已提交
1339 1340
	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1341

1342
	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) > 0);
1343
}
1344

1345 1346
Datum
tintervalge(PG_FUNCTION_ARGS)
1347
{
B
Bruce Momjian 已提交
1348 1349
	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1350

1351 1352
	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) >= 0);
}
1353

1354 1355 1356 1357 1358
Datum
bttintervalcmp(PG_FUNCTION_ARGS)
{
	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1359

1360
	PG_RETURN_INT32(tinterval_cmp_internal(i1, i2));
1361
}
1362 1363 1364


/*
1365
 *		tintervalleneq	- returns true iff length of interval i is equal to
1366
 *								reltime t
1367 1368 1369 1370 1371 1372 1373 1374 1375 1376
 *		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
1377
 */
1378 1379
Datum
tintervalleneq(PG_FUNCTION_ARGS)
1380
{
1381 1382
	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1383 1384
	RelativeTime rt;

1385 1386 1387
	if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
		PG_RETURN_BOOL(false);
	rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1388
											   TimeIntervalGetDatum(i)));
1389
	PG_RETURN_BOOL(rt != INVALID_RELTIME && rt == t);
1390 1391
}

1392 1393
Datum
tintervallenne(PG_FUNCTION_ARGS)
1394
{
1395 1396
	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1397 1398
	RelativeTime rt;

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

1406 1407
Datum
tintervallenlt(PG_FUNCTION_ARGS)
1408
{
1409 1410
	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1411 1412
	RelativeTime rt;

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

1420 1421
Datum
tintervallengt(PG_FUNCTION_ARGS)
1422
{
1423 1424
	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1425 1426
	RelativeTime rt;

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

1434 1435
Datum
tintervallenle(PG_FUNCTION_ARGS)
1436
{
1437 1438
	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1439 1440
	RelativeTime rt;

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

1448 1449
Datum
tintervallenge(PG_FUNCTION_ARGS)
1450
{
1451 1452
	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1453 1454
	RelativeTime rt;

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

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

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

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

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

/*
 *		tintervalstart	- returns  the start of interval i
 */
1507 1508
Datum
tintervalstart(PG_FUNCTION_ARGS)
1509
{
B
Bruce Momjian 已提交
1510
	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1511

1512
	if (i->status == T_INTERVAL_INVAL)
1513 1514
		PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
	PG_RETURN_ABSOLUTETIME(i->data[0]);
1515 1516 1517 1518 1519
}

/*
 *		tintervalend		- returns  the end of interval i
 */
1520 1521
Datum
tintervalend(PG_FUNCTION_ARGS)
1522
{
B
Bruce Momjian 已提交
1523
	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1524

1525
	if (i->status == T_INTERVAL_INVAL)
1526 1527
		PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
	PG_RETURN_ABSOLUTETIME(i->data[1]);
1528 1529 1530 1531 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
}


/*****************************************************************************
 *	 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++;
1573
	/* skip leading blanks up to '"' */
1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598
	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 */
1599
	*i_start = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
B
Bruce Momjian 已提交
1600
													CStringGetDatum(p)));
1601
	/* rechange NULL at the end of the first date to a '"' */
1602 1603
	*p1 = '"';
	p = ++p1;
1604
	/* skip blanks up to '"', beginning of second date */
1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626
	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 */
1627
	*i_end = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
B
Bruce Momjian 已提交
1628
													CStringGetDatum(p)));
1629
	/* rechange NULL at the end of the first date to a '"' */
1630 1631 1632 1633 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
	*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
 */
1662 1663
Datum
timeofday(PG_FUNCTION_ARGS)
1664 1665 1666
{
	struct timeval tp;
	struct timezone tpz;
1667 1668
	char		templ[128];
	char		buf[128];
1669
	text	   *result;
1670
	int			len;
1671
	pg_time_t	tt;
1672 1673

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

	len = VARHDRSZ + strlen(buf);
1680
	result = (text *) palloc(len);
J
TOAST  
Jan Wieck 已提交
1681
	VARATT_SIZEP(result) = len;
1682 1683
	memcpy(VARDATA(result), buf, strlen(buf));
	PG_RETURN_TEXT_P(result);
1684
}