nabstime.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,745 行 · 第 1/3 页

C
1,745
字号
/*------------------------------------------------------------------------- * * nabstime.c *	  Utilities for the built-in type "AbsoluteTime". *	  Functions for the built-in type "RelativeTime". *	  Functions for the built-in type "TimeInterval". * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.117.2.1 2004/05/05 17:28:57 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <ctype.h>#include <time.h>#include <sys/time.h>#include <float.h>#include <limits.h>#include "access/xact.h"#include "libpq/pqformat.h"#include "miscadmin.h"#include "utils/builtins.h"#define MIN_DAYNUM -24856		/* December 13, 1901 */#define MAX_DAYNUM 24854		/* January 18, 2038 */#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)#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))/* * Function prototypes -- internal to this file only */static AbsoluteTime tm2abstime(struct tm * tm, int tz);static void reltime2tm(RelativeTime time, struct tm * tm);static int istinterval(char *i_string,			AbsoluteTime *i_start,			AbsoluteTime *i_end);/* * GetCurrentAbsoluteTime() * * Get the current system time (relative to Unix epoch). */AbsoluteTimeGetCurrentAbsoluteTime(void){	time_t		now;	now = time(NULL);	return (AbsoluteTime) now;}/* * GetCurrentAbsoluteTimeUsec() * * Get the current system time (relative to Unix epoch), including fractional * seconds expressed as microseconds. */AbsoluteTimeGetCurrentAbsoluteTimeUsec(int *usec){	time_t		now;	struct timeval tp;	gettimeofday(&tp, NULL);	now = tp.tv_sec;	*usec = tp.tv_usec;	return (AbsoluteTime) now;}/* * AbsoluteTimeUsecToTimestampTz() * * Convert system time including microseconds to TimestampTz representation. */TimestampTzAbsoluteTimeUsecToTimestampTz(AbsoluteTime sec, int usec){	TimestampTz result;#ifdef HAVE_INT64_TIMESTAMP	result = ((sec - ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * 86400))			  * INT64CONST(1000000)) + usec;#else	result = sec - ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * 86400)		+ (usec / 1000000.0);#endif	return result;}/* * GetCurrentDateTime() * * Get the transaction start time ("now()") broken down as a struct tm. */voidGetCurrentDateTime(struct tm * tm){	int			tz;	abstime2tm(GetCurrentTransactionStartTime(), &tz, tm, NULL);}/* * GetCurrentTimeUsec() * * Get the transaction start time ("now()") broken down as a struct tm, * including fractional seconds and timezone offset. */voidGetCurrentTimeUsec(struct tm * tm, fsec_t *fsec, int *tzp){	int			tz;	int			usec;	abstime2tm(GetCurrentTransactionStartTimeUsec(&usec), &tz, tm, NULL);	/* Note: don't pass NULL tzp to abstime2tm; affects behavior */	if (tzp != NULL)		*tzp = tz;#ifdef HAVE_INT64_TIMESTAMP	*fsec = usec;#else	*fsec = usec / 1000000.0;#endif}voidabstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn){	time_t		time = (time_t) _time;	struct tm  *tx;	/*	 * 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.	 */	if (HasCTZSet && (tzp != NULL))		time -= CTimeZone;	if ((!HasCTZSet) && (tzp != NULL))		tx = localtime(&time);	else		tx = gmtime(&time);	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;#if defined(HAVE_TM_ZONE)	tm->tm_gmtoff = tx->tm_gmtoff;	tm->tm_zone = tx->tm_zone;	if (tzp != NULL)	{		/*		 * We have a brute force time zone per SQL99? Then use it without		 * change since we have already rotated to the time zone.		 */		if (HasCTZSet)		{			*tzp = CTimeZone;			tm->tm_gmtoff = CTimeZone;			tm->tm_isdst = 0;			tm->tm_zone = NULL;			if (tzn != NULL)				*tzn = NULL;		}		else		{			*tzp = -tm->tm_gmtoff;		/* tm_gmtoff is Sun/DEC-ism */			/*			 * XXX FreeBSD man pages indicate that this should work - tgl			 * 97/04/23			 */			if (tzn != NULL)			{				/*				 * Copy no more than MAXTZLEN bytes of timezone to tzn, in				 * case it contains an error message, which doesn't fit in				 * the buffer				 */				StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1);				if (strlen(tm->tm_zone) > MAXTZLEN)					ereport(WARNING,							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),							 errmsg("invalid time zone name: \"%s\"",									tm->tm_zone)));			}		}	}	else		tm->tm_isdst = -1;#elif defined(HAVE_INT_TIMEZONE)	if (tzp != NULL)	{		/*		 * We have a brute force time zone per SQL99? Then use it without		 * change since we have already rotated to the time zone.		 */		if (HasCTZSet)		{			*tzp = CTimeZone;			tm->tm_isdst = 0;			if (tzn != NULL)				*tzn = NULL;		}		else		{			*tzp = ((tm->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);			if (tzn != NULL)			{				/*				 * Copy no more than MAXTZLEN bytes of timezone to tzn, in				 * case it contains an error message, which doesn't fit in				 * the buffer				 */				StrNCpy(*tzn, tzname[tm->tm_isdst], MAXTZLEN + 1);				if (strlen(tzname[tm->tm_isdst]) > MAXTZLEN)					ereport(WARNING,							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),							 errmsg("invalid time zone name: \"%s\"",									tzname[tm->tm_isdst])));			}		}	}	else		tm->tm_isdst = -1;#else							/* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */	if (tzp != NULL)	{		/*		 * We have a brute force time zone per SQL99? Then use it without		 * change since we have already rotated to the time zone.		 */		if (HasCTZSet)		{			*tzp = CTimeZone;			if (tzn != NULL)				*tzn = NULL;		}		else		{			/* default to UTC */			*tzp = 0;			if (tzn != NULL)				*tzn = NULL;		}	}	else		tm->tm_isdst = -1;#endif}/* tm2abstime() * Convert a tm structure to abstime. * Note that tm has full year (not 1900-based) and 1-based month. */static AbsoluteTimetm2abstime(struct tm * tm, int tz){	int			day;	AbsoluteTime sec;	/* 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		|| tm->tm_hour < 0 || tm->tm_hour > 23		|| tm->tm_min < 0 || tm->tm_min > 59		|| tm->tm_sec < 0 || tm->tm_sec > 60)		return INVALID_ABSTIME;	day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;	/* check for time out of range */	if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM))		return INVALID_ABSTIME;	/* convert to seconds */	sec = tm->tm_sec + tz + (tm->tm_min + (day * 24 + tm->tm_hour) * 60) * 60;	/* check for overflow */	if ((day == MAX_DAYNUM && sec < 0) ||		(day == MIN_DAYNUM && sec > 0))		return INVALID_ABSTIME;	/* check for reserved values (e.g. "current" on edge of usual range */	if (!AbsoluteTimeIsReal(sec))		return INVALID_ABSTIME;	return sec;}/* abstimein() * Decode date/time string and return abstime. */Datumabstimein(PG_FUNCTION_ARGS){	char	   *str = PG_GETARG_CSTRING(0);	AbsoluteTime result;	fsec_t		fsec;	int			tz = 0;	struct tm	date,			   *tm = &date;	int			dterr;	char	   *field[MAXDATEFIELDS];	char		lowstr[MAXDATELEN + 1];	int			dtype;	int			nf,				ftype[MAXDATEFIELDS];	if (strlen(str) >= sizeof(lowstr))		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");	switch (dtype)	{		case DTK_DATE:			result = tm2abstime(tm, tz);			break;		case DTK_EPOCH:			/*			 * Don't bother retaining this as a reserved value, but			 * instead just set to the actual epoch time (1970-01-01)			 */			result = 0;			break;		case DTK_LATE:			result = NOEND_ABSTIME;			break;		case DTK_EARLY:			result = NOSTART_ABSTIME;			break;		case DTK_INVALID:			result = INVALID_ABSTIME;			break;		default:			elog(ERROR, "unexpected dtype %d while parsing abstime \"%s\"",				 dtype, str);			result = INVALID_ABSTIME;			break;	};	PG_RETURN_ABSOLUTETIME(result);}/* abstimeout() * Given an AbsoluteTime return the English text version of the date */Datumabstimeout(PG_FUNCTION_ARGS){	AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);	char	   *result;	int			tz;	double		fsec = 0;	struct tm	tt,			   *tm = &tt;	char		buf[MAXDATELEN + 1];	char		zone[MAXDATELEN + 1],			   *tzn = zone;	switch (time)	{			/*			 * Note that timestamp no longer supports 'invalid'. Retain			 * 'invalid' for abstime for now, but dump it someday.			 */		case INVALID_ABSTIME:			strcpy(buf, INVALID);			break;		case NOEND_ABSTIME:			strcpy(buf, LATE);			break;		case NOSTART_ABSTIME:			strcpy(buf, EARLY);			break;		default:			abstime2tm(time, &tz, tm, &tzn);			EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);			break;	}	result = pstrdup(buf);	PG_RETURN_CSTRING(result);}/* *		abstimerecv			- converts external binary format to abstime */Datumabstimerecv(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 */Datumabstimesend(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));}/* abstime_finite() */Datumabstime_finite(PG_FUNCTION_ARGS){	AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);	PG_RETURN_BOOL((abstime != INVALID_ABSTIME) &&				   (abstime != NOSTART_ABSTIME) &&				   (abstime != NOEND_ABSTIME));}/* * abstime comparison routines */static intabstime_cmp_internal(AbsoluteTime a, AbsoluteTime b){	/*	 * 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.	 */	if (a == INVALID_ABSTIME)	{		if (b == INVALID_ABSTIME)			return 0;			/* INVALID = INVALID */		else			return 1;			/* INVALID > non-INVALID */	}	if (b == INVALID_ABSTIME)		return -1;				/* non-INVALID < INVALID */#if 0	/* CURRENT is no longer stored internally... */	/* 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;	else		return -1;}Datumabstimeeq(PG_FUNCTION_ARGS){	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) == 0);}Datumabstimene(PG_FUNCTION_ARGS){	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) != 0);}Datumabstimelt(PG_FUNCTION_ARGS){	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) < 0);}Datumabstimegt(PG_FUNCTION_ARGS){	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) > 0);}Datumabstimele(PG_FUNCTION_ARGS){	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) <= 0);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?