interval.c

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

C
831
字号
#include "postgres_fe.h"#include <time.h>#include <math.h>#ifdef __FAST_MATH__#error -ffast-math is known to break this code#endif#include "extern.h"#include "dt.h"#include "pgtypes_error.h"#include "pgtypes_interval.h"/* TrimTrailingZeros() * ... resulting from printing numbers with full precision. */static voidTrimTrailingZeros(char *str){	int			len = strlen(str);	/* chop off trailing zeros... but leave at least 2 fractional digits */	while ((*(str + len - 1) == '0')		   && (*(str + len - 3) != '.'))	{		len--;		*(str + len) = '\0';	}}/* DecodeTime() * Decode time string which includes delimiters. * Only check the lower limit on hours, since this same code *	can be used to represent time spans. */static intDecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec){	char	   *cp;	*tmask = DTK_TIME_M;	tm->tm_hour = strtol(str, &cp, 10);	if (*cp != ':')		return -1;	str = cp + 1;	tm->tm_min = strtol(str, &cp, 10);	if (*cp == '\0')	{		tm->tm_sec = 0;		*fsec = 0;	}	else if (*cp != ':')		return -1;	else	{		str = cp + 1;		tm->tm_sec = strtol(str, &cp, 10);		if (*cp == '\0')			*fsec = 0;		else if (*cp == '.')		{#ifdef HAVE_INT64_TIMESTAMP			char		fstr[MAXDATELEN + 1];			/*			 * OK, we have at most six digits to work with. Let's			 * construct a string and then do the conversion to an			 * integer.			 */			strncpy(fstr, (cp + 1), 7);			strcpy((fstr + strlen(fstr)), "000000");			*(fstr + 6) = '\0';			*fsec = strtol(fstr, &cp, 10);#else			str = cp;			*fsec = strtod(str, &cp);#endif			if (*cp != '\0')				return -1;		}		else			return -1;	}	/* do a sanity check */#ifdef HAVE_INT64_TIMESTAMP	if ((tm->tm_hour < 0)		|| (tm->tm_min < 0) || (tm->tm_min > 59)		|| (tm->tm_sec < 0) || (tm->tm_sec > 59)		|| (*fsec >= INT64CONST(1000000)))		return -1;#else	if ((tm->tm_hour < 0)		|| (tm->tm_min < 0) || (tm->tm_min > 59)		|| (tm->tm_sec < 0) || (tm->tm_sec > 59)		|| (*fsec >= 1))		return -1;#endif	return 0;}	/* DecodeTime() *//* DecodeInterval() * Interpret previously parsed fields for general time interval. * Return 0 if decoded and -1 if problems. * * Allow "date" field DTK_DATE since this could be just *	an unsigned floating point number. - thomas 1997-11-16 * * Allow ISO-style time span, with implicit units on number of days *	preceding an hh:mm:ss field. - thomas 1998-04-30 */intDecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fsec_t *fsec){	int			is_before = FALSE;	char	   *cp;	int			fmask = 0,				tmask,				type;	int			i;	int			val;	double		fval;	*dtype = DTK_DELTA;	type = IGNORE_DTF;	tm->tm_year = 0;	tm->tm_mon = 0;	tm->tm_mday = 0;	tm->tm_hour = 0;	tm->tm_min = 0;	tm->tm_sec = 0;	*fsec = 0;	/* read through list backwards to pick up units before values */	for (i = nf - 1; i >= 0; i--)	{		switch (ftype[i])		{			case DTK_TIME:				if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)					return -1;				type = DTK_DAY;				break;			case DTK_TZ:				/*				 * Timezone is a token with a leading sign character and				 * otherwise the same as a non-signed time field				 */				/*				 * A single signed number ends up here, but will be				 * rejected by DecodeTime(). So, work this out to drop				 * through to DTK_NUMBER, which *can* tolerate this.				 */				cp = field[i] + 1;				while ((*cp != '\0') && (*cp != ':') && (*cp != '.'))					cp++;				if ((*cp == ':')					&& (DecodeTime((field[i] + 1), fmask, &tmask, tm, fsec) == 0))				{					if (*field[i] == '-')					{						/* flip the sign on all fields */						tm->tm_hour = -tm->tm_hour;						tm->tm_min = -tm->tm_min;						tm->tm_sec = -tm->tm_sec;						*fsec = -(*fsec);					}					/*					 * Set the next type to be a day, if units are not					 * specified. This handles the case of '1 +02:03'					 * since we are reading right to left.					 */					type = DTK_DAY;					tmask = DTK_M(TZ);					break;				}				else if (type == IGNORE_DTF)				{					if (*cp == '.')					{						/*						 * Got a decimal point? Then assume some sort of						 * seconds specification						 */						type = DTK_SECOND;					}					else if (*cp == '\0')					{						/*						 * Only a signed integer? Then must assume a						 * timezone-like usage						 */						type = DTK_HOUR;					}				}				/* DROP THROUGH */			case DTK_DATE:			case DTK_NUMBER:				val = strtol(field[i], &cp, 10);				if (type == IGNORE_DTF)					type = DTK_SECOND;				if (*cp == '.')				{					fval = strtod(cp, &cp);					if (*cp != '\0')						return -1;					if (val < 0)						fval = -(fval);				}				else if (*cp == '\0')					fval = 0;				else					return -1;				tmask = 0;		/* DTK_M(type); */				switch (type)				{					case DTK_MICROSEC:#ifdef HAVE_INT64_TIMESTAMP						*fsec += (val + fval);#else						*fsec += ((val + fval) * 1e-6);#endif						break;					case DTK_MILLISEC:#ifdef HAVE_INT64_TIMESTAMP						*fsec += ((val + fval) * 1000);#else						*fsec += ((val + fval) * 1e-3);#endif						break;					case DTK_SECOND:						tm->tm_sec += val;#ifdef HAVE_INT64_TIMESTAMP						*fsec += (fval * 1000000);#else						*fsec += fval;#endif						tmask = DTK_M(SECOND);						break;					case DTK_MINUTE:						tm->tm_min += val;						if (fval != 0)						{							int			sec;							fval *= 60;							sec = fval;							tm->tm_sec += sec;#ifdef HAVE_INT64_TIMESTAMP							*fsec += ((fval - sec) * 1000000);#else							*fsec += (fval - sec);#endif						}						tmask = DTK_M(MINUTE);						break;					case DTK_HOUR:						tm->tm_hour += val;						if (fval != 0)						{							int			sec;							fval *= 3600;							sec = fval;							tm->tm_sec += sec;#ifdef HAVE_INT64_TIMESTAMP							*fsec += ((fval - sec) * 1000000);#else							*fsec += (fval - sec);#endif						}						tmask = DTK_M(HOUR);						break;					case DTK_DAY:						tm->tm_mday += val;						if (fval != 0)						{							int			sec;							fval *= 86400;							sec = fval;							tm->tm_sec += sec;#ifdef HAVE_INT64_TIMESTAMP							*fsec += ((fval - sec) * 1000000);#else							*fsec += (fval - sec);#endif						}						tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY));						break;					case DTK_WEEK:						tm->tm_mday += val * 7;						if (fval != 0)						{							int			sec;							fval *= (7 * 86400);							sec = fval;							tm->tm_sec += sec;#ifdef HAVE_INT64_TIMESTAMP							*fsec += ((fval - sec) * 1000000);#else							*fsec += (fval - sec);#endif						}						tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY));						break;					case DTK_MONTH:						tm->tm_mon += val;						if (fval != 0)						{							int			sec;							fval *= (30 * 86400);							sec = fval;							tm->tm_sec += sec;#ifdef HAVE_INT64_TIMESTAMP							*fsec += ((fval - sec) * 1000000);#else							*fsec += (fval - sec);#endif						}						tmask = DTK_M(MONTH);						break;					case DTK_YEAR:						tm->tm_year += val;						if (fval != 0)							tm->tm_mon += (fval * 12);						tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));						break;					case DTK_DECADE:						tm->tm_year += val * 10;						if (fval != 0)							tm->tm_mon += (fval * 120);						tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));						break;					case DTK_CENTURY:						tm->tm_year += val * 100;						if (fval != 0)							tm->tm_mon += (fval * 1200);						tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));						break;					case DTK_MILLENNIUM:						tm->tm_year += val * 1000;						if (fval != 0)							tm->tm_mon += (fval * 12000);						tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));						break;					default:						return -1;				}				break;			case DTK_STRING:			case DTK_SPECIAL:				type = DecodeUnits(i, field[i], &val);				if (type == IGNORE_DTF)					continue;				tmask = 0;		/* DTK_M(type); */				switch (type)				{					case UNITS:						type = val;						break;					case AGO:						is_before = TRUE;						type = val;						break;					case RESERV:						tmask = (DTK_DATE_M || DTK_TIME_M);						*dtype = val;						break;					default:						return -1;				}				break;			default:				return -1;		}		if (tmask & fmask)			return -1;		fmask |= tmask;	}

⌨️ 快捷键说明

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