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 + -
显示快捷键?