📄 timestamp.c
字号:
/*------------------------------------------------------------------------- * * timestamp.c * Functions for the built-in SQL92 types "timestamp" and "interval". * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.157.2.1 2005/11/22 18:23:22 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <ctype.h>#include <math.h>#include <float.h>#include <limits.h>#include <sys/time.h>#include "access/hash.h"#include "access/xact.h"#include "catalog/pg_type.h"#include "libpq/pqformat.h"#include "miscadmin.h"#include "parser/scansup.h"#include "utils/array.h"#include "utils/builtins.h"#include "utils/datetime.h"/* * gcc's -ffast-math switch breaks routines that expect exact results from * expressions like timeval / SECS_PER_HOUR, where timeval is double. */#ifdef __FAST_MATH__#error -ffast-math is known to break this code#endif/* Set at postmaster start */TimestampTz PgStartTime;#ifdef HAVE_INT64_TIMESTAMPstatic int64 time2t(const int hour, const int min, const int sec, const fsec_t fsec);#elsestatic double time2t(const int hour, const int min, const int sec, const fsec_t fsec);#endifstatic int EncodeSpecialTimestamp(Timestamp dt, char *str);static Timestamp dt2local(Timestamp dt, int timezone);static void AdjustTimestampForTypmod(Timestamp *time, int32 typmod);static void AdjustIntervalForTypmod(Interval *interval, int32 typmod);static TimestampTz timestamp2timestamptz(Timestamp timestamp);/***************************************************************************** * USER I/O ROUTINES * *****************************************************************************//* timestamp_in() * Convert a string to internal form. */Datumtimestamp_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); Timestamp result; fsec_t fsec; struct pg_tm tt, *tm = &tt; int tz; int dtype; int nf; int dterr; char *field[MAXDATEFIELDS]; int ftype[MAXDATEFIELDS]; char workbuf[MAXDATELEN + MAXDATEFIELDS]; dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field, ftype, MAXDATEFIELDS, &nf); if (dterr == 0) dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz); if (dterr != 0) DateTimeParseError(dterr, str, "timestamp"); switch (dtype) { case DTK_DATE: if (tm2timestamp(tm, fsec, NULL, &result) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range: \"%s\"", str))); break; case DTK_EPOCH: result = SetEpochTimestamp(); break; case DTK_LATE: TIMESTAMP_NOEND(result); break; case DTK_EARLY: TIMESTAMP_NOBEGIN(result); break; case DTK_INVALID: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("date/time value \"%s\" is no longer supported", str))); TIMESTAMP_NOEND(result); break; default: elog(ERROR, "unexpected dtype %d while parsing timestamp \"%s\"", dtype, str); TIMESTAMP_NOEND(result); } AdjustTimestampForTypmod(&result, typmod); PG_RETURN_TIMESTAMP(result);}/* timestamp_out() * Convert a timestamp to external form. */Datumtimestamp_out(PG_FUNCTION_ARGS){ Timestamp timestamp = PG_GETARG_TIMESTAMP(0); char *result; struct pg_tm tt, *tm = &tt; fsec_t fsec; char *tzn = NULL; char buf[MAXDATELEN + 1]; if (TIMESTAMP_NOT_FINITE(timestamp)) EncodeSpecialTimestamp(timestamp, buf); else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) EncodeDateTime(tm, fsec, NULL, &tzn, DateStyle, buf); else ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); result = pstrdup(buf); PG_RETURN_CSTRING(result);}/* * timestamp_recv - converts external binary format to timestamp * * We make no attempt to provide compatibility between int and float * timestamp representations ... */Datumtimestamp_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); Timestamp timestamp; struct pg_tm tt, *tm = &tt; fsec_t fsec;#ifdef HAVE_INT64_TIMESTAMP timestamp = (Timestamp) pq_getmsgint64(buf);#else timestamp = (Timestamp) pq_getmsgfloat8(buf);#endif /* rangecheck: see if timestamp_out would like it */ if (TIMESTAMP_NOT_FINITE(timestamp)) /* ok */ ; else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); AdjustTimestampForTypmod(×tamp, typmod); PG_RETURN_TIMESTAMP(timestamp);}/* * timestamp_send - converts timestamp to binary format */Datumtimestamp_send(PG_FUNCTION_ARGS){ Timestamp timestamp = PG_GETARG_TIMESTAMP(0); StringInfoData buf; pq_begintypsend(&buf);#ifdef HAVE_INT64_TIMESTAMP pq_sendint64(&buf, timestamp);#else pq_sendfloat8(&buf, timestamp);#endif PG_RETURN_BYTEA_P(pq_endtypsend(&buf));}/* timestamp_scale() * Adjust time type for specified scale factor. * Used by PostgreSQL type system to stuff columns. */Datumtimestamp_scale(PG_FUNCTION_ARGS){ Timestamp timestamp = PG_GETARG_TIMESTAMP(0); int32 typmod = PG_GETARG_INT32(1); Timestamp result; result = timestamp; AdjustTimestampForTypmod(&result, typmod); PG_RETURN_TIMESTAMP(result);}static voidAdjustTimestampForTypmod(Timestamp *time, int32 typmod){#ifdef HAVE_INT64_TIMESTAMP static const int64 TimestampScales[MAX_TIMESTAMP_PRECISION + 1] = { INT64CONST(1000000), INT64CONST(100000), INT64CONST(10000), INT64CONST(1000), INT64CONST(100), INT64CONST(10), INT64CONST(1) }; static const int64 TimestampOffsets[MAX_TIMESTAMP_PRECISION + 1] = { INT64CONST(500000), INT64CONST(50000), INT64CONST(5000), INT64CONST(500), INT64CONST(50), INT64CONST(5), INT64CONST(0) };#else static const double TimestampScales[MAX_TIMESTAMP_PRECISION + 1] = { 1, 10, 100, 1000, 10000, 100000, 1000000 };#endif if (!TIMESTAMP_NOT_FINITE(*time) && (typmod != -1) && (typmod != MAX_TIMESTAMP_PRECISION)) { if (typmod < 0 || typmod > MAX_TIMESTAMP_PRECISION) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("timestamp(%d) precision must be between %d and %d", typmod, 0, MAX_TIMESTAMP_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 (*time >= INT64CONST(0)) { *time = ((*time + TimestampOffsets[typmod]) / TimestampScales[typmod]) * TimestampScales[typmod]; } else { *time = -((((-*time) + TimestampOffsets[typmod]) / TimestampScales[typmod]) * TimestampScales[typmod]); }#else *time = rint((double) *time * TimestampScales[typmod]) / TimestampScales[typmod];#endif }}/* timestamptz_in() * Convert a string to internal form. */Datumtimestamptz_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); TimestampTz result; fsec_t fsec; struct pg_tm tt, *tm = &tt; int tz; int dtype; int nf; int dterr; char *field[MAXDATEFIELDS]; int ftype[MAXDATEFIELDS]; char workbuf[MAXDATELEN + MAXDATEFIELDS]; dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field, ftype, MAXDATEFIELDS, &nf); if (dterr == 0) dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz); if (dterr != 0) DateTimeParseError(dterr, str, "timestamp with time zone"); switch (dtype) { case DTK_DATE: if (tm2timestamp(tm, fsec, &tz, &result) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range: \"%s\"", str))); break; case DTK_EPOCH: result = SetEpochTimestamp(); break; case DTK_LATE: TIMESTAMP_NOEND(result); break; case DTK_EARLY: TIMESTAMP_NOBEGIN(result); break; case DTK_INVALID: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("date/time value \"%s\" is no longer supported", str))); TIMESTAMP_NOEND(result); break; default: elog(ERROR, "unexpected dtype %d while parsing timestamptz \"%s\"", dtype, str); TIMESTAMP_NOEND(result); } AdjustTimestampForTypmod(&result, typmod); PG_RETURN_TIMESTAMPTZ(result);}/* timestamptz_out() * Convert a timestamp to external form. */Datumtimestamptz_out(PG_FUNCTION_ARGS){ TimestampTz dt = PG_GETARG_TIMESTAMPTZ(0); char *result; int tz; struct pg_tm tt, *tm = &tt; fsec_t fsec; char *tzn; char buf[MAXDATELEN + 1]; if (TIMESTAMP_NOT_FINITE(dt)) EncodeSpecialTimestamp(dt, buf); else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn, NULL) == 0) EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf); else ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); result = pstrdup(buf); PG_RETURN_CSTRING(result);}/* * timestamptz_recv - converts external binary format to timestamptz * * We make no attempt to provide compatibility between int and float * timestamp representations ... */Datumtimestamptz_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); TimestampTz timestamp; int tz; struct pg_tm tt, *tm = &tt; fsec_t fsec; char *tzn;#ifdef HAVE_INT64_TIMESTAMP timestamp = (TimestampTz) pq_getmsgint64(buf);#else timestamp = (TimestampTz) pq_getmsgfloat8(buf);#endif /* rangecheck: see if timestamptz_out would like it */ if (TIMESTAMP_NOT_FINITE(timestamp)) /* ok */ ; else if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); AdjustTimestampForTypmod(×tamp, typmod); PG_RETURN_TIMESTAMPTZ(timestamp);}/* * timestamptz_send - converts timestamptz to binary format */Datumtimestamptz_send(PG_FUNCTION_ARGS){ TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0); StringInfoData buf; pq_begintypsend(&buf);#ifdef HAVE_INT64_TIMESTAMP pq_sendint64(&buf, timestamp);#else pq_sendfloat8(&buf, timestamp);#endif PG_RETURN_BYTEA_P(pq_endtypsend(&buf));}/* timestamptz_scale() * Adjust time type for specified scale factor. * Used by PostgreSQL type system to stuff columns. */Datumtimestamptz_scale(PG_FUNCTION_ARGS){ TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0); int32 typmod = PG_GETARG_INT32(1); TimestampTz result; 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -