📄 timestamp.c
字号:
/*------------------------------------------------------------------------- * * timestamp.c * Functions for the built-in SQL92 types "timestamp" and "interval". * * 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/timestamp.c,v 1.96.2.1 2004/05/31 18:32:23 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <ctype.h>#include <math.h>#include <errno.h>#include <float.h>#include <limits.h>/* for finite() on Solaris */#ifdef HAVE_IEEEFP_H#include <ieeefp.h>#endif#include "access/hash.h"#include "access/xact.h"#include "catalog/pg_type.h"#include "libpq/pqformat.h"#include "miscadmin.h"#include "utils/array.h"#include "utils/builtins.h"/* * gcc's -ffast-math switch breaks routines that expect exact results from * expressions like timeval / 3600, where timeval is double. */#ifdef __FAST_MATH__#error -ffast-math is known to break this code#endif#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);/***************************************************************************** * 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 tm tt, *tm = &tt; int tz; int dtype; int nf; int dterr; char *field[MAXDATEFIELDS]; int ftype[MAXDATEFIELDS]; char lowstr[MAXDATELEN + 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, "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 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) == 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 HAVE_INT64_TIMESTAMP PG_RETURN_TIMESTAMP((Timestamp) pq_getmsgint64(buf));#else PG_RETURN_TIMESTAMP((Timestamp) pq_getmsgfloat8(buf));#endif}/* * 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 tm tt, *tm = &tt; int tz; int dtype; int nf; int dterr; char *field[MAXDATEFIELDS]; int ftype[MAXDATEFIELDS]; char lowstr[MAXDATELEN + 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, "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 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) == 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 HAVE_INT64_TIMESTAMP PG_RETURN_TIMESTAMPTZ((TimestampTz) pq_getmsgint64(buf));#else PG_RETURN_TIMESTAMPTZ((TimestampTz) pq_getmsgfloat8(buf));#endif}/* * 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 tm tt, *tm = &tt; int dtype; int nf; int dterr; char *field[MAXDATEFIELDS]; int ftype[MAXDATEFIELDS]; char lowstr[MAXDATELEN + MAXDATEFIELDS]; 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; if (strlen(str) >= sizeof(lowstr)) dterr = DTERR_BAD_FORMAT; else dterr = ParseDateTime(str, lowstr, 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"))); AdjustIntervalForTypmod(result, typmod); 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); } 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 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); Interval *interval; interval = (Interval *) palloc(sizeof(Interval));#ifdef HAVE_INT64_TIMESTAMP interval->time = pq_getmsgint64(buf);#else interval->time = pq_getmsgfloat8(buf);#endif interval->month = pq_getmsgint(buf, sizeof(interval->month)); 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -