📄 timestamp.c
字号:
result = timestamp; AdjustTimestampForTypmod(&result, typmod); PG_RETURN_TIMESTAMPTZ(result);}/* interval_in() * Convert a string to internal form. * * External format(s): * Uses the generic date/time parsing and decoding routines. */Datuminterval_in(PG_FUNCTION_ARGS){ char *str = PG_GETARG_CSTRING(0);#ifdef NOT_USED Oid typelem = PG_GETARG_OID(1);#endif int32 typmod = PG_GETARG_INT32(2); Interval *result; fsec_t fsec; struct pg_tm tt, *tm = &tt; int dtype; int nf; int dterr; char *field[MAXDATEFIELDS]; int ftype[MAXDATEFIELDS]; char workbuf[256]; 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; dterr = ParseDateTime(str, workbuf, sizeof(workbuf), 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, "interval"); } result = (Interval *) palloc(sizeof(Interval)); switch (dtype) { case DTK_DELTA: if (tm2interval(tm, fsec, result) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); break; case DTK_INVALID: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("date/time value \"%s\" is no longer supported", str))); break; default: elog(ERROR, "unexpected dtype %d while parsing interval \"%s\"", dtype, str); } AdjustIntervalForTypmod(result, typmod); PG_RETURN_INTERVAL_P(result);}/* interval_out() * Convert a time span to external form. */Datuminterval_out(PG_FUNCTION_ARGS){ Interval *span = PG_GETARG_INTERVAL_P(0); char *result; struct pg_tm tt, *tm = &tt; fsec_t fsec; char buf[MAXDATELEN + 1]; if (interval2tm(*span, tm, &fsec) != 0) elog(ERROR, "could not convert interval to tm"); if (EncodeInterval(tm, fsec, DateStyle, buf) != 0) elog(ERROR, "could not format interval"); result = pstrdup(buf); PG_RETURN_CSTRING(result);}/* * interval_recv - converts external binary format to interval */Datuminterval_recv(PG_FUNCTION_ARGS){ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);#ifdef NOT_USED Oid typelem = PG_GETARG_OID(1);#endif int32 typmod = PG_GETARG_INT32(2); Interval *interval; interval = (Interval *) palloc(sizeof(Interval));#ifdef HAVE_INT64_TIMESTAMP interval->time = pq_getmsgint64(buf);#else interval->time = pq_getmsgfloat8(buf);#endif interval->day = pq_getmsgint(buf, sizeof(interval->day)); interval->month = pq_getmsgint(buf, sizeof(interval->month)); AdjustIntervalForTypmod(interval, typmod); PG_RETURN_INTERVAL_P(interval);}/* * interval_send - converts interval to binary format */Datuminterval_send(PG_FUNCTION_ARGS){ Interval *interval = PG_GETARG_INTERVAL_P(0); StringInfoData buf; pq_begintypsend(&buf);#ifdef HAVE_INT64_TIMESTAMP pq_sendint64(&buf, interval->time);#else pq_sendfloat8(&buf, interval->time);#endif pq_sendint(&buf, interval->day, sizeof(interval->day)); pq_sendint(&buf, interval->month, sizeof(interval->month)); PG_RETURN_BYTEA_P(pq_endtypsend(&buf));}Datumintervaltypmodin(PG_FUNCTION_ARGS){ ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0); int32 *tl; int n; int32 typmod; tl = ArrayGetIntegerTypmods(ta, &n); /* * tl[0] - opt_interval tl[1] - Iconst (optional) * * Note we must validate tl[0] even though it's normally guaranteed * correct by the grammar --- consider SELECT 'foo'::"interval"(1000). */ if (n > 0) { switch (tl[0]) { case INTERVAL_MASK(YEAR): case INTERVAL_MASK(MONTH): case INTERVAL_MASK(DAY): case INTERVAL_MASK(HOUR): case INTERVAL_MASK(MINUTE): case INTERVAL_MASK(SECOND): case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH): case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR): case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): case INTERVAL_FULL_RANGE: /* all OK */ break; default: ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid INTERVAL type modifier"))); } } if (n == 1) { if (tl[0] != INTERVAL_FULL_RANGE) typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, tl[0]); else typmod = -1; } else if (n == 2) { if (tl[1] < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("INTERVAL(%d) precision must not be negative", tl[1]))); if (tl[1] > MAX_INTERVAL_PRECISION) { ereport(WARNING, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d", tl[1], MAX_INTERVAL_PRECISION))); typmod = INTERVAL_TYPMOD(MAX_INTERVAL_PRECISION, tl[0]); } else typmod = INTERVAL_TYPMOD(tl[1], tl[0]); } else { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid INTERVAL type modifier"))); typmod = 0; /* keep compiler quiet */ } PG_RETURN_INT32(typmod);}Datumintervaltypmodout(PG_FUNCTION_ARGS){ int32 typmod = PG_GETARG_INT32(0); char *res = (char *) palloc(64); int fields; int precision; const char *fieldstr; if (typmod < 0) { *res = '\0'; PG_RETURN_CSTRING(res); } fields = INTERVAL_RANGE(typmod); precision = INTERVAL_PRECISION(typmod); switch (fields) { case INTERVAL_MASK(YEAR): fieldstr = " year"; break; case INTERVAL_MASK(MONTH): fieldstr = " month"; break; case INTERVAL_MASK(DAY): fieldstr = " day"; break; case INTERVAL_MASK(HOUR): fieldstr = " hour"; break; case INTERVAL_MASK(MINUTE): fieldstr = " minute"; break; case INTERVAL_MASK(SECOND): fieldstr = " second"; break; case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH): fieldstr = " year to month"; break; case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR): fieldstr = " day to hour"; break; case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): fieldstr = " day to minute"; break; case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): fieldstr = " day to second"; break; case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): fieldstr = " hour to minute"; break; case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): fieldstr = " hour to second"; break; case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): fieldstr = " minute to second"; break; case INTERVAL_FULL_RANGE: fieldstr = ""; break; default: elog(ERROR, "invalid INTERVAL typmod: 0x%x", typmod); fieldstr = ""; break; } if (precision != INTERVAL_FULL_PRECISION) snprintf(res, 64, "(%d)%s", precision, fieldstr); else snprintf(res, 64, "%s", fieldstr); PG_RETURN_CSTRING(res);}/* interval_scale() * Adjust interval type for specified fields. * Used by PostgreSQL type system to stuff columns. */Datuminterval_scale(PG_FUNCTION_ARGS){ Interval *interval = PG_GETARG_INTERVAL_P(0); int32 typmod = PG_GETARG_INT32(1); Interval *result; result = palloc(sizeof(Interval)); *result = *interval; AdjustIntervalForTypmod(result, typmod); PG_RETURN_INTERVAL_P(result);}/* * Adjust interval for specified precision, in both YEAR to SECOND * range and sub-second precision. */static voidAdjustIntervalForTypmod(Interval *interval, int32 typmod){#ifdef HAVE_INT64_TIMESTAMP static const int64 IntervalScales[MAX_INTERVAL_PRECISION + 1] = { INT64CONST(1000000), INT64CONST(100000), INT64CONST(10000), INT64CONST(1000), INT64CONST(100), INT64CONST(10), INT64CONST(1) }; static const int64 IntervalOffsets[MAX_INTERVAL_PRECISION + 1] = { INT64CONST(500000), INT64CONST(50000), INT64CONST(5000), INT64CONST(500), INT64CONST(50), INT64CONST(5), INT64CONST(0) };#else static const double IntervalScales[MAX_INTERVAL_PRECISION + 1] = { 1, 10, 100, 1000, 10000, 100000, 1000000 };#endif /* * Unspecified range and precision? Then not necessary to adjust. Setting * typmod to -1 is the convention for all types. */ if (typmod != -1) { int range = INTERVAL_RANGE(typmod); int precision = INTERVAL_PRECISION(typmod); if (range == INTERVAL_FULL_RANGE) { /* Do nothing... */ } else if (range == INTERVAL_MASK(YEAR)) { interval->month = (interval->month / MONTHS_PER_YEAR) * MONTHS_PER_YEAR; interval->day = 0; interval->time = 0; } else if (range == INTERVAL_MASK(MONTH)) { interval->month %= MONTHS_PER_YEAR; interval->day = 0; interval->time = 0; } /* YEAR TO MONTH */ else if (range == (INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH))) { /* month is already year to month */ interval->day = 0; interval->time = 0; } else if (range == INTERVAL_MASK(DAY)) { interval->month = 0; interval->time = 0; } else if (range == INTERVAL_MASK(HOUR)) { interval->month = 0; interval->day = 0;#ifdef HAVE_INT64_TIMESTAMP interval->time = (interval->time / USECS_PER_HOUR) * USECS_PER_HOUR;#else interval->time = ((int) (interval->time / SECS_PER_HOUR)) * (double) SECS_PER_HOUR;#endif } else if (range == INTERVAL_MASK(MINUTE)) {#ifdef HAVE_INT64_TIMESTAMP int64 hour;#else double hour;#endif interval->month = 0; interval->day = 0;#ifdef HAVE_INT64_TIMESTAMP hour = interval->time / USECS_PER_HOUR; interval->time -= hour * USECS_PER_HOUR; interval->time = (interval->time / USECS_PER_MINUTE) * USECS_PER_MINUTE;#else TMODULO(interval->time, hour, (double) SECS_PER_HOUR); interval->time = ((int) (interval->time / SECS_PER_MINUTE)) * (double) SECS_PER_MINUTE;#endif } else if (range == INTERVAL_MASK(SECOND)) {#ifdef HAVE_INT64_TIMESTAMP int64 minute;#else double minute;#endif interval->month = 0; interval->day = 0;#ifdef HAVE_INT64_TIMESTAMP minute = interval->time / USECS_PER_MINUTE; interval->time -= minute * USECS_PER_MINUTE;#else TMODULO(interval->time, minute, (double) SECS_PER_MINUTE); /* return subseconds too */#endif } /* DAY TO HOUR */ else if (range == (INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR))) { interval->month = 0;#ifdef HAVE_INT64_TIMESTAMP interval->time = (interval->time / USECS_PER_HOUR) * USECS_PER_HOUR;#else interval->time = ((int) (interval->time / SECS_PER_HOUR)) * (double) SECS_PER_HOUR;#endif } /* DAY TO MINUTE */ else if (range == (INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) { interval->month = 0;#ifdef HAVE_INT64_TIMESTAMP interval->time = (interval->time / USECS_PER_MINUTE) * USECS_PER_MINUTE;#else interval->time = ((int) (interval->time / SECS_PER_MINUTE)) * (double) SECS_PER_MINUTE;#endif } /* DAY TO SECOND */ else if (range == (INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND))) interval->month = 0; /* HOUR TO MINUTE */ else if (range == (INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) { interval->month = 0; interval->day = 0;#ifdef HAVE_INT64_TIMESTAMP interval->time = (interval->time / USECS_PER_MINUTE) * USECS_PER_MINUTE;#else interval->time = ((int) (interval->time / SECS_PER_MINUTE)) * (double) SECS_PER_MINUTE;#endif } /* HOUR TO SECOND */ else if (range == (INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND))) { interval->month = 0; interval->day = 0; /* return subseconds too */ } /* MINUTE TO SECOND */ else if (range == (INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND))) {#ifdef HAVE_INT64_TIMESTAMP int64 hour;#else double hour;#endif interval->month = 0; interval->day = 0;#ifdef HAVE_INT64_TIMESTAMP hour = interval->time / USECS_PER_HOUR; interval->time -= hour * USECS_PER_HOUR;#else TMODULO(interval->time, hour, (double) SECS_PER_HOUR);#endif } else elog(ERROR, "unrecognized interval typmod: %d", typmod); /* Need to adjust subsecond precision? */ if (precision != INTERVAL_FULL_PRECISION) { if (precision < 0 || precision > MAX_INTERVAL_PRECISION) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("interval(%d) precision must be between %d and %d", precision, 0, MAX_INTERVAL_PRECISION))); /* * Note: this round-to-nearest code is not completely consistent * about rounding values that are exactly halfway between integral * values. On most platforms, rint() will implement * round-to-nearest-even, but the integer code always rounds up * (away from zero). Is it worth trying to be consistent? */#ifdef HAVE_INT64_TIMESTAMP if (interval->time >= INT64CONST(0)) { interval->time = ((interval->time + IntervalOffsets[precision]) / IntervalScales[precision]) * IntervalScales[precision]; } else { interval->time = -(((-interval->time +
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -