Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* timestamp.c
|
2013-04-20 17:04:41 +02:00
|
|
|
* Functions for the built-in SQL types "timestamp" and "interval".
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*
|
2019-01-02 18:44:25 +01:00
|
|
|
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/utils/adt/timestamp.c
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
2000-05-29 03:59:17 +02:00
|
|
|
|
|
|
|
#include "postgres.h"
|
|
|
|
|
1997-04-03 21:58:11 +02:00
|
|
|
#include <ctype.h>
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
#include <math.h>
|
|
|
|
#include <limits.h>
|
2005-06-30 05:48:58 +02:00
|
|
|
#include <sys/time.h>
|
2000-07-13 00:59:15 +02:00
|
|
|
|
2000-05-29 03:59:17 +02:00
|
|
|
#include "access/xact.h"
|
2002-08-26 19:54:02 +02:00
|
|
|
#include "catalog/pg_type.h"
|
Fix integer-overflow problems in interval comparison.
When using integer timestamps, the interval-comparison functions tried
to compute the overall magnitude of an interval as an int64 number of
microseconds. As reported by Frazer McLean, this overflows for intervals
exceeding about 296000 years, which is bad since we nominally allow
intervals many times larger than that. That results in wrong comparison
results, and possibly in corrupted btree indexes for columns containing
such large interval values.
To fix, compute the magnitude as int128 instead. Although some compilers
have native support for int128 calculations, many don't, so create our
own support functions that can do 128-bit addition and multiplication
if the compiler support isn't there. These support functions are designed
with an eye to allowing the int128 code paths in numeric.c to be rewritten
for use on all platforms, although this patch doesn't do that, or even
provide all the int128 primitives that will be needed for it.
Back-patch as far as 9.4. Earlier releases did not guard against overflow
of interval values at all (commit 146604ec4 fixed that), so it seems not
very exciting to worry about overly-large intervals for them.
Before 9.6, we did not assume that unreferenced "static inline" functions
would not draw compiler warnings, so omit functions not directly referenced
by timestamp.c, the only present consumer of int128.h. (We could have
omitted these functions in HEAD too, but since they were written and
debugged on the way to the present patch, and they look likely to be needed
by numeric.c, let's keep them in HEAD.) I did not bother to try to prevent
such warnings in a --disable-integer-datetimes build, though.
Before 9.5, configure will never define HAVE_INT128, so the part of
int128.h that exploits a native int128 implementation is dead code in the
9.4 branch. I didn't bother to remove it, thinking that keeping the file
looking similar in different branches is more useful.
In HEAD only, add a simple test harness for int128.h in src/tools/.
In back branches, this does not change the float-timestamps code path.
That's not subject to the same kind of overflow risk, since it computes
the interval magnitude as float8. (No doubt, when this code was originally
written, overflow was disregarded for exactly that reason.) There is a
precision hazard instead :-(, but we'll avert our eyes from that question,
since no complaints have been reported and that code's deprecated anyway.
Kyotaro Horiguchi and Tom Lane
Discussion: https://postgr.es/m/1490104629.422698.918452336.26FA96B7@webmail.messagingengine.com
2017-04-06 05:51:27 +02:00
|
|
|
#include "common/int128.h"
|
2008-05-05 01:19:24 +02:00
|
|
|
#include "funcapi.h"
|
2003-05-13 01:08:52 +02:00
|
|
|
#include "libpq/pqformat.h"
|
1997-07-01 02:22:46 +02:00
|
|
|
#include "miscadmin.h"
|
2015-03-01 19:22:34 +01:00
|
|
|
#include "nodes/makefuncs.h"
|
2012-02-08 15:33:02 +01:00
|
|
|
#include "nodes/nodeFuncs.h"
|
2019-02-10 00:08:48 +01:00
|
|
|
#include "nodes/supportnodes.h"
|
2004-05-07 02:24:59 +02:00
|
|
|
#include "parser/scansup.h"
|
2000-07-17 05:05:41 +02:00
|
|
|
#include "utils/array.h"
|
1997-03-14 06:58:13 +01:00
|
|
|
#include "utils/builtins.h"
|
2005-06-30 00:51:57 +02:00
|
|
|
#include "utils/datetime.h"
|
2018-07-29 03:30:48 +02:00
|
|
|
#include "utils/float.h"
|
2005-06-30 00:51:57 +02:00
|
|
|
|
2002-09-21 21:52:41 +02:00
|
|
|
/*
|
|
|
|
* gcc's -ffast-math switch breaks routines that expect exact results from
|
2005-07-21 05:56:25 +02:00
|
|
|
* expressions like timeval / SECS_PER_HOUR, where timeval is double.
|
2002-09-21 21:52:41 +02:00
|
|
|
*/
|
|
|
|
#ifdef __FAST_MATH__
|
|
|
|
#error -ffast-math is known to break this code
|
|
|
|
#endif
|
|
|
|
|
2014-05-06 18:12:18 +02:00
|
|
|
#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0))
|
2014-01-30 15:41:43 +01:00
|
|
|
|
2005-06-30 00:51:57 +02:00
|
|
|
/* Set at postmaster start */
|
|
|
|
TimestampTz PgStartTime;
|
2009-06-11 16:49:15 +02:00
|
|
|
|
2008-05-04 23:13:36 +02:00
|
|
|
/* Set at configuration reload */
|
|
|
|
TimestampTz PgReloadTime;
|
2005-06-30 00:51:57 +02:00
|
|
|
|
2008-05-05 01:19:24 +02:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
Timestamp current;
|
|
|
|
Timestamp finish;
|
|
|
|
Interval step;
|
|
|
|
int step_sign;
|
|
|
|
} generate_series_timestamp_fctx;
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
TimestampTz current;
|
|
|
|
TimestampTz finish;
|
2008-05-05 01:19:24 +02:00
|
|
|
Interval step;
|
|
|
|
int step_sign;
|
|
|
|
} generate_series_timestamptz_fctx;
|
|
|
|
|
2005-06-30 00:51:57 +02:00
|
|
|
|
2008-03-21 02:31:43 +01:00
|
|
|
static TimeOffset time2t(const int hour, const int min, const int sec, const fsec_t fsec);
|
2000-06-09 00:38:00 +02:00
|
|
|
static Timestamp dt2local(Timestamp dt, int timezone);
|
2001-10-18 19:30:21 +02:00
|
|
|
static void AdjustIntervalForTypmod(Interval *interval, int32 typmod);
|
2004-03-22 02:38:18 +01:00
|
|
|
static TimestampTz timestamp2timestamptz(Timestamp timestamp);
|
2016-08-17 02:33:01 +02:00
|
|
|
static Timestamp timestamptz2timestamp(TimestampTz timestamp);
|
2001-09-28 10:09:14 +02:00
|
|
|
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2006-12-30 22:21:56 +01:00
|
|
|
/* common code for timestamptypmodin and timestamptztypmodin */
|
|
|
|
static int32
|
|
|
|
anytimestamp_typmodin(bool istz, ArrayType *ta)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
int32 *tl;
|
|
|
|
int n;
|
2006-12-30 22:21:56 +01:00
|
|
|
|
2007-06-15 22:56:52 +02:00
|
|
|
tl = ArrayGetIntegerTypmods(ta, &n);
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* we're not too tense about good error message here because grammar
|
|
|
|
* shouldn't allow wrong number of modifiers for TIMESTAMP
|
|
|
|
*/
|
|
|
|
if (n != 1)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("invalid type modifier")));
|
|
|
|
|
2016-08-17 02:33:01 +02:00
|
|
|
return anytimestamp_typmod_check(istz, tl[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* exported so parse_expr.c can use it */
|
|
|
|
int32
|
|
|
|
anytimestamp_typmod_check(bool istz, int32 typmod)
|
|
|
|
{
|
|
|
|
if (typmod < 0)
|
2006-12-30 22:21:56 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("TIMESTAMP(%d)%s precision must not be negative",
|
2016-08-17 02:33:01 +02:00
|
|
|
typmod, (istz ? " WITH TIME ZONE" : ""))));
|
|
|
|
if (typmod > MAX_TIMESTAMP_PRECISION)
|
2006-12-30 22:21:56 +01:00
|
|
|
{
|
|
|
|
ereport(WARNING,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("TIMESTAMP(%d)%s precision reduced to maximum allowed, %d",
|
|
|
|
typmod, (istz ? " WITH TIME ZONE" : ""),
|
|
|
|
MAX_TIMESTAMP_PRECISION)));
|
2006-12-30 22:21:56 +01:00
|
|
|
typmod = MAX_TIMESTAMP_PRECISION;
|
2007-11-15 22:14:46 +01:00
|
|
|
}
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
return typmod;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* common code for timestamptypmodout and timestamptztypmodout */
|
|
|
|
static char *
|
|
|
|
anytimestamp_typmodout(bool istz, int32 typmod)
|
|
|
|
{
|
|
|
|
const char *tz = istz ? " with time zone" : " without time zone";
|
|
|
|
|
|
|
|
if (typmod >= 0)
|
2014-01-07 03:30:26 +01:00
|
|
|
return psprintf("(%d)%s", (int) typmod, tz);
|
2006-12-30 22:21:56 +01:00
|
|
|
else
|
2014-01-07 03:30:26 +01:00
|
|
|
return psprintf("%s", tz);
|
2006-12-30 22:21:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* USER I/O ROUTINES *
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
/* timestamp_in()
|
|
|
|
* Convert a string to internal form.
|
|
|
|
*/
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
timestamp_in(PG_FUNCTION_ARGS)
|
1997-03-14 06:58:13 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
char *str = PG_GETARG_CSTRING(0);
|
2001-10-25 07:50:21 +02:00
|
|
|
|
2001-10-03 07:29:27 +02:00
|
|
|
#ifdef NOT_USED
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
#endif
|
|
|
|
int32 typmod = PG_GETARG_INT32(2);
|
2000-06-09 03:11:16 +02:00
|
|
|
Timestamp result;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*tm = &tt;
|
|
|
|
int tz;
|
|
|
|
int dtype;
|
|
|
|
int nf;
|
2003-08-28 01:29:29 +02:00
|
|
|
int dterr;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
char *field[MAXDATEFIELDS];
|
|
|
|
int ftype[MAXDATEFIELDS];
|
2005-05-26 04:04:14 +02:00
|
|
|
char workbuf[MAXDATELEN + MAXDATEFIELDS];
|
2002-08-04 08:44:47 +02:00
|
|
|
|
2005-05-26 04:04:14 +02:00
|
|
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
|
|
|
field, ftype, MAXDATEFIELDS, &nf);
|
2003-08-28 01:29:29 +02:00
|
|
|
if (dterr == 0)
|
|
|
|
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
|
|
|
|
if (dterr != 0)
|
|
|
|
DateTimeParseError(dterr, str, "timestamp");
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
switch (dtype)
|
|
|
|
{
|
|
|
|
case DTK_DATE:
|
2001-09-28 10:09:14 +02:00
|
|
|
if (tm2timestamp(tm, fsec, NULL, &result) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range: \"%s\"", str)));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_EPOCH:
|
2001-09-28 10:09:14 +02:00
|
|
|
result = SetEpochTimestamp();
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_LATE:
|
2000-06-09 03:11:16 +02:00
|
|
|
TIMESTAMP_NOEND(result);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_EARLY:
|
2000-06-09 03:11:16 +02:00
|
|
|
TIMESTAMP_NOBEGIN(result);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2003-07-27 06:53:12 +02:00
|
|
|
elog(ERROR, "unexpected dtype %d while parsing timestamp \"%s\"",
|
|
|
|
dtype, str);
|
2001-09-28 10:09:14 +02:00
|
|
|
TIMESTAMP_NOEND(result);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
1997-03-14 06:58:13 +01:00
|
|
|
|
2001-10-03 07:29:27 +02:00
|
|
|
AdjustTimestampForTypmod(&result, typmod);
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
PG_RETURN_TIMESTAMP(result);
|
|
|
|
}
|
1997-03-14 06:58:13 +01:00
|
|
|
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
/* timestamp_out()
|
|
|
|
* Convert a timestamp to external form.
|
|
|
|
*/
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
timestamp_out(PG_FUNCTION_ARGS)
|
1997-03-14 06:58:13 +01:00
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
|
1997-09-08 04:41:22 +02:00
|
|
|
char *result;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
2001-09-28 10:09:14 +02:00
|
|
|
*tm = &tt;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec;
|
2001-09-28 10:09:14 +02:00
|
|
|
char buf[MAXDATELEN + 1];
|
|
|
|
|
2001-10-03 07:29:27 +02:00
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
|
|
|
EncodeSpecialTimestamp(timestamp, buf);
|
2005-06-15 02:34:11 +02:00
|
|
|
else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
|
2012-03-14 22:03:34 +01:00
|
|
|
EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf);
|
2001-09-28 10:09:14 +02:00
|
|
|
else
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
2001-09-28 10:09:14 +02:00
|
|
|
|
|
|
|
result = pstrdup(buf);
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
/*
|
|
|
|
* timestamp_recv - converts external binary format to timestamp
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
timestamp_recv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2005-07-10 23:14:00 +02:00
|
|
|
#ifdef NOT_USED
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
#endif
|
|
|
|
int32 typmod = PG_GETARG_INT32(2);
|
2005-10-15 04:49:52 +02:00
|
|
|
Timestamp timestamp;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
2004-06-03 19:57:09 +02:00
|
|
|
*tm = &tt;
|
|
|
|
fsec_t fsec;
|
2003-05-13 01:08:52 +02:00
|
|
|
|
2004-06-03 19:57:09 +02:00
|
|
|
timestamp = (Timestamp) pq_getmsgint64(buf);
|
|
|
|
|
2016-03-18 14:38:59 +01:00
|
|
|
/* range check: see if timestamp_out would like it */
|
2004-06-03 19:57:09 +02:00
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
2004-08-29 07:07:03 +02:00
|
|
|
/* ok */ ;
|
2016-03-17 00:09:04 +01:00
|
|
|
else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0 ||
|
|
|
|
!IS_VALID_TIMESTAMP(timestamp))
|
2004-06-03 19:57:09 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
2005-07-10 23:14:00 +02:00
|
|
|
AdjustTimestampForTypmod(×tamp, typmod);
|
|
|
|
|
2004-06-03 19:57:09 +02:00
|
|
|
PG_RETURN_TIMESTAMP(timestamp);
|
2003-05-13 01:08:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* timestamp_send - converts timestamp to binary format
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
timestamp_send(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
|
2003-05-13 01:08:52 +02:00
|
|
|
StringInfoData buf;
|
|
|
|
|
|
|
|
pq_begintypsend(&buf);
|
|
|
|
pq_sendint64(&buf, timestamp);
|
|
|
|
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
|
|
|
}
|
|
|
|
|
2006-12-30 22:21:56 +01:00
|
|
|
Datum
|
|
|
|
timestamptypmodin(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
PG_RETURN_INT32(anytimestamp_typmodin(false, ta));
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
timestamptypmodout(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
int32 typmod = PG_GETARG_INT32(0);
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
PG_RETURN_CSTRING(anytimestamp_typmodout(false, typmod));
|
|
|
|
}
|
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
|
2019-02-10 00:08:48 +01:00
|
|
|
/*
|
|
|
|
* timestamp_support()
|
|
|
|
*
|
|
|
|
* Planner support function for the timestamp_scale() and timestamptz_scale()
|
|
|
|
* length coercion functions (we need not distinguish them here).
|
2012-02-08 15:33:02 +01:00
|
|
|
*/
|
|
|
|
Datum
|
2019-02-10 00:08:48 +01:00
|
|
|
timestamp_support(PG_FUNCTION_ARGS)
|
2012-02-08 15:33:02 +01:00
|
|
|
{
|
2019-02-10 00:08:48 +01:00
|
|
|
Node *rawreq = (Node *) PG_GETARG_POINTER(0);
|
|
|
|
Node *ret = NULL;
|
|
|
|
|
|
|
|
if (IsA(rawreq, SupportRequestSimplify))
|
|
|
|
{
|
|
|
|
SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
|
|
|
|
|
|
|
|
ret = TemporalSimplify(MAX_TIMESTAMP_PRECISION, (Node *) req->fcall);
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(ret);
|
2012-02-08 15:33:02 +01:00
|
|
|
}
|
|
|
|
|
2001-10-03 07:29:27 +02:00
|
|
|
/* timestamp_scale()
|
|
|
|
* Adjust time type for specified scale factor.
|
|
|
|
* Used by PostgreSQL type system to stuff columns.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
timestamp_scale(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
|
2001-10-03 07:29:27 +02:00
|
|
|
int32 typmod = PG_GETARG_INT32(1);
|
|
|
|
Timestamp result;
|
|
|
|
|
|
|
|
result = timestamp;
|
|
|
|
|
2001-10-03 17:50:48 +02:00
|
|
|
AdjustTimestampForTypmod(&result, typmod);
|
2001-10-03 07:29:27 +02:00
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMP(result);
|
|
|
|
}
|
|
|
|
|
2016-08-17 02:33:01 +02:00
|
|
|
/*
|
2019-09-25 20:51:47 +02:00
|
|
|
* AdjustTimestampForTypmodError --- round off a timestamp to suit given typmod
|
2016-08-17 02:33:01 +02:00
|
|
|
* Works for either timestamp or timestamptz.
|
|
|
|
*/
|
2019-09-25 20:51:47 +02:00
|
|
|
bool
|
|
|
|
AdjustTimestampForTypmodError(Timestamp *time, int32 typmod, bool *error)
|
2001-10-03 07:29:27 +02:00
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
static const int64 TimestampScales[MAX_TIMESTAMP_PRECISION + 1] = {
|
2002-04-21 21:52:18 +02:00
|
|
|
INT64CONST(1000000),
|
|
|
|
INT64CONST(100000),
|
|
|
|
INT64CONST(10000),
|
|
|
|
INT64CONST(1000),
|
|
|
|
INT64CONST(100),
|
|
|
|
INT64CONST(10),
|
|
|
|
INT64CONST(1)
|
|
|
|
};
|
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
static const int64 TimestampOffsets[MAX_TIMESTAMP_PRECISION + 1] = {
|
2003-01-09 02:06:57 +01:00
|
|
|
INT64CONST(500000),
|
|
|
|
INT64CONST(50000),
|
|
|
|
INT64CONST(5000),
|
|
|
|
INT64CONST(500),
|
|
|
|
INT64CONST(50),
|
|
|
|
INT64CONST(5),
|
2002-04-21 21:52:18 +02:00
|
|
|
INT64CONST(0)
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!TIMESTAMP_NOT_FINITE(*time)
|
|
|
|
&& (typmod != -1) && (typmod != MAX_TIMESTAMP_PRECISION))
|
2001-10-03 07:29:27 +02:00
|
|
|
{
|
2005-05-23 19:13:14 +02:00
|
|
|
if (typmod < 0 || typmod > MAX_TIMESTAMP_PRECISION)
|
2019-09-25 20:51:47 +02:00
|
|
|
{
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
*error = true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("timestamp(%d) precision must be between %d and %d",
|
|
|
|
typmod, 0, MAX_TIMESTAMP_PRECISION)));
|
2019-09-25 20:51:47 +02:00
|
|
|
}
|
2001-10-03 07:29:27 +02:00
|
|
|
|
2002-04-21 21:52:18 +02:00
|
|
|
if (*time >= INT64CONST(0))
|
|
|
|
{
|
2005-05-24 04:09:45 +02:00
|
|
|
*time = ((*time + TimestampOffsets[typmod]) / TimestampScales[typmod]) *
|
2005-10-15 04:49:52 +02:00
|
|
|
TimestampScales[typmod];
|
2002-04-21 21:52:18 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
*time = -((((-*time) + TimestampOffsets[typmod]) / TimestampScales[typmod])
|
|
|
|
* TimestampScales[typmod]);
|
2002-04-21 21:52:18 +02:00
|
|
|
}
|
2001-10-03 07:29:27 +02:00
|
|
|
}
|
2019-09-25 20:51:47 +02:00
|
|
|
|
|
|
|
return true;
|
2001-10-03 07:29:27 +02:00
|
|
|
}
|
|
|
|
|
2019-09-25 20:51:47 +02:00
|
|
|
void
|
|
|
|
AdjustTimestampForTypmod(Timestamp *time, int32 typmod)
|
|
|
|
{
|
|
|
|
(void) AdjustTimestampForTypmodError(time, typmod, NULL);
|
|
|
|
}
|
2001-09-28 10:09:14 +02:00
|
|
|
|
|
|
|
/* timestamptz_in()
|
|
|
|
* Convert a string to internal form.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
timestamptz_in(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *str = PG_GETARG_CSTRING(0);
|
2001-10-25 07:50:21 +02:00
|
|
|
|
2001-10-03 07:29:27 +02:00
|
|
|
#ifdef NOT_USED
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
#endif
|
|
|
|
int32 typmod = PG_GETARG_INT32(2);
|
2001-10-25 07:50:21 +02:00
|
|
|
TimestampTz result;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
2001-09-28 10:09:14 +02:00
|
|
|
*tm = &tt;
|
|
|
|
int tz;
|
|
|
|
int dtype;
|
|
|
|
int nf;
|
2003-08-28 01:29:29 +02:00
|
|
|
int dterr;
|
2001-09-28 10:09:14 +02:00
|
|
|
char *field[MAXDATEFIELDS];
|
|
|
|
int ftype[MAXDATEFIELDS];
|
2005-05-26 04:04:14 +02:00
|
|
|
char workbuf[MAXDATELEN + MAXDATEFIELDS];
|
2002-08-04 08:44:47 +02:00
|
|
|
|
2005-05-26 04:04:14 +02:00
|
|
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
|
|
|
field, ftype, MAXDATEFIELDS, &nf);
|
2003-08-28 01:29:29 +02:00
|
|
|
if (dterr == 0)
|
|
|
|
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
|
|
|
|
if (dterr != 0)
|
|
|
|
DateTimeParseError(dterr, str, "timestamp with time zone");
|
2001-09-28 10:09:14 +02:00
|
|
|
|
|
|
|
switch (dtype)
|
|
|
|
{
|
|
|
|
case DTK_DATE:
|
|
|
|
if (tm2timestamp(tm, fsec, &tz, &result) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range: \"%s\"", str)));
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_EPOCH:
|
|
|
|
result = SetEpochTimestamp();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_LATE:
|
|
|
|
TIMESTAMP_NOEND(result);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_EARLY:
|
|
|
|
TIMESTAMP_NOBEGIN(result);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2003-07-27 06:53:12 +02:00
|
|
|
elog(ERROR, "unexpected dtype %d while parsing timestamptz \"%s\"",
|
|
|
|
dtype, str);
|
2001-09-28 10:09:14 +02:00
|
|
|
TIMESTAMP_NOEND(result);
|
|
|
|
}
|
|
|
|
|
2001-10-03 07:29:27 +02:00
|
|
|
AdjustTimestampForTypmod(&result, typmod);
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
PG_RETURN_TIMESTAMPTZ(result);
|
|
|
|
}
|
|
|
|
|
2014-03-04 19:09:43 +01:00
|
|
|
/*
|
|
|
|
* Try to parse a timezone specification, and return its timezone offset value
|
|
|
|
* if it's acceptable. Otherwise, an error is thrown.
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
*
|
|
|
|
* Note: some code paths update tm->tm_isdst, and some don't; current callers
|
|
|
|
* don't care, so we don't bother being consistent.
|
2014-03-04 19:09:43 +01:00
|
|
|
*/
|
|
|
|
static int
|
2017-06-21 20:39:04 +02:00
|
|
|
parse_sane_timezone(struct pg_tm *tm, text *zone)
|
2014-03-04 19:09:43 +01:00
|
|
|
{
|
|
|
|
char tzname[TZ_STRLEN_MAX + 1];
|
|
|
|
int rt;
|
|
|
|
int tz;
|
|
|
|
|
|
|
|
text_to_cstring_buffer(zone, tzname, sizeof(tzname));
|
|
|
|
|
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Look up the requested timezone. First we try to interpret it as a
|
2014-03-04 19:09:43 +01:00
|
|
|
* numeric timezone specification; if DecodeTimezone decides it doesn't
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
* like the format, we look in the timezone abbreviation table (to handle
|
|
|
|
* cases like "EST"), and if that also fails, we look in the timezone
|
|
|
|
* database (to handle cases like "America/New_York"). (This matches the
|
|
|
|
* order in which timestamp input checks the cases; it's important because
|
|
|
|
* the timezone database unwisely uses a few zone names that are identical
|
|
|
|
* to offset abbreviations.)
|
2014-03-04 19:09:43 +01:00
|
|
|
*
|
|
|
|
* Note pg_tzset happily parses numeric input that DecodeTimezone would
|
2014-05-06 18:12:18 +02:00
|
|
|
* reject. To avoid having it accept input that would otherwise be seen
|
2014-03-04 19:09:43 +01:00
|
|
|
* as invalid, it's enough to disallow having a digit in the first
|
|
|
|
* position of our input string.
|
|
|
|
*/
|
2014-03-06 20:19:00 +01:00
|
|
|
if (isdigit((unsigned char) *tzname))
|
2014-03-04 19:09:43 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2018-07-22 23:58:01 +02:00
|
|
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
|
|
|
"numeric time zone", tzname),
|
2014-03-04 19:09:43 +01:00
|
|
|
errhint("Numeric time zones must have \"-\" or \"+\" as first character.")));
|
|
|
|
|
|
|
|
rt = DecodeTimezone(tzname, &tz);
|
|
|
|
if (rt != 0)
|
|
|
|
{
|
|
|
|
char *lowzone;
|
|
|
|
int type,
|
|
|
|
val;
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
pg_tz *tzp;
|
2014-03-04 19:09:43 +01:00
|
|
|
|
|
|
|
if (rt == DTERR_TZDISP_OVERFLOW)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("numeric time zone \"%s\" out of range", tzname)));
|
2014-03-04 19:09:43 +01:00
|
|
|
else if (rt != DTERR_BAD_FORMAT)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("time zone \"%s\" not recognized", tzname)));
|
|
|
|
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
/* DecodeTimezoneAbbrev requires lowercase input */
|
2014-03-04 19:09:43 +01:00
|
|
|
lowzone = downcase_truncate_identifier(tzname,
|
|
|
|
strlen(tzname),
|
|
|
|
false);
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
|
2014-03-04 19:09:43 +01:00
|
|
|
|
|
|
|
if (type == TZ || type == DTZ)
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
{
|
|
|
|
/* fixed-offset abbreviation */
|
|
|
|
tz = -val;
|
|
|
|
}
|
|
|
|
else if (type == DYNTZ)
|
|
|
|
{
|
|
|
|
/* dynamic-offset abbreviation, resolve using specified time */
|
|
|
|
tz = DetermineTimeZoneAbbrevOffset(tm, tzname, tzp);
|
|
|
|
}
|
2014-03-04 19:09:43 +01:00
|
|
|
else
|
|
|
|
{
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
/* try it as a full zone name */
|
2014-03-04 19:09:43 +01:00
|
|
|
tzp = pg_tzset(tzname);
|
|
|
|
if (tzp)
|
|
|
|
tz = DetermineTimeZoneOffset(tm, tzp);
|
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("time zone \"%s\" not recognized", tzname)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return tz;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* make_timestamp_internal
|
|
|
|
* workhorse for make_timestamp and make_timestamptz
|
|
|
|
*/
|
|
|
|
static Timestamp
|
|
|
|
make_timestamp_internal(int year, int month, int day,
|
|
|
|
int hour, int min, double sec)
|
|
|
|
{
|
|
|
|
struct pg_tm tm;
|
|
|
|
TimeOffset date;
|
|
|
|
TimeOffset time;
|
|
|
|
int dterr;
|
|
|
|
Timestamp result;
|
|
|
|
|
|
|
|
tm.tm_year = year;
|
|
|
|
tm.tm_mon = month;
|
|
|
|
tm.tm_mday = day;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note: we'll reject zero or negative year values. Perhaps negatives
|
|
|
|
* should be allowed to represent BC years?
|
|
|
|
*/
|
|
|
|
dterr = ValidateDate(DTK_DATE_M, false, false, false, &tm);
|
|
|
|
|
|
|
|
if (dterr != 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
|
|
|
|
errmsg("date field value out of range: %d-%02d-%02d",
|
|
|
|
year, month, day)));
|
|
|
|
|
|
|
|
if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("date out of range: %d-%02d-%02d",
|
|
|
|
year, month, day)));
|
|
|
|
|
|
|
|
date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
|
|
|
|
|
2014-03-05 22:42:18 +01:00
|
|
|
/*
|
|
|
|
* This should match the checks in DecodeTimeOnly, except that since we're
|
|
|
|
* dealing with a float "sec" value, we also explicitly reject NaN. (An
|
|
|
|
* infinity input should get rejected by the range comparisons, but we
|
|
|
|
* can't be sure how those will treat a NaN.)
|
|
|
|
*/
|
2014-03-04 19:09:43 +01:00
|
|
|
if (hour < 0 || min < 0 || min > MINS_PER_HOUR - 1 ||
|
2014-03-05 22:42:18 +01:00
|
|
|
isnan(sec) ||
|
2014-03-04 19:09:43 +01:00
|
|
|
sec < 0 || sec > SECS_PER_MINUTE ||
|
|
|
|
hour > HOURS_PER_DAY ||
|
|
|
|
/* test for > 24:00:00 */
|
|
|
|
(hour == HOURS_PER_DAY && (min > 0 || sec > 0)))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
|
|
|
|
errmsg("time field value out of range: %d:%02d:%02g",
|
|
|
|
hour, min, sec)));
|
|
|
|
|
|
|
|
/* This should match tm2time */
|
|
|
|
time = (((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE)
|
|
|
|
* USECS_PER_SEC) + rint(sec * USECS_PER_SEC);
|
|
|
|
|
|
|
|
result = date * USECS_PER_DAY + time;
|
|
|
|
/* check for major overflow */
|
|
|
|
if ((result - time) / USECS_PER_DAY != date)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
|
|
|
|
year, month, day,
|
|
|
|
hour, min, sec)));
|
|
|
|
|
|
|
|
/* check for just-barely overflow (okay except time-of-day wraps) */
|
|
|
|
/* caution: we want to allow 1999-12-31 24:00:00 */
|
|
|
|
if ((result < 0 && date > 0) ||
|
|
|
|
(result > 0 && date < -1))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
|
|
|
|
year, month, day,
|
|
|
|
hour, min, sec)));
|
|
|
|
|
2016-03-17 00:09:04 +01:00
|
|
|
/* final range check catches just-out-of-range timestamps */
|
|
|
|
if (!IS_VALID_TIMESTAMP(result))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
|
|
|
|
year, month, day,
|
|
|
|
hour, min, sec)));
|
|
|
|
|
2014-03-04 19:09:43 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* make_timestamp() - timestamp constructor
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
make_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int32 year = PG_GETARG_INT32(0);
|
|
|
|
int32 month = PG_GETARG_INT32(1);
|
|
|
|
int32 mday = PG_GETARG_INT32(2);
|
|
|
|
int32 hour = PG_GETARG_INT32(3);
|
|
|
|
int32 min = PG_GETARG_INT32(4);
|
|
|
|
float8 sec = PG_GETARG_FLOAT8(5);
|
|
|
|
Timestamp result;
|
|
|
|
|
|
|
|
result = make_timestamp_internal(year, month, mday,
|
|
|
|
hour, min, sec);
|
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMP(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* make_timestamptz() - timestamp with time zone constructor
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
make_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int32 year = PG_GETARG_INT32(0);
|
|
|
|
int32 month = PG_GETARG_INT32(1);
|
|
|
|
int32 mday = PG_GETARG_INT32(2);
|
|
|
|
int32 hour = PG_GETARG_INT32(3);
|
|
|
|
int32 min = PG_GETARG_INT32(4);
|
|
|
|
float8 sec = PG_GETARG_FLOAT8(5);
|
|
|
|
Timestamp result;
|
|
|
|
|
|
|
|
result = make_timestamp_internal(year, month, mday,
|
|
|
|
hour, min, sec);
|
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(result));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Construct a timestamp with time zone.
|
|
|
|
* As above, but the time zone is specified as seventh argument.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
make_timestamptz_at_timezone(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int32 year = PG_GETARG_INT32(0);
|
|
|
|
int32 month = PG_GETARG_INT32(1);
|
|
|
|
int32 mday = PG_GETARG_INT32(2);
|
|
|
|
int32 hour = PG_GETARG_INT32(3);
|
|
|
|
int32 min = PG_GETARG_INT32(4);
|
|
|
|
float8 sec = PG_GETARG_FLOAT8(5);
|
|
|
|
text *zone = PG_GETARG_TEXT_PP(6);
|
2016-03-17 00:09:04 +01:00
|
|
|
TimestampTz result;
|
2014-03-04 19:09:43 +01:00
|
|
|
Timestamp timestamp;
|
|
|
|
struct pg_tm tt;
|
|
|
|
int tz;
|
|
|
|
fsec_t fsec;
|
|
|
|
|
|
|
|
timestamp = make_timestamp_internal(year, month, mday,
|
|
|
|
hour, min, sec);
|
|
|
|
|
|
|
|
if (timestamp2tm(timestamp, NULL, &tt, &fsec, NULL, NULL) != 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
|
|
|
tz = parse_sane_timezone(&tt, zone);
|
|
|
|
|
2016-03-17 00:09:04 +01:00
|
|
|
result = dt2local(timestamp, -tz);
|
|
|
|
|
|
|
|
if (!IS_VALID_TIMESTAMP(result))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMPTZ(result);
|
2014-03-04 19:09:43 +01:00
|
|
|
}
|
|
|
|
|
2016-03-29 23:09:21 +02:00
|
|
|
/*
|
|
|
|
* to_timestamp(double precision)
|
|
|
|
* Convert UNIX epoch to timestamptz.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
float8_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 seconds = PG_GETARG_FLOAT8(0);
|
|
|
|
TimestampTz result;
|
|
|
|
|
|
|
|
/* Deal with NaN and infinite inputs ... */
|
|
|
|
if (isnan(seconds))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp cannot be NaN")));
|
|
|
|
|
|
|
|
if (isinf(seconds))
|
|
|
|
{
|
|
|
|
if (seconds < 0)
|
|
|
|
TIMESTAMP_NOBEGIN(result);
|
|
|
|
else
|
|
|
|
TIMESTAMP_NOEND(result);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Out of range? */
|
|
|
|
if (seconds <
|
2017-02-09 21:49:57 +01:00
|
|
|
(float8) SECS_PER_DAY * (DATETIME_MIN_JULIAN - UNIX_EPOCH_JDATE)
|
|
|
|
|| seconds >=
|
2016-03-29 23:09:21 +02:00
|
|
|
(float8) SECS_PER_DAY * (TIMESTAMP_END_JULIAN - UNIX_EPOCH_JDATE))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range: \"%g\"", seconds)));
|
|
|
|
|
|
|
|
/* Convert UNIX epoch to Postgres epoch */
|
|
|
|
seconds -= ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
|
|
|
|
|
2017-02-09 21:49:57 +01:00
|
|
|
seconds = rint(seconds * USECS_PER_SEC);
|
|
|
|
result = (int64) seconds;
|
2016-03-29 23:09:21 +02:00
|
|
|
|
|
|
|
/* Recheck in case roundoff produces something just out of range */
|
|
|
|
if (!IS_VALID_TIMESTAMP(result))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range: \"%g\"",
|
|
|
|
PG_GETARG_FLOAT8(0))));
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMP(result);
|
|
|
|
}
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
/* timestamptz_out()
|
|
|
|
* Convert a timestamp to external form.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
timestamptz_out(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2003-05-13 01:08:52 +02:00
|
|
|
TimestampTz dt = PG_GETARG_TIMESTAMPTZ(0);
|
2001-09-28 10:09:14 +02:00
|
|
|
char *result;
|
1997-09-08 04:41:22 +02:00
|
|
|
int tz;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
1997-09-08 04:41:22 +02:00
|
|
|
*tm = &tt;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec;
|
2012-03-15 20:17:19 +01:00
|
|
|
const char *tzn;
|
1997-09-08 04:41:22 +02:00
|
|
|
char buf[MAXDATELEN + 1];
|
1997-03-14 06:58:13 +01:00
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
if (TIMESTAMP_NOT_FINITE(dt))
|
2000-06-09 03:11:16 +02:00
|
|
|
EncodeSpecialTimestamp(dt, buf);
|
2005-06-15 02:34:11 +02:00
|
|
|
else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn, NULL) == 0)
|
2012-03-14 22:03:34 +01:00
|
|
|
EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
else
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
result = pstrdup(buf);
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
/*
|
|
|
|
* timestamptz_recv - converts external binary format to timestamptz
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
timestamptz_recv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2005-07-10 23:14:00 +02:00
|
|
|
#ifdef NOT_USED
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
#endif
|
|
|
|
int32 typmod = PG_GETARG_INT32(2);
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz timestamp;
|
2004-06-03 19:57:09 +02:00
|
|
|
int tz;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
2004-06-03 19:57:09 +02:00
|
|
|
*tm = &tt;
|
|
|
|
fsec_t fsec;
|
2003-05-13 01:08:52 +02:00
|
|
|
|
2004-06-03 19:57:09 +02:00
|
|
|
timestamp = (TimestampTz) pq_getmsgint64(buf);
|
|
|
|
|
2016-03-18 14:38:59 +01:00
|
|
|
/* range check: see if timestamptz_out would like it */
|
2004-06-03 19:57:09 +02:00
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
2004-08-29 07:07:03 +02:00
|
|
|
/* ok */ ;
|
2016-03-17 00:09:04 +01:00
|
|
|
else if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0 ||
|
|
|
|
!IS_VALID_TIMESTAMP(timestamp))
|
2004-06-03 19:57:09 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
2005-07-10 23:14:00 +02:00
|
|
|
AdjustTimestampForTypmod(×tamp, typmod);
|
|
|
|
|
2004-06-03 19:57:09 +02:00
|
|
|
PG_RETURN_TIMESTAMPTZ(timestamp);
|
2003-05-13 01:08:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* timestamptz_send - converts timestamptz to binary format
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
timestamptz_send(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
|
2003-05-13 01:08:52 +02:00
|
|
|
StringInfoData buf;
|
|
|
|
|
|
|
|
pq_begintypsend(&buf);
|
|
|
|
pq_sendint64(&buf, timestamp);
|
|
|
|
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
|
|
|
}
|
|
|
|
|
2006-12-30 22:21:56 +01:00
|
|
|
Datum
|
|
|
|
timestamptztypmodin(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
PG_RETURN_INT32(anytimestamp_typmodin(true, ta));
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
timestamptztypmodout(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
int32 typmod = PG_GETARG_INT32(0);
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
PG_RETURN_CSTRING(anytimestamp_typmodout(true, typmod));
|
|
|
|
}
|
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
|
2001-10-03 07:29:27 +02:00
|
|
|
/* timestamptz_scale()
|
|
|
|
* Adjust time type for specified scale factor.
|
|
|
|
* Used by PostgreSQL type system to stuff columns.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
timestamptz_scale(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2003-05-13 01:08:52 +02:00
|
|
|
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
|
2001-10-03 07:29:27 +02:00
|
|
|
int32 typmod = PG_GETARG_INT32(1);
|
2001-10-25 07:50:21 +02:00
|
|
|
TimestampTz result;
|
2001-10-03 07:29:27 +02:00
|
|
|
|
|
|
|
result = timestamp;
|
|
|
|
|
2001-10-03 17:50:48 +02:00
|
|
|
AdjustTimestampForTypmod(&result, typmod);
|
2001-10-03 07:29:27 +02:00
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMPTZ(result);
|
|
|
|
}
|
|
|
|
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
/* interval_in()
|
|
|
|
* Convert a string to internal form.
|
|
|
|
*
|
|
|
|
* External format(s):
|
|
|
|
* Uses the generic date/time parsing and decoding routines.
|
|
|
|
*/
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_in(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
char *str = PG_GETARG_CSTRING(0);
|
2001-10-25 07:50:21 +02:00
|
|
|
|
2001-10-18 19:30:21 +02:00
|
|
|
#ifdef NOT_USED
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
#endif
|
|
|
|
int32 typmod = PG_GETARG_INT32(2);
|
2001-09-28 10:09:14 +02:00
|
|
|
Interval *result;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*tm = &tt;
|
|
|
|
int dtype;
|
|
|
|
int nf;
|
2008-09-10 20:29:41 +02:00
|
|
|
int range;
|
2003-08-28 01:29:29 +02:00
|
|
|
int dterr;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
char *field[MAXDATEFIELDS];
|
|
|
|
int ftype[MAXDATEFIELDS];
|
2005-05-26 04:04:14 +02:00
|
|
|
char workbuf[256];
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2008-09-10 20:29:41 +02:00
|
|
|
if (typmod >= 0)
|
|
|
|
range = INTERVAL_RANGE(typmod);
|
|
|
|
else
|
|
|
|
range = INTERVAL_FULL_RANGE;
|
|
|
|
|
2005-05-26 04:04:14 +02:00
|
|
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field,
|
|
|
|
ftype, MAXDATEFIELDS, &nf);
|
2003-08-28 01:29:29 +02:00
|
|
|
if (dterr == 0)
|
2008-11-11 03:42:33 +01:00
|
|
|
dterr = DecodeInterval(field, ftype, nf, range,
|
|
|
|
&dtype, tm, &fsec);
|
|
|
|
|
|
|
|
/* if those functions think it's a bad format, try ISO8601 style */
|
|
|
|
if (dterr == DTERR_BAD_FORMAT)
|
2009-06-11 16:49:15 +02:00
|
|
|
dterr = DecodeISO8601Interval(str,
|
2008-11-11 03:42:33 +01:00
|
|
|
&dtype, tm, &fsec);
|
|
|
|
|
2003-08-28 01:29:29 +02:00
|
|
|
if (dterr != 0)
|
|
|
|
{
|
|
|
|
if (dterr == DTERR_FIELD_OVERFLOW)
|
|
|
|
dterr = DTERR_INTERVAL_OVERFLOW;
|
|
|
|
DateTimeParseError(dterr, str, "interval");
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
result = (Interval *) palloc(sizeof(Interval));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
switch (dtype)
|
|
|
|
{
|
|
|
|
case DTK_DELTA:
|
2001-09-28 10:09:14 +02:00
|
|
|
if (tm2interval(tm, fsec, result) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
1997-10-09 07:02:17 +02:00
|
|
|
default:
|
2003-07-27 06:53:12 +02:00
|
|
|
elog(ERROR, "unexpected dtype %d while parsing interval \"%s\"",
|
|
|
|
dtype, str);
|
1997-10-09 07:02:17 +02:00
|
|
|
}
|
1998-02-26 05:46:47 +01:00
|
|
|
|
2005-07-10 23:14:00 +02:00
|
|
|
AdjustIntervalForTypmod(result, typmod);
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
PG_RETURN_INTERVAL_P(result);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
/* interval_out()
|
|
|
|
* Convert a time span to external form.
|
|
|
|
*/
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_out(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Interval *span = PG_GETARG_INTERVAL_P(0);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
char *result;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*tm = &tt;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
char buf[MAXDATELEN + 1];
|
|
|
|
|
|
|
|
if (interval2tm(*span, tm, &fsec) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
elog(ERROR, "could not convert interval to tm");
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2009-05-26 04:17:50 +02:00
|
|
|
EncodeInterval(tm, fsec, IntervalStyle, buf);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
result = pstrdup(buf);
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
/*
|
|
|
|
* interval_recv - converts external binary format to interval
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
interval_recv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2005-07-10 23:14:00 +02:00
|
|
|
#ifdef NOT_USED
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
#endif
|
|
|
|
int32 typmod = PG_GETARG_INT32(2);
|
2003-05-13 01:08:52 +02:00
|
|
|
Interval *interval;
|
|
|
|
|
|
|
|
interval = (Interval *) palloc(sizeof(Interval));
|
|
|
|
|
2005-05-23 19:13:14 +02:00
|
|
|
interval->time = pq_getmsgint64(buf);
|
2005-07-20 18:42:32 +02:00
|
|
|
interval->day = pq_getmsgint(buf, sizeof(interval->day));
|
2005-05-23 19:13:14 +02:00
|
|
|
interval->month = pq_getmsgint(buf, sizeof(interval->month));
|
2003-05-13 01:08:52 +02:00
|
|
|
|
2005-07-10 23:14:00 +02:00
|
|
|
AdjustIntervalForTypmod(interval, typmod);
|
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
PG_RETURN_INTERVAL_P(interval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* interval_send - converts interval to binary format
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
interval_send(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Interval *interval = PG_GETARG_INTERVAL_P(0);
|
|
|
|
StringInfoData buf;
|
|
|
|
|
|
|
|
pq_begintypsend(&buf);
|
|
|
|
pq_sendint64(&buf, interval->time);
|
2017-10-12 06:00:46 +02:00
|
|
|
pq_sendint32(&buf, interval->day);
|
|
|
|
pq_sendint32(&buf, interval->month);
|
2003-05-13 01:08:52 +02:00
|
|
|
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
|
|
|
}
|
|
|
|
|
2012-02-08 15:33:02 +01:00
|
|
|
/*
|
|
|
|
* The interval typmod stores a "range" in its high 16 bits and a "precision"
|
2014-05-06 18:12:18 +02:00
|
|
|
* in its low 16 bits. Both contribute to defining the resolution of the
|
2012-02-08 15:33:02 +01:00
|
|
|
* type. Range addresses resolution granules larger than one second, and
|
|
|
|
* precision specifies resolution below one second. This representation can
|
|
|
|
* express all SQL standard resolutions, but we implement them all in terms of
|
|
|
|
* truncating rightward from some position. Range is a bitmap of permitted
|
|
|
|
* fields, but only the temporally-smallest such field is significant to our
|
|
|
|
* calculations. Precision is a count of sub-second decimal places to retain.
|
|
|
|
* Setting all bits (INTERVAL_FULL_PRECISION) gives the same truncation
|
|
|
|
* semantics as choosing MAX_INTERVAL_PRECISION.
|
|
|
|
*/
|
2006-12-30 22:21:56 +01:00
|
|
|
Datum
|
|
|
|
intervaltypmodin(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
int32 *tl;
|
|
|
|
int n;
|
2006-12-30 22:21:56 +01:00
|
|
|
int32 typmod;
|
|
|
|
|
2007-06-15 22:56:52 +02:00
|
|
|
tl = ArrayGetIntegerTypmods(ta, &n);
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* tl[0] - interval range (fields bitmask) tl[1] - precision (optional)
|
2006-12-30 22:21:56 +01:00
|
|
|
*
|
|
|
|
* 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",
|
2007-11-15 22:14:46 +01:00
|
|
|
tl[1])));
|
2006-12-30 22:21:56 +01:00
|
|
|
if (tl[1] > MAX_INTERVAL_PRECISION)
|
|
|
|
{
|
|
|
|
ereport(WARNING,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d",
|
|
|
|
tl[1], MAX_INTERVAL_PRECISION)));
|
2006-12-30 22:21:56 +01:00
|
|
|
typmod = INTERVAL_TYPMOD(MAX_INTERVAL_PRECISION, tl[0]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
typmod = INTERVAL_TYPMOD(tl[1], tl[0]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2007-11-15 22:14:46 +01:00
|
|
|
errmsg("invalid INTERVAL type modifier")));
|
2006-12-30 22:21:56 +01:00
|
|
|
typmod = 0; /* keep compiler quiet */
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_INT32(typmod);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
intervaltypmodout(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
int32 typmod = PG_GETARG_INT32(0);
|
2006-12-30 22:21:56 +01:00
|
|
|
char *res = (char *) palloc(64);
|
2007-11-15 22:14:46 +01:00
|
|
|
int fields;
|
|
|
|
int precision;
|
2006-12-30 22:21:56 +01:00
|
|
|
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)
|
2008-09-11 17:27:30 +02:00
|
|
|
snprintf(res, 64, "%s(%d)", fieldstr, precision);
|
2006-12-30 22:21:56 +01:00
|
|
|
else
|
|
|
|
snprintf(res, 64, "%s", fieldstr);
|
|
|
|
|
|
|
|
PG_RETURN_CSTRING(res);
|
|
|
|
}
|
|
|
|
|
2016-12-27 21:43:54 +01:00
|
|
|
/*
|
|
|
|
* Given an interval typmod value, return a code for the least-significant
|
|
|
|
* field that the typmod allows to be nonzero, for instance given
|
|
|
|
* INTERVAL DAY TO HOUR we want to identify "hour".
|
|
|
|
*
|
|
|
|
* The results should be ordered by field significance, which means
|
|
|
|
* we can't use the dt.h macros YEAR etc, because for some odd reason
|
|
|
|
* they aren't ordered that way. Instead, arbitrarily represent
|
|
|
|
* SECOND = 0, MINUTE = 1, HOUR = 2, DAY = 3, MONTH = 4, YEAR = 5.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
intervaltypmodleastfield(int32 typmod)
|
|
|
|
{
|
|
|
|
if (typmod < 0)
|
|
|
|
return 0; /* SECOND */
|
|
|
|
|
|
|
|
switch (INTERVAL_RANGE(typmod))
|
|
|
|
{
|
|
|
|
case INTERVAL_MASK(YEAR):
|
|
|
|
return 5; /* YEAR */
|
|
|
|
case INTERVAL_MASK(MONTH):
|
|
|
|
return 4; /* MONTH */
|
|
|
|
case INTERVAL_MASK(DAY):
|
|
|
|
return 3; /* DAY */
|
|
|
|
case INTERVAL_MASK(HOUR):
|
|
|
|
return 2; /* HOUR */
|
|
|
|
case INTERVAL_MASK(MINUTE):
|
|
|
|
return 1; /* MINUTE */
|
|
|
|
case INTERVAL_MASK(SECOND):
|
|
|
|
return 0; /* SECOND */
|
|
|
|
case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
|
|
|
|
return 4; /* MONTH */
|
|
|
|
case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
|
|
|
|
return 2; /* HOUR */
|
|
|
|
case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
|
|
|
|
return 1; /* MINUTE */
|
|
|
|
case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
|
|
|
|
return 0; /* SECOND */
|
|
|
|
case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
|
|
|
|
return 1; /* MINUTE */
|
|
|
|
case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
|
|
|
|
return 0; /* SECOND */
|
|
|
|
case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
|
|
|
|
return 0; /* SECOND */
|
|
|
|
case INTERVAL_FULL_RANGE:
|
|
|
|
return 0; /* SECOND */
|
|
|
|
default:
|
|
|
|
elog(ERROR, "invalid INTERVAL typmod: 0x%x", typmod);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0; /* can't get here, but keep compiler quiet */
|
|
|
|
}
|
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
|
2019-02-10 00:08:48 +01:00
|
|
|
/*
|
|
|
|
* interval_support()
|
|
|
|
*
|
|
|
|
* Planner support function for interval_scale().
|
|
|
|
*
|
2012-02-08 15:33:02 +01:00
|
|
|
* Flatten superfluous calls to interval_scale(). The interval typmod is
|
|
|
|
* complex to permit accepting and regurgitating all SQL standard variations.
|
|
|
|
* For truncation purposes, it boils down to a single, simple granularity.
|
|
|
|
*/
|
|
|
|
Datum
|
2019-02-10 00:08:48 +01:00
|
|
|
interval_support(PG_FUNCTION_ARGS)
|
2012-02-08 15:33:02 +01:00
|
|
|
{
|
2019-02-10 00:08:48 +01:00
|
|
|
Node *rawreq = (Node *) PG_GETARG_POINTER(0);
|
2012-02-08 15:33:02 +01:00
|
|
|
Node *ret = NULL;
|
|
|
|
|
2019-02-10 00:08:48 +01:00
|
|
|
if (IsA(rawreq, SupportRequestSimplify))
|
|
|
|
{
|
|
|
|
SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
|
|
|
|
FuncExpr *expr = req->fcall;
|
|
|
|
Node *typmod;
|
2012-02-08 15:33:02 +01:00
|
|
|
|
2019-02-10 00:08:48 +01:00
|
|
|
Assert(list_length(expr->args) >= 2);
|
2012-02-08 15:33:02 +01:00
|
|
|
|
2019-02-10 00:08:48 +01:00
|
|
|
typmod = (Node *) lsecond(expr->args);
|
2016-12-27 21:43:54 +01:00
|
|
|
|
2019-02-10 00:08:48 +01:00
|
|
|
if (IsA(typmod, Const) &&!((Const *) typmod)->constisnull)
|
2012-02-08 15:33:02 +01:00
|
|
|
{
|
2019-02-10 00:08:48 +01:00
|
|
|
Node *source = (Node *) linitial(expr->args);
|
|
|
|
int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
|
|
|
|
bool noop;
|
|
|
|
|
|
|
|
if (new_typmod < 0)
|
|
|
|
noop = true;
|
2016-12-27 21:43:54 +01:00
|
|
|
else
|
2019-02-10 00:08:48 +01:00
|
|
|
{
|
|
|
|
int32 old_typmod = exprTypmod(source);
|
|
|
|
int old_least_field;
|
|
|
|
int new_least_field;
|
|
|
|
int old_precis;
|
|
|
|
int new_precis;
|
|
|
|
|
|
|
|
old_least_field = intervaltypmodleastfield(old_typmod);
|
|
|
|
new_least_field = intervaltypmodleastfield(new_typmod);
|
|
|
|
if (old_typmod < 0)
|
|
|
|
old_precis = INTERVAL_FULL_PRECISION;
|
|
|
|
else
|
|
|
|
old_precis = INTERVAL_PRECISION(old_typmod);
|
|
|
|
new_precis = INTERVAL_PRECISION(new_typmod);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Cast is a no-op if least field stays the same or decreases
|
|
|
|
* while precision stays the same or increases. But
|
|
|
|
* precision, which is to say, sub-second precision, only
|
|
|
|
* affects ranges that include SECOND.
|
|
|
|
*/
|
|
|
|
noop = (new_least_field <= old_least_field) &&
|
|
|
|
(old_least_field > 0 /* SECOND */ ||
|
|
|
|
new_precis >= MAX_INTERVAL_PRECISION ||
|
|
|
|
new_precis >= old_precis);
|
|
|
|
}
|
|
|
|
if (noop)
|
|
|
|
ret = relabel_to_typmod(source, new_typmod);
|
2012-02-08 15:33:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(ret);
|
|
|
|
}
|
|
|
|
|
2001-10-18 19:30:21 +02:00
|
|
|
/* interval_scale()
|
|
|
|
* Adjust interval type for specified fields.
|
|
|
|
* Used by PostgreSQL type system to stuff columns.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
interval_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);
|
|
|
|
}
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2005-07-12 18:05:12 +02:00
|
|
|
/*
|
|
|
|
* Adjust interval for specified precision, in both YEAR to SECOND
|
|
|
|
* range and sub-second precision.
|
|
|
|
*/
|
2001-10-18 19:30:21 +02:00
|
|
|
static void
|
|
|
|
AdjustIntervalForTypmod(Interval *interval, int32 typmod)
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
static const int64 IntervalScales[MAX_INTERVAL_PRECISION + 1] = {
|
2002-04-21 21:52:18 +02:00
|
|
|
INT64CONST(1000000),
|
|
|
|
INT64CONST(100000),
|
|
|
|
INT64CONST(10000),
|
|
|
|
INT64CONST(1000),
|
|
|
|
INT64CONST(100),
|
|
|
|
INT64CONST(10),
|
|
|
|
INT64CONST(1)
|
|
|
|
};
|
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
static const int64 IntervalOffsets[MAX_INTERVAL_PRECISION + 1] = {
|
2003-01-09 02:06:57 +01:00
|
|
|
INT64CONST(500000),
|
|
|
|
INT64CONST(50000),
|
|
|
|
INT64CONST(5000),
|
|
|
|
INT64CONST(500),
|
|
|
|
INT64CONST(50),
|
|
|
|
INT64CONST(5),
|
2002-04-21 21:52:18 +02:00
|
|
|
INT64CONST(0)
|
|
|
|
};
|
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Unspecified range and precision? Then not necessary to adjust. Setting
|
2009-06-02 01:55:15 +02:00
|
|
|
* typmod to -1 is the convention for all data types.
|
2002-08-04 08:44:47 +02:00
|
|
|
*/
|
2008-09-10 20:29:41 +02:00
|
|
|
if (typmod >= 0)
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
2002-08-04 08:44:47 +02:00
|
|
|
int range = INTERVAL_RANGE(typmod);
|
|
|
|
int precision = INTERVAL_PRECISION(typmod);
|
2001-10-18 19:30:21 +02:00
|
|
|
|
2009-06-02 01:55:15 +02:00
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* Our interpretation of intervals with a limited set of fields is
|
|
|
|
* that fields to the right of the last one specified are zeroed out,
|
|
|
|
* but those to the left of it remain valid. Thus for example there
|
|
|
|
* is no operational difference between INTERVAL YEAR TO MONTH and
|
2014-05-06 18:12:18 +02:00
|
|
|
* INTERVAL MONTH. In some cases we could meaningfully enforce that
|
2009-06-11 16:49:15 +02:00
|
|
|
* higher-order fields are zero; for example INTERVAL DAY could reject
|
|
|
|
* nonzero "month" field. However that seems a bit pointless when we
|
|
|
|
* can't do it consistently. (We cannot enforce a range limit on the
|
|
|
|
* highest expected field, since we do not have any equivalent of
|
2012-02-09 18:22:21 +01:00
|
|
|
* SQL's <interval leading field precision>.) If we ever decide to
|
2019-02-10 00:08:48 +01:00
|
|
|
* revisit this, interval_support will likely require adjusting.
|
2009-06-02 01:55:15 +02:00
|
|
|
*
|
|
|
|
* Note: before PG 8.4 we interpreted a limited set of fields as
|
|
|
|
* actually causing a "modulo" operation on a given value, potentially
|
2014-05-06 18:12:18 +02:00
|
|
|
* losing high-order as well as low-order information. But there is
|
2009-06-02 01:55:15 +02:00
|
|
|
* no support for such behavior in the standard, and it seems fairly
|
2014-05-06 18:12:18 +02:00
|
|
|
* undesirable on data consistency grounds anyway. Now we only
|
2009-06-02 01:55:15 +02:00
|
|
|
* perform truncation or rounding of low-order fields.
|
|
|
|
*/
|
2002-08-04 08:44:47 +02:00
|
|
|
if (range == INTERVAL_FULL_RANGE)
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
|
|
|
/* Do nothing... */
|
|
|
|
}
|
2002-08-04 08:44:47 +02:00
|
|
|
else if (range == INTERVAL_MASK(YEAR))
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
2005-07-21 05:56:25 +02:00
|
|
|
interval->month = (interval->month / MONTHS_PER_YEAR) * MONTHS_PER_YEAR;
|
2005-07-20 18:42:32 +02:00
|
|
|
interval->day = 0;
|
2005-05-23 19:13:14 +02:00
|
|
|
interval->time = 0;
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
2002-08-04 08:44:47 +02:00
|
|
|
else if (range == INTERVAL_MASK(MONTH))
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
2005-07-20 18:42:32 +02:00
|
|
|
interval->day = 0;
|
2005-05-23 19:13:14 +02:00
|
|
|
interval->time = 0;
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
|
|
|
/* YEAR TO MONTH */
|
2002-08-04 08:44:47 +02:00
|
|
|
else if (range == (INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH)))
|
2005-07-20 18:42:32 +02:00
|
|
|
{
|
|
|
|
interval->day = 0;
|
2005-05-23 19:13:14 +02:00
|
|
|
interval->time = 0;
|
2005-07-20 18:42:32 +02:00
|
|
|
}
|
2002-08-04 08:44:47 +02:00
|
|
|
else if (range == INTERVAL_MASK(DAY))
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
2005-07-20 18:42:32 +02:00
|
|
|
interval->time = 0;
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
2002-08-04 08:44:47 +02:00
|
|
|
else if (range == INTERVAL_MASK(HOUR))
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
2005-05-23 20:56:55 +02:00
|
|
|
interval->time = (interval->time / USECS_PER_HOUR) *
|
2005-10-15 04:49:52 +02:00
|
|
|
USECS_PER_HOUR;
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
2002-08-04 08:44:47 +02:00
|
|
|
else if (range == INTERVAL_MASK(MINUTE))
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
2005-05-23 20:56:55 +02:00
|
|
|
interval->time = (interval->time / USECS_PER_MINUTE) *
|
2005-10-15 04:49:52 +02:00
|
|
|
USECS_PER_MINUTE;
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
2002-08-04 08:44:47 +02:00
|
|
|
else if (range == INTERVAL_MASK(SECOND))
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
2009-06-02 01:55:15 +02:00
|
|
|
/* fractional-second rounding will be dealt with below */
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
|
|
|
/* DAY TO HOUR */
|
2002-08-04 08:44:47 +02:00
|
|
|
else if (range == (INTERVAL_MASK(DAY) |
|
|
|
|
INTERVAL_MASK(HOUR)))
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
2005-05-23 20:56:55 +02:00
|
|
|
interval->time = (interval->time / USECS_PER_HOUR) *
|
2005-10-15 04:49:52 +02:00
|
|
|
USECS_PER_HOUR;
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
|
|
|
/* DAY TO MINUTE */
|
2002-08-04 08:44:47 +02:00
|
|
|
else if (range == (INTERVAL_MASK(DAY) |
|
|
|
|
INTERVAL_MASK(HOUR) |
|
|
|
|
INTERVAL_MASK(MINUTE)))
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
2005-05-23 20:56:55 +02:00
|
|
|
interval->time = (interval->time / USECS_PER_MINUTE) *
|
2005-10-15 04:49:52 +02:00
|
|
|
USECS_PER_MINUTE;
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
|
|
|
/* DAY TO SECOND */
|
2002-08-04 08:44:47 +02:00
|
|
|
else if (range == (INTERVAL_MASK(DAY) |
|
|
|
|
INTERVAL_MASK(HOUR) |
|
|
|
|
INTERVAL_MASK(MINUTE) |
|
|
|
|
INTERVAL_MASK(SECOND)))
|
2009-06-02 01:55:15 +02:00
|
|
|
{
|
|
|
|
/* fractional-second rounding will be dealt with below */
|
|
|
|
}
|
2001-10-18 19:30:21 +02:00
|
|
|
/* HOUR TO MINUTE */
|
2002-08-04 08:44:47 +02:00
|
|
|
else if (range == (INTERVAL_MASK(HOUR) |
|
|
|
|
INTERVAL_MASK(MINUTE)))
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
2005-05-23 20:56:55 +02:00
|
|
|
interval->time = (interval->time / USECS_PER_MINUTE) *
|
2005-10-15 04:49:52 +02:00
|
|
|
USECS_PER_MINUTE;
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
|
|
|
/* HOUR TO SECOND */
|
2002-08-04 08:44:47 +02:00
|
|
|
else if (range == (INTERVAL_MASK(HOUR) |
|
|
|
|
INTERVAL_MASK(MINUTE) |
|
|
|
|
INTERVAL_MASK(SECOND)))
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
2009-06-02 01:55:15 +02:00
|
|
|
/* fractional-second rounding will be dealt with below */
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
|
|
|
/* MINUTE TO SECOND */
|
2002-08-04 08:44:47 +02:00
|
|
|
else if (range == (INTERVAL_MASK(MINUTE) |
|
|
|
|
INTERVAL_MASK(SECOND)))
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
2009-06-02 01:55:15 +02:00
|
|
|
/* fractional-second rounding will be dealt with below */
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
|
|
|
else
|
2003-07-27 06:53:12 +02:00
|
|
|
elog(ERROR, "unrecognized interval typmod: %d", typmod);
|
2001-10-18 19:30:21 +02:00
|
|
|
|
2016-03-18 14:38:59 +01:00
|
|
|
/* Need to adjust sub-second precision? */
|
2002-08-04 08:44:47 +02:00
|
|
|
if (precision != INTERVAL_FULL_PRECISION)
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
2005-05-23 19:13:14 +02:00
|
|
|
if (precision < 0 || precision > MAX_INTERVAL_PRECISION)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("interval(%d) precision must be between %d and %d",
|
|
|
|
precision, 0, MAX_INTERVAL_PRECISION)));
|
2001-10-18 19:30:21 +02:00
|
|
|
|
2002-04-21 21:52:18 +02:00
|
|
|
if (interval->time >= INT64CONST(0))
|
|
|
|
{
|
2005-05-24 04:09:45 +02:00
|
|
|
interval->time = ((interval->time +
|
2005-10-15 04:49:52 +02:00
|
|
|
IntervalOffsets[precision]) /
|
|
|
|
IntervalScales[precision]) *
|
|
|
|
IntervalScales[precision];
|
2002-04-21 21:52:18 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-05-23 19:13:14 +02:00
|
|
|
interval->time = -(((-interval->time +
|
2005-10-15 04:49:52 +02:00
|
|
|
IntervalOffsets[precision]) /
|
2005-05-23 19:13:14 +02:00
|
|
|
IntervalScales[precision]) *
|
2005-10-15 04:49:52 +02:00
|
|
|
IntervalScales[precision]);
|
2002-04-21 21:52:18 +02:00
|
|
|
}
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-04 19:09:43 +01:00
|
|
|
/*
|
|
|
|
* make_interval - numeric Interval constructor
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
make_interval(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int32 years = PG_GETARG_INT32(0);
|
|
|
|
int32 months = PG_GETARG_INT32(1);
|
|
|
|
int32 weeks = PG_GETARG_INT32(2);
|
|
|
|
int32 days = PG_GETARG_INT32(3);
|
|
|
|
int32 hours = PG_GETARG_INT32(4);
|
|
|
|
int32 mins = PG_GETARG_INT32(5);
|
|
|
|
double secs = PG_GETARG_FLOAT8(6);
|
|
|
|
Interval *result;
|
|
|
|
|
2014-03-05 22:42:18 +01:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Reject out-of-range inputs. We really ought to check the integer
|
2014-03-05 22:42:18 +01:00
|
|
|
* inputs as well, but it's not entirely clear what limits to apply.
|
|
|
|
*/
|
|
|
|
if (isinf(secs) || isnan(secs))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
|
|
|
|
2014-03-04 19:09:43 +01:00
|
|
|
result = (Interval *) palloc(sizeof(Interval));
|
|
|
|
result->month = years * MONTHS_PER_YEAR + months;
|
|
|
|
result->day = weeks * 7 + days;
|
|
|
|
|
2017-02-09 21:49:57 +01:00
|
|
|
secs = rint(secs * USECS_PER_SEC);
|
2017-02-09 00:04:59 +01:00
|
|
|
result->time = hours * ((int64) SECS_PER_HOUR * USECS_PER_SEC) +
|
|
|
|
mins * ((int64) SECS_PER_MINUTE * USECS_PER_SEC) +
|
2017-02-09 21:49:57 +01:00
|
|
|
(int64) secs;
|
2014-03-04 19:09:43 +01:00
|
|
|
|
|
|
|
PG_RETURN_INTERVAL_P(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
/* EncodeSpecialTimestamp()
|
|
|
|
* Convert reserved timestamp data type to string.
|
|
|
|
*/
|
2015-10-20 20:06:24 +02:00
|
|
|
void
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
EncodeSpecialTimestamp(Timestamp dt, char *str)
|
|
|
|
{
|
2001-09-28 10:09:14 +02:00
|
|
|
if (TIMESTAMP_IS_NOBEGIN(dt))
|
|
|
|
strcpy(str, EARLY);
|
|
|
|
else if (TIMESTAMP_IS_NOEND(dt))
|
|
|
|
strcpy(str, LATE);
|
2017-06-21 20:39:04 +02:00
|
|
|
else /* shouldn't happen */
|
2008-10-14 17:44:29 +02:00
|
|
|
elog(ERROR, "invalid argument for EncodeSpecialTimestamp");
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
now(PG_FUNCTION_ARGS)
|
1997-03-14 06:58:13 +01:00
|
|
|
{
|
2005-06-30 00:51:57 +02:00
|
|
|
PG_RETURN_TIMESTAMPTZ(GetCurrentTransactionStartTimestamp());
|
1997-03-14 06:58:13 +01:00
|
|
|
}
|
|
|
|
|
2006-04-25 02:25:22 +02:00
|
|
|
Datum
|
|
|
|
statement_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_TIMESTAMPTZ(GetCurrentStatementStartTimestamp());
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
clock_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_TIMESTAMPTZ(GetCurrentTimestamp());
|
|
|
|
}
|
|
|
|
|
2005-06-14 23:04:42 +02:00
|
|
|
Datum
|
2008-05-04 23:13:36 +02:00
|
|
|
pg_postmaster_start_time(PG_FUNCTION_ARGS)
|
2005-06-14 23:04:42 +02:00
|
|
|
{
|
2005-06-30 00:51:57 +02:00
|
|
|
PG_RETURN_TIMESTAMPTZ(PgStartTime);
|
2008-05-04 23:13:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_conf_load_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_TIMESTAMPTZ(PgReloadTime);
|
2005-06-30 00:51:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* GetCurrentTimestamp -- get the current operating system time
|
|
|
|
*
|
|
|
|
* Result is in the form of a TimestampTz value, and is expressed to the
|
|
|
|
* full precision of the gettimeofday() syscall
|
|
|
|
*/
|
|
|
|
TimestampTz
|
|
|
|
GetCurrentTimestamp(void)
|
|
|
|
{
|
|
|
|
TimestampTz result;
|
|
|
|
struct timeval tp;
|
|
|
|
|
|
|
|
gettimeofday(&tp, NULL);
|
|
|
|
|
2005-08-12 20:23:56 +02:00
|
|
|
result = (TimestampTz) tp.tv_sec -
|
2005-06-30 00:51:57 +02:00
|
|
|
((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
|
2012-11-07 17:59:12 +01:00
|
|
|
result = (result * USECS_PER_SEC) + tp.tv_usec;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-08-17 02:33:01 +02:00
|
|
|
/*
|
|
|
|
* GetSQLCurrentTimestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
|
|
|
|
*/
|
|
|
|
TimestampTz
|
|
|
|
GetSQLCurrentTimestamp(int32 typmod)
|
|
|
|
{
|
|
|
|
TimestampTz ts;
|
|
|
|
|
|
|
|
ts = GetCurrentTransactionStartTimestamp();
|
|
|
|
if (typmod >= 0)
|
|
|
|
AdjustTimestampForTypmod(&ts, typmod);
|
|
|
|
return ts;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* GetSQLLocalTimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
|
|
|
|
*/
|
|
|
|
Timestamp
|
|
|
|
GetSQLLocalTimestamp(int32 typmod)
|
|
|
|
{
|
|
|
|
Timestamp ts;
|
|
|
|
|
|
|
|
ts = timestamptz2timestamp(GetCurrentTransactionStartTimestamp());
|
|
|
|
if (typmod >= 0)
|
|
|
|
AdjustTimestampForTypmod(&ts, typmod);
|
|
|
|
return ts;
|
|
|
|
}
|
|
|
|
|
2018-10-11 20:30:59 +02:00
|
|
|
/*
|
|
|
|
* timeofday(*) -- returns the current time as a text.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
timeofday(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
struct timeval tp;
|
|
|
|
char templ[128];
|
|
|
|
char buf[128];
|
|
|
|
pg_time_t tt;
|
|
|
|
|
|
|
|
gettimeofday(&tp, NULL);
|
|
|
|
tt = (pg_time_t) tp.tv_sec;
|
|
|
|
pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
|
|
|
|
pg_localtime(&tt, session_timezone));
|
|
|
|
snprintf(buf, sizeof(buf), templ, tp.tv_usec);
|
|
|
|
|
|
|
|
PG_RETURN_TEXT_P(cstring_to_text(buf));
|
|
|
|
}
|
|
|
|
|
2006-06-21 00:52:00 +02:00
|
|
|
/*
|
|
|
|
* TimestampDifference -- convert the difference between two timestamps
|
|
|
|
* into integer seconds and microseconds
|
|
|
|
*
|
|
|
|
* Both inputs must be ordinary finite timestamps (in current usage,
|
|
|
|
* they'll be results from GetCurrentTimestamp()).
|
|
|
|
*
|
2016-03-18 14:38:59 +01:00
|
|
|
* We expect start_time <= stop_time. If not, we return zeros; for current
|
2006-06-21 00:52:00 +02:00
|
|
|
* callers there is no need to be tense about which way division rounds on
|
|
|
|
* negative inputs.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
TimestampDifference(TimestampTz start_time, TimestampTz stop_time,
|
|
|
|
long *secs, int *microsecs)
|
|
|
|
{
|
|
|
|
TimestampTz diff = stop_time - start_time;
|
|
|
|
|
|
|
|
if (diff <= 0)
|
|
|
|
{
|
|
|
|
*secs = 0;
|
|
|
|
*microsecs = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*secs = (long) (diff / USECS_PER_SEC);
|
|
|
|
*microsecs = (int) (diff % USECS_PER_SEC);
|
|
|
|
}
|
|
|
|
}
|
2005-08-12 20:23:56 +02:00
|
|
|
|
2007-04-30 05:23:49 +02:00
|
|
|
/*
|
|
|
|
* TimestampDifferenceExceeds -- report whether the difference between two
|
|
|
|
* timestamps is >= a threshold (expressed in milliseconds)
|
|
|
|
*
|
|
|
|
* Both inputs must be ordinary finite timestamps (in current usage,
|
|
|
|
* they'll be results from GetCurrentTimestamp()).
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
TimestampDifferenceExceeds(TimestampTz start_time,
|
|
|
|
TimestampTz stop_time,
|
|
|
|
int msec)
|
|
|
|
{
|
|
|
|
TimestampTz diff = stop_time - start_time;
|
|
|
|
|
|
|
|
return (diff >= msec * INT64CONST(1000));
|
|
|
|
}
|
|
|
|
|
2005-08-12 20:23:56 +02:00
|
|
|
/*
|
|
|
|
* Convert a time_t to TimestampTz.
|
|
|
|
*
|
|
|
|
* We do not use time_t internally in Postgres, but this is provided for use
|
|
|
|
* by functions that need to interpret, say, a stat(2) result.
|
2008-02-17 03:09:32 +01:00
|
|
|
*
|
|
|
|
* To avoid having the function's ABI vary depending on the width of time_t,
|
|
|
|
* we declare the argument as pg_time_t, which is cast-compatible with
|
|
|
|
* time_t but always 64 bits wide (unless the platform has no 64-bit type).
|
|
|
|
* This detail should be invisible to callers, at least at source code level.
|
2005-08-12 20:23:56 +02:00
|
|
|
*/
|
|
|
|
TimestampTz
|
2008-02-17 03:09:32 +01:00
|
|
|
time_t_to_timestamptz(pg_time_t tm)
|
2005-08-12 20:23:56 +02:00
|
|
|
{
|
|
|
|
TimestampTz result;
|
|
|
|
|
|
|
|
result = (TimestampTz) tm -
|
|
|
|
((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
|
|
|
|
result *= USECS_PER_SEC;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2006-06-21 00:52:00 +02:00
|
|
|
/*
|
|
|
|
* Convert a TimestampTz to time_t.
|
|
|
|
*
|
|
|
|
* This too is just marginally useful, but some places need it.
|
2008-02-17 03:09:32 +01:00
|
|
|
*
|
|
|
|
* To avoid having the function's ABI vary depending on the width of time_t,
|
|
|
|
* we declare the result as pg_time_t, which is cast-compatible with
|
|
|
|
* time_t but always 64 bits wide (unless the platform has no 64-bit type).
|
|
|
|
* This detail should be invisible to callers, at least at source code level.
|
2006-06-21 00:52:00 +02:00
|
|
|
*/
|
2008-02-17 03:09:32 +01:00
|
|
|
pg_time_t
|
2006-06-21 00:52:00 +02:00
|
|
|
timestamptz_to_time_t(TimestampTz t)
|
|
|
|
{
|
2008-02-17 03:09:32 +01:00
|
|
|
pg_time_t result;
|
2006-06-21 00:52:00 +02:00
|
|
|
|
2008-02-17 03:09:32 +01:00
|
|
|
result = (pg_time_t) (t / USECS_PER_SEC +
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY));
|
2006-06-21 00:52:00 +02:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2007-04-30 23:01:53 +02:00
|
|
|
/*
|
|
|
|
* Produce a C-string representation of a TimestampTz.
|
|
|
|
*
|
|
|
|
* This is mostly for use in emitting messages. The primary difference
|
2014-05-06 18:12:18 +02:00
|
|
|
* from timestamptz_out is that we force the output format to ISO. Note
|
2007-04-30 23:01:53 +02:00
|
|
|
* also that the result is in a static buffer, not pstrdup'd.
|
|
|
|
*/
|
|
|
|
const char *
|
|
|
|
timestamptz_to_str(TimestampTz t)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
static char buf[MAXDATELEN + 1];
|
2007-04-30 23:01:53 +02:00
|
|
|
int tz;
|
|
|
|
struct pg_tm tt,
|
|
|
|
*tm = &tt;
|
|
|
|
fsec_t fsec;
|
2012-03-15 20:17:19 +01:00
|
|
|
const char *tzn;
|
2007-04-30 23:01:53 +02:00
|
|
|
|
|
|
|
if (TIMESTAMP_NOT_FINITE(t))
|
|
|
|
EncodeSpecialTimestamp(t, buf);
|
|
|
|
else if (timestamp2tm(t, &tz, tm, &fsec, &tzn, NULL) == 0)
|
2012-03-14 22:03:34 +01:00
|
|
|
EncodeDateTime(tm, fsec, true, tz, tzn, USE_ISO_DATES, buf);
|
2007-04-30 23:01:53 +02:00
|
|
|
else
|
|
|
|
strlcpy(buf, "(timestamp out of range)", sizeof(buf));
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2005-08-12 20:23:56 +02:00
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
void
|
2002-04-21 21:52:18 +02:00
|
|
|
dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2008-03-21 02:31:43 +01:00
|
|
|
TimeOffset time;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
time = jd;
|
|
|
|
|
2005-05-23 20:56:55 +02:00
|
|
|
*hour = time / USECS_PER_HOUR;
|
|
|
|
time -= (*hour) * USECS_PER_HOUR;
|
|
|
|
*min = time / USECS_PER_MINUTE;
|
|
|
|
time -= (*min) * USECS_PER_MINUTE;
|
|
|
|
*sec = time / USECS_PER_SEC;
|
|
|
|
*fsec = time - (*sec * USECS_PER_SEC);
|
2017-06-21 20:39:04 +02:00
|
|
|
} /* dt2time() */
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
|
2004-06-03 04:08:07 +02:00
|
|
|
/*
|
|
|
|
* timestamp2tm() - Convert timestamp data type to POSIX time structure.
|
|
|
|
*
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
* Note that year is _not_ 1900-based, but is an explicit full value.
|
|
|
|
* Also, month is one-based, _not_ zero-based.
|
|
|
|
* Returns:
|
|
|
|
* 0 on success
|
|
|
|
* -1 on out of range
|
2005-06-15 02:34:11 +02:00
|
|
|
*
|
2013-11-01 17:51:27 +01:00
|
|
|
* If attimezone is NULL, the global timezone setting will be used.
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*/
|
|
|
|
int
|
2017-06-21 20:39:04 +02:00
|
|
|
timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
Timestamp date;
|
2004-06-03 19:57:09 +02:00
|
|
|
Timestamp time;
|
2004-06-03 04:08:07 +02:00
|
|
|
pg_time_t utime;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2013-11-01 17:51:27 +01:00
|
|
|
/* Use session timezone if caller asks for default */
|
|
|
|
if (attimezone == NULL)
|
|
|
|
attimezone = session_timezone;
|
2001-10-18 19:30:21 +02:00
|
|
|
|
2005-10-09 19:21:47 +02:00
|
|
|
time = dt;
|
2005-05-23 20:56:55 +02:00
|
|
|
TMODULO(time, date, USECS_PER_DAY);
|
2002-04-21 21:52:18 +02:00
|
|
|
|
|
|
|
if (time < INT64CONST(0))
|
|
|
|
{
|
2005-05-23 20:56:55 +02:00
|
|
|
time += USECS_PER_DAY;
|
2005-05-23 19:13:14 +02:00
|
|
|
date -= 1;
|
2002-04-21 21:52:18 +02:00
|
|
|
}
|
2005-10-09 19:21:47 +02:00
|
|
|
|
|
|
|
/* add offset to go from J2000 back to standard Julian date */
|
|
|
|
date += POSTGRES_EPOCH_JDATE;
|
|
|
|
|
|
|
|
/* Julian day routine does not work for negative Julian days */
|
|
|
|
if (date < 0 || date > (Timestamp) INT_MAX)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
|
|
|
|
dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
|
|
|
|
|
2004-06-03 04:08:07 +02:00
|
|
|
/* Done if no TZ conversion wanted */
|
|
|
|
if (tzp == NULL)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2004-06-03 04:08:07 +02:00
|
|
|
tm->tm_isdst = -1;
|
|
|
|
tm->tm_gmtoff = 0;
|
|
|
|
tm->tm_zone = NULL;
|
|
|
|
if (tzn != NULL)
|
|
|
|
*tzn = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
2001-10-18 19:30:21 +02:00
|
|
|
|
2004-06-03 04:08:07 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If the time falls within the range of pg_time_t, use pg_localtime() to
|
|
|
|
* rotate to the local time zone.
|
2004-06-03 04:08:07 +02:00
|
|
|
*
|
|
|
|
* First, convert to an integral timestamp, avoiding possibly
|
|
|
|
* platform-specific roundoff-in-wrong-direction errors, and adjust to
|
2014-05-06 18:12:18 +02:00
|
|
|
* Unix epoch. Then see if we can convert to pg_time_t without loss. This
|
2005-10-15 04:49:52 +02:00
|
|
|
* coding avoids hardwiring any assumptions about the width of pg_time_t,
|
|
|
|
* so it should behave sanely on machines without int64.
|
2004-06-03 04:08:07 +02:00
|
|
|
*/
|
2005-05-23 20:56:55 +02:00
|
|
|
dt = (dt - *fsec) / USECS_PER_SEC +
|
2005-05-23 23:54:02 +02:00
|
|
|
(POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;
|
2004-06-03 04:08:07 +02:00
|
|
|
utime = (pg_time_t) dt;
|
|
|
|
if ((Timestamp) utime == dt)
|
|
|
|
{
|
2013-11-01 17:51:27 +01:00
|
|
|
struct pg_tm *tx = pg_localtime(&utime, attimezone);
|
2004-06-03 04:08:07 +02:00
|
|
|
|
|
|
|
tm->tm_year = tx->tm_year + 1900;
|
|
|
|
tm->tm_mon = tx->tm_mon + 1;
|
|
|
|
tm->tm_mday = tx->tm_mday;
|
|
|
|
tm->tm_hour = tx->tm_hour;
|
|
|
|
tm->tm_min = tx->tm_min;
|
|
|
|
tm->tm_sec = tx->tm_sec;
|
|
|
|
tm->tm_isdst = tx->tm_isdst;
|
|
|
|
tm->tm_gmtoff = tx->tm_gmtoff;
|
|
|
|
tm->tm_zone = tx->tm_zone;
|
2005-07-22 21:00:55 +02:00
|
|
|
*tzp = -tm->tm_gmtoff;
|
2004-06-03 04:08:07 +02:00
|
|
|
if (tzn != NULL)
|
2012-03-15 20:17:19 +01:00
|
|
|
*tzn = tm->tm_zone;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-06-03 04:08:07 +02:00
|
|
|
/*
|
|
|
|
* When out of range of pg_time_t, treat as GMT
|
|
|
|
*/
|
|
|
|
*tzp = 0;
|
|
|
|
/* Mark this as *no* time zone available */
|
2001-10-20 03:02:22 +02:00
|
|
|
tm->tm_isdst = -1;
|
2004-06-03 04:08:07 +02:00
|
|
|
tm->tm_gmtoff = 0;
|
|
|
|
tm->tm_zone = NULL;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
if (tzn != NULL)
|
|
|
|
*tzn = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2003-07-27 06:53:12 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
|
|
|
|
/* tm2timestamp()
|
|
|
|
* Convert a tm structure to a timestamp data type.
|
|
|
|
* Note that year is _not_ 1900-based, but is an explicit full value.
|
|
|
|
* Also, month is one-based, _not_ zero-based.
|
2003-07-04 20:21:14 +02:00
|
|
|
*
|
2003-07-27 06:53:12 +02:00
|
|
|
* Returns -1 on failure (value out of range).
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*/
|
|
|
|
int
|
2017-06-21 20:39:04 +02:00
|
|
|
tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2008-03-21 02:31:43 +01:00
|
|
|
TimeOffset date;
|
|
|
|
TimeOffset time;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2016-03-17 00:09:04 +01:00
|
|
|
/* Prevent overflow in Julian-day routines */
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
|
2006-11-11 02:14:19 +01:00
|
|
|
{
|
|
|
|
*result = 0; /* keep compiler quiet */
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
return -1;
|
2006-11-11 02:14:19 +01:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2003-04-04 06:50:44 +02:00
|
|
|
date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
|
2002-04-21 21:52:18 +02:00
|
|
|
time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
|
2005-07-22 23:16:15 +02:00
|
|
|
|
2005-05-23 20:56:55 +02:00
|
|
|
*result = date * USECS_PER_DAY + time;
|
2003-07-04 20:21:14 +02:00
|
|
|
/* check for major overflow */
|
2005-05-23 20:56:55 +02:00
|
|
|
if ((*result - time) / USECS_PER_DAY != date)
|
2006-11-11 02:14:19 +01:00
|
|
|
{
|
|
|
|
*result = 0; /* keep compiler quiet */
|
2003-07-04 20:21:14 +02:00
|
|
|
return -1;
|
2006-11-11 02:14:19 +01:00
|
|
|
}
|
2003-07-04 20:21:14 +02:00
|
|
|
/* check for just-barely overflow (okay except time-of-day wraps) */
|
2013-03-04 21:13:31 +01:00
|
|
|
/* caution: we want to allow 1999-12-31 24:00:00 */
|
|
|
|
if ((*result < 0 && date > 0) ||
|
|
|
|
(*result > 0 && date < -1))
|
2006-11-11 02:14:19 +01:00
|
|
|
{
|
|
|
|
*result = 0; /* keep compiler quiet */
|
2003-07-04 20:21:14 +02:00
|
|
|
return -1;
|
2006-11-11 02:14:19 +01:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
if (tzp != NULL)
|
|
|
|
*result = dt2local(*result, -(*tzp));
|
|
|
|
|
2016-03-17 00:09:04 +01:00
|
|
|
/* final range check catches just-out-of-range timestamps */
|
|
|
|
if (!IS_VALID_TIMESTAMP(*result))
|
|
|
|
{
|
|
|
|
*result = 0; /* keep compiler quiet */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
return 0;
|
2003-07-27 06:53:12 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
|
|
|
|
/* interval2tm()
|
2015-05-20 15:18:11 +02:00
|
|
|
* Convert an interval data type to a tm structure.
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*/
|
2001-09-06 05:22:42 +02:00
|
|
|
int
|
2017-06-21 20:39:04 +02:00
|
|
|
interval2tm(Interval span, struct pg_tm *tm, fsec_t *fsec)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2008-03-21 02:31:43 +01:00
|
|
|
TimeOffset time;
|
|
|
|
TimeOffset tfrac;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2005-07-21 05:56:25 +02:00
|
|
|
tm->tm_year = span.month / MONTHS_PER_YEAR;
|
|
|
|
tm->tm_mon = span.month % MONTHS_PER_YEAR;
|
2005-07-20 18:42:32 +02:00
|
|
|
tm->tm_mday = span.day;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
time = span.time;
|
|
|
|
|
2005-10-25 19:13:07 +02:00
|
|
|
tfrac = time / USECS_PER_HOUR;
|
|
|
|
time -= tfrac * USECS_PER_HOUR;
|
2014-01-30 15:41:43 +01:00
|
|
|
tm->tm_hour = tfrac;
|
|
|
|
if (!SAMESIGN(tm->tm_hour, tfrac))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
2005-10-25 19:13:07 +02:00
|
|
|
tfrac = time / USECS_PER_MINUTE;
|
|
|
|
time -= tfrac * USECS_PER_MINUTE;
|
|
|
|
tm->tm_min = tfrac;
|
|
|
|
tfrac = time / USECS_PER_SEC;
|
|
|
|
*fsec = time - (tfrac * USECS_PER_SEC);
|
|
|
|
tm->tm_sec = tfrac;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
return 0;
|
2003-07-27 06:53:12 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-09-06 05:22:42 +02:00
|
|
|
int
|
2017-06-21 20:39:04 +02:00
|
|
|
tm2interval(struct pg_tm *tm, fsec_t fsec, Interval *span)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2014-05-06 18:12:18 +02:00
|
|
|
double total_months = (double) tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon;
|
2014-01-30 15:41:43 +01:00
|
|
|
|
|
|
|
if (total_months > INT_MAX || total_months < INT_MIN)
|
|
|
|
return -1;
|
|
|
|
span->month = total_months;
|
2005-10-15 04:49:52 +02:00
|
|
|
span->day = tm->tm_mday;
|
2005-07-21 07:18:26 +02:00
|
|
|
span->time = (((((tm->tm_hour * INT64CONST(60)) +
|
2005-10-15 04:49:52 +02:00
|
|
|
tm->tm_min) * INT64CONST(60)) +
|
|
|
|
tm->tm_sec) * USECS_PER_SEC) + fsec;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
return 0;
|
2003-07-27 06:53:12 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2008-03-21 02:31:43 +01:00
|
|
|
static TimeOffset
|
2002-04-21 21:52:18 +02:00
|
|
|
time2t(const int hour, const int min, const int sec, const fsec_t fsec)
|
|
|
|
{
|
2005-07-21 20:06:13 +02:00
|
|
|
return (((((hour * MINS_PER_HOUR) + min) * SECS_PER_MINUTE) + sec) * USECS_PER_SEC) + fsec;
|
2008-03-21 02:31:43 +01:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 00:38:00 +02:00
|
|
|
static Timestamp
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
dt2local(Timestamp dt, int tz)
|
|
|
|
{
|
2005-05-23 20:56:55 +02:00
|
|
|
dt -= (tz * USECS_PER_SEC);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
return dt;
|
2008-03-21 02:31:43 +01:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* PUBLIC ROUTINES *
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
timestamp_finite(PG_FUNCTION_ARGS)
|
1997-03-14 06:58:13 +01:00
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-03-22 05:01:46 +01:00
|
|
|
PG_RETURN_BOOL(!TIMESTAMP_NOT_FINITE(timestamp));
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
1997-03-14 06:58:13 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_finite(PG_FUNCTION_ARGS)
|
1997-03-14 06:58:13 +01:00
|
|
|
{
|
2001-09-28 10:09:14 +02:00
|
|
|
PG_RETURN_BOOL(true);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
* Relational operators for timestamp.
|
|
|
|
*---------------------------------------------------------*/
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
void
|
2017-06-21 20:39:04 +02:00
|
|
|
GetEpochTime(struct pg_tm *tm)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm *t0;
|
|
|
|
pg_time_t epoch = 0;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2004-05-21 07:08:06 +02:00
|
|
|
t0 = pg_gmtime(&epoch);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2018-10-16 17:50:18 +02:00
|
|
|
if (t0 == NULL)
|
|
|
|
elog(ERROR, "could not convert epoch to timestamp: %m");
|
|
|
|
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
tm->tm_year = t0->tm_year;
|
|
|
|
tm->tm_mon = t0->tm_mon;
|
|
|
|
tm->tm_mday = t0->tm_mday;
|
|
|
|
tm->tm_hour = t0->tm_hour;
|
|
|
|
tm->tm_min = t0->tm_min;
|
|
|
|
tm->tm_sec = t0->tm_sec;
|
|
|
|
|
2004-06-03 04:08:07 +02:00
|
|
|
tm->tm_year += 1900;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
tm->tm_mon++;
|
2004-06-03 04:08:07 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
Timestamp
|
2001-09-28 10:09:14 +02:00
|
|
|
SetEpochTimestamp(void)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2001-09-28 10:09:14 +02:00
|
|
|
Timestamp dt;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
2001-09-28 10:09:14 +02:00
|
|
|
*tm = &tt;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
GetEpochTime(tm);
|
2003-07-27 06:53:12 +02:00
|
|
|
/* we don't bother to test for failure ... */
|
2001-09-28 10:09:14 +02:00
|
|
|
tm2timestamp(tm, 0, NULL, &dt);
|
1997-03-14 06:58:13 +01:00
|
|
|
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
return dt;
|
2017-06-21 20:39:04 +02:00
|
|
|
} /* SetEpochTimestamp() */
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
/*
|
2003-08-08 02:10:31 +02:00
|
|
|
* We are currently sharing some code between timestamp and timestamptz.
|
|
|
|
* The comparison functions are among them. - thomas 2001-09-25
|
|
|
|
*
|
2000-06-09 03:11:16 +02:00
|
|
|
* timestamp_relop - is timestamp1 relop timestamp2
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*/
|
2004-02-14 21:16:18 +01:00
|
|
|
int
|
2001-05-03 21:00:37 +02:00
|
|
|
timestamp_cmp_internal(Timestamp dt1, Timestamp dt2)
|
|
|
|
{
|
2005-05-24 04:09:45 +02:00
|
|
|
return (dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0);
|
2001-05-03 21:00:37 +02:00
|
|
|
}
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
timestamp_eq(PG_FUNCTION_ARGS)
|
1997-03-14 06:58:13 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-05-03 21:00:37 +02:00
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
1997-03-14 06:58:13 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
timestamp_ne(PG_FUNCTION_ARGS)
|
1997-03-14 06:58:13 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-05-03 21:00:37 +02:00
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
1997-03-14 06:58:13 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
timestamp_lt(PG_FUNCTION_ARGS)
|
1997-03-14 06:58:13 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-05-03 21:00:37 +02:00
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
1997-03-14 06:58:13 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
timestamp_gt(PG_FUNCTION_ARGS)
|
1997-03-14 06:58:13 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-05-03 21:00:37 +02:00
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
timestamp_le(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-05-03 21:00:37 +02:00
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
timestamp_ge(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-05-03 21:00:37 +02:00
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
timestamp_cmp(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
From: Thomas Lockhart <Thomas.G.Lockhart@jpl.nasa.gov>
Subject: [HACKERS] More date time functions
Here are some additional patches mostly related to the date and time
data types. It includes some type conversion routines to move between
the different date types and some other date manipulation routines such
as date_part(units,datetime).
I noticed Edmund Mergl et al's neat trick for getting function overloading
for builtin functions, so started to use that for the date and time stuff.
Later, if someone figures out how to get function overloading directly
for internal C code, then we can move to that technique.
These patches include documentation updates (don't faint!) for the built-in
man page. Doesn't yet include mention of timestamp, since I don't know
much about it and since it may change a bit to become a _real_ ANSI timestamp
which would include parser support for the declaration syntax (what do you
think, Dan?).
The patches were developed on the 970330 release, but have been rebuilt
off of the 970402 release. The first patch below is to get libpq to compile,
on my Linux box, but is not related to the rest of the patches and you can
choose not to apply that one at this time. Thanks in advance, scrappy!
1997-04-02 20:36:24 +02:00
|
|
|
|
2001-05-03 21:00:37 +02:00
|
|
|
PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2011-12-07 06:18:38 +01:00
|
|
|
/* note: this is used for timestamptz also */
|
|
|
|
static int
|
|
|
|
timestamp_fastcmp(Datum x, Datum y, SortSupport ssup)
|
|
|
|
{
|
|
|
|
Timestamp a = DatumGetTimestamp(x);
|
|
|
|
Timestamp b = DatumGetTimestamp(y);
|
|
|
|
|
|
|
|
return timestamp_cmp_internal(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
timestamp_sortsupport(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2012-06-10 21:20:04 +02:00
|
|
|
SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
|
2011-12-07 06:18:38 +01:00
|
|
|
|
|
|
|
ssup->comparator = timestamp_fastcmp;
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
2007-07-06 06:16:00 +02:00
|
|
|
Datum
|
|
|
|
timestamp_hash(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
return hashint8(fcinfo);
|
|
|
|
}
|
|
|
|
|
2017-09-01 04:21:21 +02:00
|
|
|
Datum
|
|
|
|
timestamp_hash_extended(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
return hashint8extended(fcinfo);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2004-03-22 02:38:18 +01:00
|
|
|
/*
|
2016-03-18 14:38:59 +01:00
|
|
|
* Cross-type comparison functions for timestamp vs timestamptz
|
2004-03-22 02:38:18 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
Datum
|
|
|
|
timestamp_eq_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
|
|
|
|
TimestampTz dt1;
|
2004-03-22 02:38:18 +01:00
|
|
|
|
|
|
|
dt1 = timestamp2timestamptz(timestampVal);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
timestamp_ne_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
|
|
|
|
TimestampTz dt1;
|
2004-03-22 02:38:18 +01:00
|
|
|
|
|
|
|
dt1 = timestamp2timestamptz(timestampVal);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
timestamp_lt_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
|
|
|
|
TimestampTz dt1;
|
2004-03-22 02:38:18 +01:00
|
|
|
|
|
|
|
dt1 = timestamp2timestamptz(timestampVal);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
timestamp_gt_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
|
|
|
|
TimestampTz dt1;
|
2004-03-22 02:38:18 +01:00
|
|
|
|
|
|
|
dt1 = timestamp2timestamptz(timestampVal);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
timestamp_le_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
|
|
|
|
TimestampTz dt1;
|
2004-03-22 02:38:18 +01:00
|
|
|
|
|
|
|
dt1 = timestamp2timestamptz(timestampVal);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
timestamp_ge_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
|
|
|
|
TimestampTz dt1;
|
2004-03-22 02:38:18 +01:00
|
|
|
|
|
|
|
dt1 = timestamp2timestamptz(timestampVal);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
timestamp_cmp_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
|
|
|
|
TimestampTz dt1;
|
2004-03-22 02:38:18 +01:00
|
|
|
|
|
|
|
dt1 = timestamp2timestamptz(timestampVal);
|
|
|
|
|
|
|
|
PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
timestamptz_eq_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
|
2004-03-22 02:38:18 +01:00
|
|
|
Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt2;
|
2004-03-22 02:38:18 +01:00
|
|
|
|
|
|
|
dt2 = timestamp2timestamptz(timestampVal);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
timestamptz_ne_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
|
2004-03-22 02:38:18 +01:00
|
|
|
Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt2;
|
2004-03-22 02:38:18 +01:00
|
|
|
|
|
|
|
dt2 = timestamp2timestamptz(timestampVal);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
timestamptz_lt_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
|
2004-03-22 02:38:18 +01:00
|
|
|
Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt2;
|
2004-03-22 02:38:18 +01:00
|
|
|
|
|
|
|
dt2 = timestamp2timestamptz(timestampVal);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
timestamptz_gt_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
|
2004-03-22 02:38:18 +01:00
|
|
|
Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt2;
|
2004-03-22 02:38:18 +01:00
|
|
|
|
|
|
|
dt2 = timestamp2timestamptz(timestampVal);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
timestamptz_le_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
|
2004-03-22 02:38:18 +01:00
|
|
|
Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt2;
|
2004-03-22 02:38:18 +01:00
|
|
|
|
|
|
|
dt2 = timestamp2timestamptz(timestampVal);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
timestamptz_ge_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
|
2004-03-22 02:38:18 +01:00
|
|
|
Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt2;
|
2004-03-22 02:38:18 +01:00
|
|
|
|
|
|
|
dt2 = timestamp2timestamptz(timestampVal);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
timestamptz_cmp_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
|
2004-03-22 02:38:18 +01:00
|
|
|
Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
|
2004-08-29 07:07:03 +02:00
|
|
|
TimestampTz dt2;
|
2004-03-22 02:38:18 +01:00
|
|
|
|
|
|
|
dt2 = timestamp2timestamptz(timestampVal);
|
|
|
|
|
|
|
|
PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
/*
|
|
|
|
* interval_relop - is interval1 relop interval2
|
Fix integer-overflow problems in interval comparison.
When using integer timestamps, the interval-comparison functions tried
to compute the overall magnitude of an interval as an int64 number of
microseconds. As reported by Frazer McLean, this overflows for intervals
exceeding about 296000 years, which is bad since we nominally allow
intervals many times larger than that. That results in wrong comparison
results, and possibly in corrupted btree indexes for columns containing
such large interval values.
To fix, compute the magnitude as int128 instead. Although some compilers
have native support for int128 calculations, many don't, so create our
own support functions that can do 128-bit addition and multiplication
if the compiler support isn't there. These support functions are designed
with an eye to allowing the int128 code paths in numeric.c to be rewritten
for use on all platforms, although this patch doesn't do that, or even
provide all the int128 primitives that will be needed for it.
Back-patch as far as 9.4. Earlier releases did not guard against overflow
of interval values at all (commit 146604ec4 fixed that), so it seems not
very exciting to worry about overly-large intervals for them.
Before 9.6, we did not assume that unreferenced "static inline" functions
would not draw compiler warnings, so omit functions not directly referenced
by timestamp.c, the only present consumer of int128.h. (We could have
omitted these functions in HEAD too, but since they were written and
debugged on the way to the present patch, and they look likely to be needed
by numeric.c, let's keep them in HEAD.) I did not bother to try to prevent
such warnings in a --disable-integer-datetimes build, though.
Before 9.5, configure will never define HAVE_INT128, so the part of
int128.h that exploits a native int128 implementation is dead code in the
9.4 branch. I didn't bother to remove it, thinking that keeping the file
looking similar in different branches is more useful.
In HEAD only, add a simple test harness for int128.h in src/tools/.
In back branches, this does not change the float-timestamps code path.
That's not subject to the same kind of overflow risk, since it computes
the interval magnitude as float8. (No doubt, when this code was originally
written, overflow was disregarded for exactly that reason.) There is a
precision hazard instead :-(, but we'll avert our eyes from that question,
since no complaints have been reported and that code's deprecated anyway.
Kyotaro Horiguchi and Tom Lane
Discussion: https://postgr.es/m/1490104629.422698.918452336.26FA96B7@webmail.messagingengine.com
2017-04-06 05:51:27 +02:00
|
|
|
*
|
|
|
|
* Interval comparison is based on converting interval values to a linear
|
|
|
|
* representation expressed in the units of the time field (microseconds,
|
|
|
|
* in the case of integer timestamps) with days assumed to be always 24 hours
|
|
|
|
* and months assumed to be always 30 days. To avoid overflow, we need a
|
|
|
|
* wider-than-int64 datatype for the linear representation, so use INT128.
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*/
|
Fix integer-overflow problems in interval comparison.
When using integer timestamps, the interval-comparison functions tried
to compute the overall magnitude of an interval as an int64 number of
microseconds. As reported by Frazer McLean, this overflows for intervals
exceeding about 296000 years, which is bad since we nominally allow
intervals many times larger than that. That results in wrong comparison
results, and possibly in corrupted btree indexes for columns containing
such large interval values.
To fix, compute the magnitude as int128 instead. Although some compilers
have native support for int128 calculations, many don't, so create our
own support functions that can do 128-bit addition and multiplication
if the compiler support isn't there. These support functions are designed
with an eye to allowing the int128 code paths in numeric.c to be rewritten
for use on all platforms, although this patch doesn't do that, or even
provide all the int128 primitives that will be needed for it.
Back-patch as far as 9.4. Earlier releases did not guard against overflow
of interval values at all (commit 146604ec4 fixed that), so it seems not
very exciting to worry about overly-large intervals for them.
Before 9.6, we did not assume that unreferenced "static inline" functions
would not draw compiler warnings, so omit functions not directly referenced
by timestamp.c, the only present consumer of int128.h. (We could have
omitted these functions in HEAD too, but since they were written and
debugged on the way to the present patch, and they look likely to be needed
by numeric.c, let's keep them in HEAD.) I did not bother to try to prevent
such warnings in a --disable-integer-datetimes build, though.
Before 9.5, configure will never define HAVE_INT128, so the part of
int128.h that exploits a native int128 implementation is dead code in the
9.4 branch. I didn't bother to remove it, thinking that keeping the file
looking similar in different branches is more useful.
In HEAD only, add a simple test harness for int128.h in src/tools/.
In back branches, this does not change the float-timestamps code path.
That's not subject to the same kind of overflow risk, since it computes
the interval magnitude as float8. (No doubt, when this code was originally
written, overflow was disregarded for exactly that reason.) There is a
precision hazard instead :-(, but we'll avert our eyes from that question,
since no complaints have been reported and that code's deprecated anyway.
Kyotaro Horiguchi and Tom Lane
Discussion: https://postgr.es/m/1490104629.422698.918452336.26FA96B7@webmail.messagingengine.com
2017-04-06 05:51:27 +02:00
|
|
|
|
|
|
|
static inline INT128
|
2009-04-04 06:53:25 +02:00
|
|
|
interval_cmp_value(const Interval *interval)
|
2001-05-03 21:00:37 +02:00
|
|
|
{
|
Fix integer-overflow problems in interval comparison.
When using integer timestamps, the interval-comparison functions tried
to compute the overall magnitude of an interval as an int64 number of
microseconds. As reported by Frazer McLean, this overflows for intervals
exceeding about 296000 years, which is bad since we nominally allow
intervals many times larger than that. That results in wrong comparison
results, and possibly in corrupted btree indexes for columns containing
such large interval values.
To fix, compute the magnitude as int128 instead. Although some compilers
have native support for int128 calculations, many don't, so create our
own support functions that can do 128-bit addition and multiplication
if the compiler support isn't there. These support functions are designed
with an eye to allowing the int128 code paths in numeric.c to be rewritten
for use on all platforms, although this patch doesn't do that, or even
provide all the int128 primitives that will be needed for it.
Back-patch as far as 9.4. Earlier releases did not guard against overflow
of interval values at all (commit 146604ec4 fixed that), so it seems not
very exciting to worry about overly-large intervals for them.
Before 9.6, we did not assume that unreferenced "static inline" functions
would not draw compiler warnings, so omit functions not directly referenced
by timestamp.c, the only present consumer of int128.h. (We could have
omitted these functions in HEAD too, but since they were written and
debugged on the way to the present patch, and they look likely to be needed
by numeric.c, let's keep them in HEAD.) I did not bother to try to prevent
such warnings in a --disable-integer-datetimes build, though.
Before 9.5, configure will never define HAVE_INT128, so the part of
int128.h that exploits a native int128 implementation is dead code in the
9.4 branch. I didn't bother to remove it, thinking that keeping the file
looking similar in different branches is more useful.
In HEAD only, add a simple test harness for int128.h in src/tools/.
In back branches, this does not change the float-timestamps code path.
That's not subject to the same kind of overflow risk, since it computes
the interval magnitude as float8. (No doubt, when this code was originally
written, overflow was disregarded for exactly that reason.) There is a
precision hazard instead :-(, but we'll avert our eyes from that question,
since no complaints have been reported and that code's deprecated anyway.
Kyotaro Horiguchi and Tom Lane
Discussion: https://postgr.es/m/1490104629.422698.918452336.26FA96B7@webmail.messagingengine.com
2017-04-06 05:51:27 +02:00
|
|
|
INT128 span;
|
|
|
|
int64 dayfraction;
|
|
|
|
int64 days;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Separate time field into days and dayfraction, then add the month and
|
|
|
|
* day fields to the days part. We cannot overflow int64 days here.
|
|
|
|
*/
|
|
|
|
dayfraction = interval->time % USECS_PER_DAY;
|
|
|
|
days = interval->time / USECS_PER_DAY;
|
|
|
|
days += interval->month * INT64CONST(30);
|
|
|
|
days += interval->day;
|
2001-05-03 21:00:37 +02:00
|
|
|
|
Fix integer-overflow problems in interval comparison.
When using integer timestamps, the interval-comparison functions tried
to compute the overall magnitude of an interval as an int64 number of
microseconds. As reported by Frazer McLean, this overflows for intervals
exceeding about 296000 years, which is bad since we nominally allow
intervals many times larger than that. That results in wrong comparison
results, and possibly in corrupted btree indexes for columns containing
such large interval values.
To fix, compute the magnitude as int128 instead. Although some compilers
have native support for int128 calculations, many don't, so create our
own support functions that can do 128-bit addition and multiplication
if the compiler support isn't there. These support functions are designed
with an eye to allowing the int128 code paths in numeric.c to be rewritten
for use on all platforms, although this patch doesn't do that, or even
provide all the int128 primitives that will be needed for it.
Back-patch as far as 9.4. Earlier releases did not guard against overflow
of interval values at all (commit 146604ec4 fixed that), so it seems not
very exciting to worry about overly-large intervals for them.
Before 9.6, we did not assume that unreferenced "static inline" functions
would not draw compiler warnings, so omit functions not directly referenced
by timestamp.c, the only present consumer of int128.h. (We could have
omitted these functions in HEAD too, but since they were written and
debugged on the way to the present patch, and they look likely to be needed
by numeric.c, let's keep them in HEAD.) I did not bother to try to prevent
such warnings in a --disable-integer-datetimes build, though.
Before 9.5, configure will never define HAVE_INT128, so the part of
int128.h that exploits a native int128 implementation is dead code in the
9.4 branch. I didn't bother to remove it, thinking that keeping the file
looking similar in different branches is more useful.
In HEAD only, add a simple test harness for int128.h in src/tools/.
In back branches, this does not change the float-timestamps code path.
That's not subject to the same kind of overflow risk, since it computes
the interval magnitude as float8. (No doubt, when this code was originally
written, overflow was disregarded for exactly that reason.) There is a
precision hazard instead :-(, but we'll avert our eyes from that question,
since no complaints have been reported and that code's deprecated anyway.
Kyotaro Horiguchi and Tom Lane
Discussion: https://postgr.es/m/1490104629.422698.918452336.26FA96B7@webmail.messagingengine.com
2017-04-06 05:51:27 +02:00
|
|
|
/* Widen dayfraction to 128 bits */
|
|
|
|
span = int64_to_int128(dayfraction);
|
|
|
|
|
|
|
|
/* Scale up days to microseconds, forming a 128-bit product */
|
|
|
|
int128_add_int64_mul_int64(&span, days, USECS_PER_DAY);
|
2001-05-03 21:00:37 +02:00
|
|
|
|
2009-04-04 06:53:25 +02:00
|
|
|
return span;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
interval_cmp_internal(Interval *interval1, Interval *interval2)
|
|
|
|
{
|
Fix integer-overflow problems in interval comparison.
When using integer timestamps, the interval-comparison functions tried
to compute the overall magnitude of an interval as an int64 number of
microseconds. As reported by Frazer McLean, this overflows for intervals
exceeding about 296000 years, which is bad since we nominally allow
intervals many times larger than that. That results in wrong comparison
results, and possibly in corrupted btree indexes for columns containing
such large interval values.
To fix, compute the magnitude as int128 instead. Although some compilers
have native support for int128 calculations, many don't, so create our
own support functions that can do 128-bit addition and multiplication
if the compiler support isn't there. These support functions are designed
with an eye to allowing the int128 code paths in numeric.c to be rewritten
for use on all platforms, although this patch doesn't do that, or even
provide all the int128 primitives that will be needed for it.
Back-patch as far as 9.4. Earlier releases did not guard against overflow
of interval values at all (commit 146604ec4 fixed that), so it seems not
very exciting to worry about overly-large intervals for them.
Before 9.6, we did not assume that unreferenced "static inline" functions
would not draw compiler warnings, so omit functions not directly referenced
by timestamp.c, the only present consumer of int128.h. (We could have
omitted these functions in HEAD too, but since they were written and
debugged on the way to the present patch, and they look likely to be needed
by numeric.c, let's keep them in HEAD.) I did not bother to try to prevent
such warnings in a --disable-integer-datetimes build, though.
Before 9.5, configure will never define HAVE_INT128, so the part of
int128.h that exploits a native int128 implementation is dead code in the
9.4 branch. I didn't bother to remove it, thinking that keeping the file
looking similar in different branches is more useful.
In HEAD only, add a simple test harness for int128.h in src/tools/.
In back branches, this does not change the float-timestamps code path.
That's not subject to the same kind of overflow risk, since it computes
the interval magnitude as float8. (No doubt, when this code was originally
written, overflow was disregarded for exactly that reason.) There is a
precision hazard instead :-(, but we'll avert our eyes from that question,
since no complaints have been reported and that code's deprecated anyway.
Kyotaro Horiguchi and Tom Lane
Discussion: https://postgr.es/m/1490104629.422698.918452336.26FA96B7@webmail.messagingengine.com
2017-04-06 05:51:27 +02:00
|
|
|
INT128 span1 = interval_cmp_value(interval1);
|
|
|
|
INT128 span2 = interval_cmp_value(interval2);
|
2009-04-04 06:53:25 +02:00
|
|
|
|
Fix integer-overflow problems in interval comparison.
When using integer timestamps, the interval-comparison functions tried
to compute the overall magnitude of an interval as an int64 number of
microseconds. As reported by Frazer McLean, this overflows for intervals
exceeding about 296000 years, which is bad since we nominally allow
intervals many times larger than that. That results in wrong comparison
results, and possibly in corrupted btree indexes for columns containing
such large interval values.
To fix, compute the magnitude as int128 instead. Although some compilers
have native support for int128 calculations, many don't, so create our
own support functions that can do 128-bit addition and multiplication
if the compiler support isn't there. These support functions are designed
with an eye to allowing the int128 code paths in numeric.c to be rewritten
for use on all platforms, although this patch doesn't do that, or even
provide all the int128 primitives that will be needed for it.
Back-patch as far as 9.4. Earlier releases did not guard against overflow
of interval values at all (commit 146604ec4 fixed that), so it seems not
very exciting to worry about overly-large intervals for them.
Before 9.6, we did not assume that unreferenced "static inline" functions
would not draw compiler warnings, so omit functions not directly referenced
by timestamp.c, the only present consumer of int128.h. (We could have
omitted these functions in HEAD too, but since they were written and
debugged on the way to the present patch, and they look likely to be needed
by numeric.c, let's keep them in HEAD.) I did not bother to try to prevent
such warnings in a --disable-integer-datetimes build, though.
Before 9.5, configure will never define HAVE_INT128, so the part of
int128.h that exploits a native int128 implementation is dead code in the
9.4 branch. I didn't bother to remove it, thinking that keeping the file
looking similar in different branches is more useful.
In HEAD only, add a simple test harness for int128.h in src/tools/.
In back branches, this does not change the float-timestamps code path.
That's not subject to the same kind of overflow risk, since it computes
the interval magnitude as float8. (No doubt, when this code was originally
written, overflow was disregarded for exactly that reason.) There is a
precision hazard instead :-(, but we'll avert our eyes from that question,
since no complaints have been reported and that code's deprecated anyway.
Kyotaro Horiguchi and Tom Lane
Discussion: https://postgr.es/m/1490104629.422698.918452336.26FA96B7@webmail.messagingengine.com
2017-04-06 05:51:27 +02:00
|
|
|
return int128_compare(span1, span2);
|
2001-05-03 21:00:37 +02:00
|
|
|
}
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_eq(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
|
|
|
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-05-03 21:00:37 +02:00
|
|
|
PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) == 0);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_ne(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
|
|
|
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-05-03 21:00:37 +02:00
|
|
|
PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) != 0);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_lt(PG_FUNCTION_ARGS)
|
From: Thomas Lockhart <Thomas.G.Lockhart@jpl.nasa.gov>
Subject: [HACKERS] More date time functions
Here are some additional patches mostly related to the date and time
data types. It includes some type conversion routines to move between
the different date types and some other date manipulation routines such
as date_part(units,datetime).
I noticed Edmund Mergl et al's neat trick for getting function overloading
for builtin functions, so started to use that for the date and time stuff.
Later, if someone figures out how to get function overloading directly
for internal C code, then we can move to that technique.
These patches include documentation updates (don't faint!) for the built-in
man page. Doesn't yet include mention of timestamp, since I don't know
much about it and since it may change a bit to become a _real_ ANSI timestamp
which would include parser support for the declaration syntax (what do you
think, Dan?).
The patches were developed on the 970330 release, but have been rebuilt
off of the 970402 release. The first patch below is to get libpq to compile,
on my Linux box, but is not related to the rest of the patches and you can
choose not to apply that one at this time. Thanks in advance, scrappy!
1997-04-02 20:36:24 +02:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
|
|
|
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-05-03 21:00:37 +02:00
|
|
|
PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) < 0);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_gt(PG_FUNCTION_ARGS)
|
1997-10-25 07:22:58 +02:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
|
|
|
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-05-03 21:00:37 +02:00
|
|
|
PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) > 0);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_le(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
|
|
|
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-05-03 21:00:37 +02:00
|
|
|
PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) <= 0);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_ge(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
|
|
|
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-05-03 21:00:37 +02:00
|
|
|
PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) >= 0);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_cmp(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
|
|
|
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-05-03 21:00:37 +02:00
|
|
|
PG_RETURN_INT32(interval_cmp_internal(interval1, interval2));
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2009-04-04 06:53:25 +02:00
|
|
|
/*
|
|
|
|
* Hashing for intervals
|
|
|
|
*
|
|
|
|
* We must produce equal hashvals for values that interval_cmp_internal()
|
|
|
|
* considers equal. So, compute the net span the same way it does,
|
2017-02-23 20:04:43 +01:00
|
|
|
* and then hash that.
|
2009-04-04 06:53:25 +02:00
|
|
|
*/
|
2000-06-19 05:55:01 +02:00
|
|
|
Datum
|
|
|
|
interval_hash(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2009-04-04 06:53:25 +02:00
|
|
|
Interval *interval = PG_GETARG_INTERVAL_P(0);
|
Fix integer-overflow problems in interval comparison.
When using integer timestamps, the interval-comparison functions tried
to compute the overall magnitude of an interval as an int64 number of
microseconds. As reported by Frazer McLean, this overflows for intervals
exceeding about 296000 years, which is bad since we nominally allow
intervals many times larger than that. That results in wrong comparison
results, and possibly in corrupted btree indexes for columns containing
such large interval values.
To fix, compute the magnitude as int128 instead. Although some compilers
have native support for int128 calculations, many don't, so create our
own support functions that can do 128-bit addition and multiplication
if the compiler support isn't there. These support functions are designed
with an eye to allowing the int128 code paths in numeric.c to be rewritten
for use on all platforms, although this patch doesn't do that, or even
provide all the int128 primitives that will be needed for it.
Back-patch as far as 9.4. Earlier releases did not guard against overflow
of interval values at all (commit 146604ec4 fixed that), so it seems not
very exciting to worry about overly-large intervals for them.
Before 9.6, we did not assume that unreferenced "static inline" functions
would not draw compiler warnings, so omit functions not directly referenced
by timestamp.c, the only present consumer of int128.h. (We could have
omitted these functions in HEAD too, but since they were written and
debugged on the way to the present patch, and they look likely to be needed
by numeric.c, let's keep them in HEAD.) I did not bother to try to prevent
such warnings in a --disable-integer-datetimes build, though.
Before 9.5, configure will never define HAVE_INT128, so the part of
int128.h that exploits a native int128 implementation is dead code in the
9.4 branch. I didn't bother to remove it, thinking that keeping the file
looking similar in different branches is more useful.
In HEAD only, add a simple test harness for int128.h in src/tools/.
In back branches, this does not change the float-timestamps code path.
That's not subject to the same kind of overflow risk, since it computes
the interval magnitude as float8. (No doubt, when this code was originally
written, overflow was disregarded for exactly that reason.) There is a
precision hazard instead :-(, but we'll avert our eyes from that question,
since no complaints have been reported and that code's deprecated anyway.
Kyotaro Horiguchi and Tom Lane
Discussion: https://postgr.es/m/1490104629.422698.918452336.26FA96B7@webmail.messagingengine.com
2017-04-06 05:51:27 +02:00
|
|
|
INT128 span = interval_cmp_value(interval);
|
|
|
|
int64 span64;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use only the least significant 64 bits for hashing. The upper 64 bits
|
|
|
|
* seldom add any useful information, and besides we must do it like this
|
|
|
|
* for compatibility with hashes calculated before use of INT128 was
|
|
|
|
* introduced.
|
|
|
|
*/
|
|
|
|
span64 = int128_to_int64(span);
|
2000-06-19 05:55:01 +02:00
|
|
|
|
Fix integer-overflow problems in interval comparison.
When using integer timestamps, the interval-comparison functions tried
to compute the overall magnitude of an interval as an int64 number of
microseconds. As reported by Frazer McLean, this overflows for intervals
exceeding about 296000 years, which is bad since we nominally allow
intervals many times larger than that. That results in wrong comparison
results, and possibly in corrupted btree indexes for columns containing
such large interval values.
To fix, compute the magnitude as int128 instead. Although some compilers
have native support for int128 calculations, many don't, so create our
own support functions that can do 128-bit addition and multiplication
if the compiler support isn't there. These support functions are designed
with an eye to allowing the int128 code paths in numeric.c to be rewritten
for use on all platforms, although this patch doesn't do that, or even
provide all the int128 primitives that will be needed for it.
Back-patch as far as 9.4. Earlier releases did not guard against overflow
of interval values at all (commit 146604ec4 fixed that), so it seems not
very exciting to worry about overly-large intervals for them.
Before 9.6, we did not assume that unreferenced "static inline" functions
would not draw compiler warnings, so omit functions not directly referenced
by timestamp.c, the only present consumer of int128.h. (We could have
omitted these functions in HEAD too, but since they were written and
debugged on the way to the present patch, and they look likely to be needed
by numeric.c, let's keep them in HEAD.) I did not bother to try to prevent
such warnings in a --disable-integer-datetimes build, though.
Before 9.5, configure will never define HAVE_INT128, so the part of
int128.h that exploits a native int128 implementation is dead code in the
9.4 branch. I didn't bother to remove it, thinking that keeping the file
looking similar in different branches is more useful.
In HEAD only, add a simple test harness for int128.h in src/tools/.
In back branches, this does not change the float-timestamps code path.
That's not subject to the same kind of overflow risk, since it computes
the interval magnitude as float8. (No doubt, when this code was originally
written, overflow was disregarded for exactly that reason.) There is a
precision hazard instead :-(, but we'll avert our eyes from that question,
since no complaints have been reported and that code's deprecated anyway.
Kyotaro Horiguchi and Tom Lane
Discussion: https://postgr.es/m/1490104629.422698.918452336.26FA96B7@webmail.messagingengine.com
2017-04-06 05:51:27 +02:00
|
|
|
return DirectFunctionCall1(hashint8, Int64GetDatumFast(span64));
|
2000-06-19 05:55:01 +02:00
|
|
|
}
|
|
|
|
|
2017-09-01 04:21:21 +02:00
|
|
|
Datum
|
|
|
|
interval_hash_extended(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Interval *interval = PG_GETARG_INTERVAL_P(0);
|
|
|
|
INT128 span = interval_cmp_value(interval);
|
|
|
|
int64 span64;
|
|
|
|
|
|
|
|
/* Same approach as interval_hash */
|
|
|
|
span64 = int128_to_int64(span);
|
|
|
|
|
|
|
|
return DirectFunctionCall2(hashint8extended, Int64GetDatumFast(span64),
|
|
|
|
PG_GETARG_DATUM(1));
|
|
|
|
}
|
|
|
|
|
2013-04-20 17:04:41 +02:00
|
|
|
/* overlaps_timestamp() --- implements the SQL OVERLAPS operator.
|
2000-12-07 19:38:59 +01:00
|
|
|
*
|
2013-04-20 17:04:41 +02:00
|
|
|
* Algorithm is per SQL spec. This is much harder than you'd think
|
2000-12-07 19:38:59 +01:00
|
|
|
* because the spec requires us to deliver a non-null answer in some cases
|
|
|
|
* where some of the inputs are null.
|
2000-03-15 00:06:59 +01:00
|
|
|
*/
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
overlaps_timestamp(PG_FUNCTION_ARGS)
|
2000-03-15 00:06:59 +01:00
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* The arguments are Timestamps, but we leave them as generic Datums to
|
|
|
|
* avoid unnecessary conversions between value and reference forms --- not
|
|
|
|
* to mention possible dereferences of null pointers.
|
2000-06-09 03:11:16 +02:00
|
|
|
*/
|
|
|
|
Datum ts1 = PG_GETARG_DATUM(0);
|
|
|
|
Datum te1 = PG_GETARG_DATUM(1);
|
|
|
|
Datum ts2 = PG_GETARG_DATUM(2);
|
|
|
|
Datum te2 = PG_GETARG_DATUM(3);
|
2000-12-07 19:38:59 +01:00
|
|
|
bool ts1IsNull = PG_ARGISNULL(0);
|
|
|
|
bool te1IsNull = PG_ARGISNULL(1);
|
|
|
|
bool ts2IsNull = PG_ARGISNULL(2);
|
|
|
|
bool te2IsNull = PG_ARGISNULL(3);
|
2000-06-09 03:11:16 +02:00
|
|
|
|
|
|
|
#define TIMESTAMP_GT(t1,t2) \
|
|
|
|
DatumGetBool(DirectFunctionCall2(timestamp_gt,t1,t2))
|
|
|
|
#define TIMESTAMP_LT(t1,t2) \
|
|
|
|
DatumGetBool(DirectFunctionCall2(timestamp_lt,t1,t2))
|
|
|
|
|
2000-12-07 19:38:59 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If both endpoints of interval 1 are null, the result is null (unknown).
|
|
|
|
* If just one endpoint is null, take ts1 as the non-null one. Otherwise,
|
|
|
|
* take ts1 as the lesser endpoint.
|
2000-12-07 19:38:59 +01:00
|
|
|
*/
|
|
|
|
if (ts1IsNull)
|
2000-03-15 00:06:59 +01:00
|
|
|
{
|
2000-12-07 19:38:59 +01:00
|
|
|
if (te1IsNull)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
/* swap null for non-null */
|
2000-03-15 00:06:59 +01:00
|
|
|
ts1 = te1;
|
2000-12-07 19:38:59 +01:00
|
|
|
te1IsNull = true;
|
2000-03-15 00:06:59 +01:00
|
|
|
}
|
2000-12-07 19:38:59 +01:00
|
|
|
else if (!te1IsNull)
|
2000-03-15 00:06:59 +01:00
|
|
|
{
|
2000-12-07 19:38:59 +01:00
|
|
|
if (TIMESTAMP_GT(ts1, te1))
|
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
Datum tt = ts1;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-12-07 19:38:59 +01:00
|
|
|
ts1 = te1;
|
|
|
|
te1 = tt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Likewise for interval 2. */
|
|
|
|
if (ts2IsNull)
|
|
|
|
{
|
|
|
|
if (te2IsNull)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
/* swap null for non-null */
|
2000-03-15 00:06:59 +01:00
|
|
|
ts2 = te2;
|
2000-12-07 19:38:59 +01:00
|
|
|
te2IsNull = true;
|
2000-03-15 00:06:59 +01:00
|
|
|
}
|
2000-12-07 19:38:59 +01:00
|
|
|
else if (!te2IsNull)
|
|
|
|
{
|
|
|
|
if (TIMESTAMP_GT(ts2, te2))
|
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
Datum tt = ts2;
|
2000-03-15 00:06:59 +01:00
|
|
|
|
2000-12-07 19:38:59 +01:00
|
|
|
ts2 = te2;
|
|
|
|
te2 = tt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* At this point neither ts1 nor ts2 is null, so we can consider three
|
|
|
|
* cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
|
|
|
|
*/
|
|
|
|
if (TIMESTAMP_GT(ts1, ts2))
|
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* This case is ts1 < te2 OR te1 < te2, which may look redundant but
|
|
|
|
* in the presence of nulls it's not quite completely so.
|
2000-12-07 19:38:59 +01:00
|
|
|
*/
|
|
|
|
if (te2IsNull)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
if (TIMESTAMP_LT(ts1, te2))
|
|
|
|
PG_RETURN_BOOL(true);
|
|
|
|
if (te1IsNull)
|
|
|
|
PG_RETURN_NULL();
|
2001-03-22 05:01:46 +01:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If te1 is not null then we had ts1 <= te1 above, and we just found
|
|
|
|
* ts1 >= te2, hence te1 >= te2.
|
2000-12-07 19:38:59 +01:00
|
|
|
*/
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
}
|
|
|
|
else if (TIMESTAMP_LT(ts1, ts2))
|
|
|
|
{
|
|
|
|
/* This case is ts2 < te1 OR te2 < te1 */
|
|
|
|
if (te1IsNull)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
if (TIMESTAMP_LT(ts2, te1))
|
|
|
|
PG_RETURN_BOOL(true);
|
|
|
|
if (te2IsNull)
|
|
|
|
PG_RETURN_NULL();
|
2001-03-22 05:01:46 +01:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If te2 is not null then we had ts2 <= te2 above, and we just found
|
|
|
|
* ts2 >= te1, hence te2 >= te1.
|
2000-12-07 19:38:59 +01:00
|
|
|
*/
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
/*
|
|
|
|
* For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
|
2016-03-18 14:38:59 +01:00
|
|
|
* rather silly way of saying "true if both are non-null, else null".
|
2000-12-07 19:38:59 +01:00
|
|
|
*/
|
|
|
|
if (te1IsNull || te2IsNull)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
PG_RETURN_BOOL(true);
|
|
|
|
}
|
2000-06-09 03:11:16 +02:00
|
|
|
|
|
|
|
#undef TIMESTAMP_GT
|
|
|
|
#undef TIMESTAMP_LT
|
|
|
|
}
|
2000-03-15 00:06:59 +01:00
|
|
|
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
* "Arithmetic" operators on date/times.
|
|
|
|
*---------------------------------------------------------*/
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
timestamp_smaller(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
|
|
|
Timestamp result;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2003-08-08 02:10:31 +02:00
|
|
|
/* use timestamp_cmp_internal to be sure this agrees with comparisons */
|
|
|
|
if (timestamp_cmp_internal(dt1, dt2) < 0)
|
|
|
|
result = dt1;
|
|
|
|
else
|
|
|
|
result = dt2;
|
2000-06-09 03:11:16 +02:00
|
|
|
PG_RETURN_TIMESTAMP(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
timestamp_larger(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
|
|
|
Timestamp result;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2003-08-08 02:10:31 +02:00
|
|
|
if (timestamp_cmp_internal(dt1, dt2) > 0)
|
|
|
|
result = dt1;
|
|
|
|
else
|
|
|
|
result = dt2;
|
2000-06-09 03:11:16 +02:00
|
|
|
PG_RETURN_TIMESTAMP(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
timestamp_mi(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
2005-08-25 05:53:22 +02:00
|
|
|
Interval *result;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
result = (Interval *) palloc(sizeof(Interval));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
if (TIMESTAMP_NOT_FINITE(dt1) || TIMESTAMP_NOT_FINITE(dt2))
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("cannot subtract infinite timestamps")));
|
2003-07-27 06:53:12 +02:00
|
|
|
|
2005-09-09 08:46:14 +02:00
|
|
|
result->time = dt1 - dt2;
|
2001-09-28 10:09:14 +02:00
|
|
|
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
result->month = 0;
|
2005-07-20 18:42:32 +02:00
|
|
|
result->day = 0;
|
|
|
|
|
2005-11-22 23:30:33 +01:00
|
|
|
/*----------
|
|
|
|
* This is wrong, but removing it breaks a lot of regression tests.
|
|
|
|
* For example:
|
2005-10-27 04:45:22 +02:00
|
|
|
*
|
2005-11-22 23:30:33 +01:00
|
|
|
* test=> SET timezone = 'EST5EDT';
|
|
|
|
* test=> SELECT
|
|
|
|
* test-> ('2005-10-30 13:22:00-05'::timestamptz -
|
2006-10-04 02:30:14 +02:00
|
|
|
* test(> '2005-10-29 13:22:00-04'::timestamptz);
|
2005-11-22 23:30:33 +01:00
|
|
|
* ?column?
|
|
|
|
* ----------------
|
|
|
|
* 1 day 01:00:00
|
|
|
|
* (1 row)
|
2005-10-27 04:45:22 +02:00
|
|
|
*
|
2005-11-22 23:30:33 +01:00
|
|
|
* so adding that to the first timestamp gets:
|
2005-10-27 04:45:22 +02:00
|
|
|
*
|
2005-11-22 23:30:33 +01:00
|
|
|
* test=> SELECT
|
|
|
|
* test-> ('2005-10-29 13:22:00-04'::timestamptz +
|
|
|
|
* test(> ('2005-10-30 13:22:00-05'::timestamptz -
|
|
|
|
* test(> '2005-10-29 13:22:00-04'::timestamptz)) at time zone 'EST';
|
2006-10-04 02:30:14 +02:00
|
|
|
* timezone
|
2005-11-22 23:30:33 +01:00
|
|
|
* --------------------
|
|
|
|
* 2005-10-30 14:22:00
|
|
|
|
* (1 row)
|
|
|
|
*----------
|
2005-10-27 04:45:22 +02:00
|
|
|
*/
|
2005-11-22 19:17:34 +01:00
|
|
|
result = DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
IntervalPGetDatum(result)));
|
2005-10-25 19:13:07 +02:00
|
|
|
|
2005-08-25 05:53:22 +02:00
|
|
|
PG_RETURN_INTERVAL_P(result);
|
2005-07-20 18:42:32 +02:00
|
|
|
}
|
|
|
|
|
2006-03-06 23:49:17 +01:00
|
|
|
/*
|
2006-10-04 02:30:14 +02:00
|
|
|
* interval_justify_interval()
|
2006-03-06 23:49:17 +01:00
|
|
|
*
|
2006-10-04 02:30:14 +02:00
|
|
|
* Adjust interval so 'month', 'day', and 'time' portions are within
|
|
|
|
* customary bounds. Specifically:
|
2006-03-06 23:49:17 +01:00
|
|
|
*
|
2006-10-04 02:30:14 +02:00
|
|
|
* 0 <= abs(time) < 24 hours
|
|
|
|
* 0 <= abs(day) < 30 days
|
2006-03-06 23:49:17 +01:00
|
|
|
*
|
2006-10-04 02:30:14 +02:00
|
|
|
* Also, the sign bit on all three fields is made equal, so either
|
|
|
|
* all three fields are negative or all are positive.
|
2006-03-06 23:49:17 +01:00
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
interval_justify_interval(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Interval *span = PG_GETARG_INTERVAL_P(0);
|
|
|
|
Interval *result;
|
2008-03-21 02:31:43 +01:00
|
|
|
TimeOffset wholeday;
|
2006-03-06 23:49:17 +01:00
|
|
|
int32 wholemonth;
|
|
|
|
|
|
|
|
result = (Interval *) palloc(sizeof(Interval));
|
|
|
|
result->month = span->month;
|
|
|
|
result->day = span->day;
|
|
|
|
result->time = span->time;
|
|
|
|
|
|
|
|
TMODULO(result->time, wholeday, USECS_PER_DAY);
|
|
|
|
result->day += wholeday; /* could overflow... */
|
|
|
|
|
|
|
|
wholemonth = result->day / DAYS_PER_MONTH;
|
|
|
|
result->day -= wholemonth * DAYS_PER_MONTH;
|
|
|
|
result->month += wholemonth;
|
|
|
|
|
|
|
|
if (result->month > 0 &&
|
|
|
|
(result->day < 0 || (result->day == 0 && result->time < 0)))
|
|
|
|
{
|
|
|
|
result->day += DAYS_PER_MONTH;
|
|
|
|
result->month--;
|
|
|
|
}
|
|
|
|
else if (result->month < 0 &&
|
2006-10-04 02:30:14 +02:00
|
|
|
(result->day > 0 || (result->day == 0 && result->time > 0)))
|
2006-03-06 23:49:17 +01:00
|
|
|
{
|
|
|
|
result->day -= DAYS_PER_MONTH;
|
|
|
|
result->month++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result->day > 0 && result->time < 0)
|
|
|
|
{
|
|
|
|
result->time += USECS_PER_DAY;
|
|
|
|
result->day--;
|
|
|
|
}
|
|
|
|
else if (result->day < 0 && result->time > 0)
|
2006-10-04 02:30:14 +02:00
|
|
|
{
|
2006-03-06 23:49:17 +01:00
|
|
|
result->time -= USECS_PER_DAY;
|
|
|
|
result->day++;
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_INTERVAL_P(result);
|
|
|
|
}
|
|
|
|
|
2005-10-25 19:13:07 +02:00
|
|
|
/*
|
|
|
|
* interval_justify_hours()
|
|
|
|
*
|
|
|
|
* Adjust interval so 'time' contains less than a whole day, adding
|
|
|
|
* the excess to 'day'. This is useful for
|
2005-07-20 18:42:32 +02:00
|
|
|
* situations (such as non-TZ) where '1 day' = '24 hours' is valid,
|
2005-10-25 19:13:07 +02:00
|
|
|
* e.g. interval subtraction and division.
|
2005-07-20 18:42:32 +02:00
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
interval_justify_hours(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
Interval *span = PG_GETARG_INTERVAL_P(0);
|
|
|
|
Interval *result;
|
2008-03-21 02:31:43 +01:00
|
|
|
TimeOffset wholeday;
|
2005-07-20 18:42:32 +02:00
|
|
|
|
|
|
|
result = (Interval *) palloc(sizeof(Interval));
|
|
|
|
result->month = span->month;
|
2005-10-25 19:13:07 +02:00
|
|
|
result->day = span->day;
|
2005-07-20 18:42:32 +02:00
|
|
|
result->time = span->time;
|
|
|
|
|
2005-10-25 19:13:07 +02:00
|
|
|
TMODULO(result->time, wholeday, USECS_PER_DAY);
|
|
|
|
result->day += wholeday; /* could overflow... */
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2006-03-06 23:49:17 +01:00
|
|
|
if (result->day > 0 && result->time < 0)
|
|
|
|
{
|
|
|
|
result->time += USECS_PER_DAY;
|
|
|
|
result->day--;
|
|
|
|
}
|
|
|
|
else if (result->day < 0 && result->time > 0)
|
|
|
|
{
|
|
|
|
result->time -= USECS_PER_DAY;
|
|
|
|
result->day++;
|
|
|
|
}
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
PG_RETURN_INTERVAL_P(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2005-10-25 19:13:07 +02:00
|
|
|
/*
|
|
|
|
* interval_justify_days()
|
|
|
|
*
|
|
|
|
* Adjust interval so 'day' contains less than 30 days, adding
|
|
|
|
* the excess to 'month'.
|
2005-07-20 18:42:32 +02:00
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
interval_justify_days(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
Interval *span = PG_GETARG_INTERVAL_P(0);
|
|
|
|
Interval *result;
|
2005-10-25 19:13:07 +02:00
|
|
|
int32 wholemonth;
|
2005-07-20 18:42:32 +02:00
|
|
|
|
|
|
|
result = (Interval *) palloc(sizeof(Interval));
|
2005-10-25 19:13:07 +02:00
|
|
|
result->month = span->month;
|
2005-07-20 18:42:32 +02:00
|
|
|
result->day = span->day;
|
|
|
|
result->time = span->time;
|
|
|
|
|
2005-10-25 19:13:07 +02:00
|
|
|
wholemonth = result->day / DAYS_PER_MONTH;
|
|
|
|
result->day -= wholemonth * DAYS_PER_MONTH;
|
|
|
|
result->month += wholemonth;
|
2005-07-20 18:42:32 +02:00
|
|
|
|
2006-03-06 23:49:17 +01:00
|
|
|
if (result->month > 0 && result->day < 0)
|
|
|
|
{
|
|
|
|
result->day += DAYS_PER_MONTH;
|
|
|
|
result->month--;
|
|
|
|
}
|
|
|
|
else if (result->month < 0 && result->day > 0)
|
|
|
|
{
|
|
|
|
result->day -= DAYS_PER_MONTH;
|
|
|
|
result->month++;
|
|
|
|
}
|
|
|
|
|
2005-07-20 18:42:32 +02:00
|
|
|
PG_RETURN_INTERVAL_P(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2004-02-14 21:16:18 +01:00
|
|
|
/* timestamp_pl_interval()
|
2015-05-20 15:18:11 +02:00
|
|
|
* Add an interval to a timestamp data type.
|
2005-07-20 18:42:32 +02:00
|
|
|
* Note that interval has provisions for qualitative year/month and day
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
* units, so try to do the right thing with them.
|
|
|
|
* To add a month, increment the month, and use the same day of month.
|
|
|
|
* Then, if the next month has fewer days, set the day of month
|
|
|
|
* to the last day of month.
|
2005-07-20 18:42:32 +02:00
|
|
|
* To add a day, increment the mday, and use the same time of day.
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
* Lastly, add in the "quantitative time".
|
|
|
|
*/
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
2004-02-14 21:16:18 +01:00
|
|
|
timestamp_pl_interval(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
|
2000-06-09 03:11:16 +02:00
|
|
|
Interval *span = PG_GETARG_INTERVAL_P(1);
|
|
|
|
Timestamp result;
|
2001-09-28 10:09:14 +02:00
|
|
|
|
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
|
|
|
result = timestamp;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (span->month != 0)
|
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
2001-09-28 10:09:14 +02:00
|
|
|
*tm = &tt;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec;
|
2001-09-28 10:09:14 +02:00
|
|
|
|
2005-07-21 06:41:43 +02:00
|
|
|
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
|
|
|
tm->tm_mon += span->month;
|
2005-07-21 05:56:25 +02:00
|
|
|
if (tm->tm_mon > MONTHS_PER_YEAR)
|
2001-09-28 10:09:14 +02:00
|
|
|
{
|
2005-07-21 05:56:25 +02:00
|
|
|
tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
|
|
|
|
tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
|
2001-09-28 10:09:14 +02:00
|
|
|
}
|
2003-07-27 06:53:12 +02:00
|
|
|
else if (tm->tm_mon < 1)
|
2001-09-28 10:09:14 +02:00
|
|
|
{
|
2005-07-21 05:56:25 +02:00
|
|
|
tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
|
|
|
|
tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR;
|
2001-09-28 10:09:14 +02:00
|
|
|
}
|
2003-07-27 06:53:12 +02:00
|
|
|
|
|
|
|
/* adjust for end of month boundary problems... */
|
|
|
|
if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
|
|
|
|
tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
|
|
|
|
|
2005-07-21 06:41:43 +02:00
|
|
|
if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
2001-09-28 10:09:14 +02:00
|
|
|
}
|
|
|
|
|
2005-07-20 18:42:32 +02:00
|
|
|
if (span->day != 0)
|
|
|
|
{
|
|
|
|
struct pg_tm tt,
|
|
|
|
*tm = &tt;
|
|
|
|
fsec_t fsec;
|
|
|
|
int julian;
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2005-07-21 06:41:43 +02:00
|
|
|
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
|
2005-07-20 18:42:32 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
2016-03-18 14:38:59 +01:00
|
|
|
/* Add days by converting to and from Julian */
|
2005-07-20 18:42:32 +02:00
|
|
|
julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day;
|
|
|
|
j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
|
|
|
|
|
2005-07-21 06:41:43 +02:00
|
|
|
if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0)
|
2005-07-20 18:42:32 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
}
|
|
|
|
|
|
|
|
timestamp += span->time;
|
2016-03-17 00:09:04 +01:00
|
|
|
|
|
|
|
if (!IS_VALID_TIMESTAMP(timestamp))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
result = timestamp;
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMP(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
2004-02-14 21:16:18 +01:00
|
|
|
timestamp_mi_interval(PG_FUNCTION_ARGS)
|
2001-09-28 10:09:14 +02:00
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
|
2001-09-28 10:09:14 +02:00
|
|
|
Interval *span = PG_GETARG_INTERVAL_P(1);
|
|
|
|
Interval tspan;
|
|
|
|
|
|
|
|
tspan.month = -span->month;
|
2005-07-20 18:42:32 +02:00
|
|
|
tspan.day = -span->day;
|
2001-09-28 10:09:14 +02:00
|
|
|
tspan.time = -span->time;
|
|
|
|
|
2004-02-14 21:16:18 +01:00
|
|
|
return DirectFunctionCall2(timestamp_pl_interval,
|
2001-09-28 10:09:14 +02:00
|
|
|
TimestampGetDatum(timestamp),
|
|
|
|
PointerGetDatum(&tspan));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-14 21:16:18 +01:00
|
|
|
/* timestamptz_pl_interval()
|
2015-05-20 15:18:11 +02:00
|
|
|
* Add an interval to a timestamp with time zone data type.
|
2001-09-28 10:09:14 +02:00
|
|
|
* Note that interval has provisions for qualitative year/month
|
|
|
|
* units, so try to do the right thing with them.
|
|
|
|
* To add a month, increment the month, and use the same day of month.
|
|
|
|
* Then, if the next month has fewer days, set the day of month
|
|
|
|
* to the last day of month.
|
|
|
|
* Lastly, add in the "quantitative time".
|
|
|
|
*/
|
|
|
|
Datum
|
2004-02-14 21:16:18 +01:00
|
|
|
timestamptz_pl_interval(PG_FUNCTION_ARGS)
|
2001-09-28 10:09:14 +02:00
|
|
|
{
|
2003-05-13 01:08:52 +02:00
|
|
|
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
|
2001-09-28 10:09:14 +02:00
|
|
|
Interval *span = PG_GETARG_INTERVAL_P(1);
|
2001-10-25 07:50:21 +02:00
|
|
|
TimestampTz result;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
int tz;
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
|
|
|
result = timestamp;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (span->month != 0)
|
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*tm = &tt;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2012-03-15 20:13:35 +01:00
|
|
|
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
2000-11-06 16:57:00 +01:00
|
|
|
|
2003-07-27 06:53:12 +02:00
|
|
|
tm->tm_mon += span->month;
|
2005-07-21 05:56:25 +02:00
|
|
|
if (tm->tm_mon > MONTHS_PER_YEAR)
|
2003-07-27 06:53:12 +02:00
|
|
|
{
|
2005-07-21 05:56:25 +02:00
|
|
|
tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
|
|
|
|
tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
2003-07-27 06:53:12 +02:00
|
|
|
else if (tm->tm_mon < 1)
|
2001-09-28 10:09:14 +02:00
|
|
|
{
|
2005-07-21 05:56:25 +02:00
|
|
|
tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
|
|
|
|
tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR;
|
2001-09-28 10:09:14 +02:00
|
|
|
}
|
2003-07-27 06:53:12 +02:00
|
|
|
|
|
|
|
/* adjust for end of month boundary problems... */
|
|
|
|
if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
|
|
|
|
tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
|
|
|
|
|
2007-08-04 03:26:54 +02:00
|
|
|
tz = DetermineTimeZoneOffset(tm, session_timezone);
|
2003-07-27 06:53:12 +02:00
|
|
|
|
2005-07-21 06:41:43 +02:00
|
|
|
if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
|
|
|
|
2005-07-20 18:42:32 +02:00
|
|
|
if (span->day != 0)
|
|
|
|
{
|
|
|
|
struct pg_tm tt,
|
|
|
|
*tm = &tt;
|
|
|
|
fsec_t fsec;
|
|
|
|
int julian;
|
|
|
|
|
2012-03-15 20:13:35 +01:00
|
|
|
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
|
2005-07-20 18:42:32 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
2016-03-18 14:38:59 +01:00
|
|
|
/* Add days by converting to and from Julian */
|
2005-07-20 18:42:32 +02:00
|
|
|
julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day;
|
|
|
|
j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
|
|
|
|
|
2007-08-04 03:26:54 +02:00
|
|
|
tz = DetermineTimeZoneOffset(tm, session_timezone);
|
2005-07-20 18:42:32 +02:00
|
|
|
|
2005-07-21 06:41:43 +02:00
|
|
|
if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0)
|
2005-07-20 18:42:32 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
}
|
|
|
|
|
|
|
|
timestamp += span->time;
|
2016-03-17 00:09:04 +01:00
|
|
|
|
|
|
|
if (!IS_VALID_TIMESTAMP(timestamp))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
result = timestamp;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
PG_RETURN_TIMESTAMP(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
2004-02-14 21:16:18 +01:00
|
|
|
timestamptz_mi_interval(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2003-05-13 01:08:52 +02:00
|
|
|
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
|
2000-06-09 03:11:16 +02:00
|
|
|
Interval *span = PG_GETARG_INTERVAL_P(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
Interval tspan;
|
|
|
|
|
2001-03-22 05:01:46 +01:00
|
|
|
tspan.month = -span->month;
|
2005-07-20 18:42:32 +02:00
|
|
|
tspan.day = -span->day;
|
2001-03-22 05:01:46 +01:00
|
|
|
tspan.time = -span->time;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2004-02-14 21:16:18 +01:00
|
|
|
return DirectFunctionCall2(timestamptz_pl_interval,
|
2000-06-09 03:11:16 +02:00
|
|
|
TimestampGetDatum(timestamp),
|
|
|
|
PointerGetDatum(&tspan));
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_um(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Interval *interval = PG_GETARG_INTERVAL_P(0);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
Interval *result;
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
result = (Interval *) palloc(sizeof(Interval));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2005-07-21 06:41:43 +02:00
|
|
|
result->time = -interval->time;
|
2014-01-30 15:41:43 +01:00
|
|
|
/* overflow check copied from int4um */
|
|
|
|
if (interval->time != 0 && SAMESIGN(result->time, interval->time))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
2005-07-21 06:41:43 +02:00
|
|
|
result->day = -interval->day;
|
2014-01-30 15:41:43 +01:00
|
|
|
if (interval->day != 0 && SAMESIGN(result->day, interval->day))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
2005-07-21 06:41:43 +02:00
|
|
|
result->month = -interval->month;
|
2014-01-30 15:41:43 +01:00
|
|
|
if (interval->month != 0 && SAMESIGN(result->month, interval->month))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
PG_RETURN_INTERVAL_P(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_smaller(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
|
|
|
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
Interval *result;
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2003-08-08 02:10:31 +02:00
|
|
|
/* use interval_cmp_internal to be sure this agrees with comparisons */
|
|
|
|
if (interval_cmp_internal(interval1, interval2) < 0)
|
|
|
|
result = interval1;
|
2001-09-28 10:09:14 +02:00
|
|
|
else
|
2003-08-08 02:10:31 +02:00
|
|
|
result = interval2;
|
2000-06-09 03:11:16 +02:00
|
|
|
PG_RETURN_INTERVAL_P(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_larger(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
|
|
|
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
Interval *result;
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2003-08-08 02:10:31 +02:00
|
|
|
if (interval_cmp_internal(interval1, interval2) > 0)
|
|
|
|
result = interval1;
|
2001-09-28 10:09:14 +02:00
|
|
|
else
|
2003-08-08 02:10:31 +02:00
|
|
|
result = interval2;
|
2000-06-09 03:11:16 +02:00
|
|
|
PG_RETURN_INTERVAL_P(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_pl(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Interval *span1 = PG_GETARG_INTERVAL_P(0);
|
|
|
|
Interval *span2 = PG_GETARG_INTERVAL_P(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
Interval *result;
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
result = (Interval *) palloc(sizeof(Interval));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2005-07-21 06:41:43 +02:00
|
|
|
result->month = span1->month + span2->month;
|
2014-01-30 15:41:43 +01:00
|
|
|
/* overflow check copied from int4pl */
|
|
|
|
if (SAMESIGN(span1->month, span2->month) &&
|
|
|
|
!SAMESIGN(result->month, span1->month))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
|
|
|
|
2005-07-21 06:41:43 +02:00
|
|
|
result->day = span1->day + span2->day;
|
2014-01-30 15:41:43 +01:00
|
|
|
if (SAMESIGN(span1->day, span2->day) &&
|
|
|
|
!SAMESIGN(result->day, span1->day))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
|
|
|
|
2005-07-21 06:41:43 +02:00
|
|
|
result->time = span1->time + span2->time;
|
2014-01-30 15:41:43 +01:00
|
|
|
if (SAMESIGN(span1->time, span2->time) &&
|
|
|
|
!SAMESIGN(result->time, span1->time))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
PG_RETURN_INTERVAL_P(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_mi(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Interval *span1 = PG_GETARG_INTERVAL_P(0);
|
|
|
|
Interval *span2 = PG_GETARG_INTERVAL_P(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
Interval *result;
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
result = (Interval *) palloc(sizeof(Interval));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2005-07-21 06:41:43 +02:00
|
|
|
result->month = span1->month - span2->month;
|
2014-01-30 15:41:43 +01:00
|
|
|
/* overflow check copied from int4mi */
|
|
|
|
if (!SAMESIGN(span1->month, span2->month) &&
|
|
|
|
!SAMESIGN(result->month, span1->month))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
|
|
|
|
2005-07-21 06:41:43 +02:00
|
|
|
result->day = span1->day - span2->day;
|
2014-01-30 15:41:43 +01:00
|
|
|
if (!SAMESIGN(span1->day, span2->day) &&
|
|
|
|
!SAMESIGN(result->day, span1->day))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
|
|
|
|
2005-07-21 06:41:43 +02:00
|
|
|
result->time = span1->time - span2->time;
|
2014-01-30 15:41:43 +01:00
|
|
|
if (!SAMESIGN(span1->time, span2->time) &&
|
|
|
|
!SAMESIGN(result->time, span1->time))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
PG_RETURN_INTERVAL_P(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2009-11-10 19:41:24 +01:00
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* There is no interval_abs(): it is unclear what value to return:
|
|
|
|
* http://archives.postgresql.org/pgsql-general/2009-10/msg01031.php
|
|
|
|
* http://archives.postgresql.org/pgsql-general/2009-11/msg00041.php
|
2009-11-10 19:41:24 +01:00
|
|
|
*/
|
2010-02-26 03:01:40 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_mul(PG_FUNCTION_ARGS)
|
2000-04-07 15:40:45 +02:00
|
|
|
{
|
2005-07-24 06:37:07 +02:00
|
|
|
Interval *span = PG_GETARG_INTERVAL_P(0);
|
2000-06-09 03:11:16 +02:00
|
|
|
float8 factor = PG_GETARG_FLOAT8(1);
|
2006-10-04 02:30:14 +02:00
|
|
|
double month_remainder_days,
|
2014-01-30 15:41:43 +01:00
|
|
|
sec_remainder,
|
|
|
|
result_double;
|
2006-10-04 02:30:14 +02:00
|
|
|
int32 orig_month = span->month,
|
|
|
|
orig_day = span->day;
|
2005-08-25 05:53:22 +02:00
|
|
|
Interval *result;
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
result = (Interval *) palloc(sizeof(Interval));
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2014-01-30 15:41:43 +01:00
|
|
|
result_double = span->month * factor;
|
2016-03-29 23:21:12 +02:00
|
|
|
if (isnan(result_double) ||
|
|
|
|
result_double > INT_MAX || result_double < INT_MIN)
|
2014-01-30 15:41:43 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
|
|
|
result->month = (int32) result_double;
|
|
|
|
|
|
|
|
result_double = span->day * factor;
|
2016-03-29 23:21:12 +02:00
|
|
|
if (isnan(result_double) ||
|
|
|
|
result_double > INT_MAX || result_double < INT_MIN)
|
2014-01-30 15:41:43 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
|
|
|
result->day = (int32) result_double;
|
2005-07-24 06:37:07 +02:00
|
|
|
|
2005-10-25 19:13:07 +02:00
|
|
|
/*
|
2005-11-22 19:17:34 +01:00
|
|
|
* The above correctly handles the whole-number part of the month and day
|
|
|
|
* products, but we have to do something with any fractional part
|
2016-03-18 14:38:59 +01:00
|
|
|
* resulting when the factor is non-integral. We cascade the fractions
|
2005-10-25 19:13:07 +02:00
|
|
|
* down to lower units using the conversion factors DAYS_PER_MONTH and
|
2005-11-22 19:17:34 +01:00
|
|
|
* SECS_PER_DAY. Note we do NOT cascade up, since we are not forced to do
|
|
|
|
* so by the representation. The user can choose to cascade up later,
|
2005-10-25 19:13:07 +02:00
|
|
|
* using justify_hours and/or justify_days.
|
|
|
|
*/
|
2005-07-24 06:37:07 +02:00
|
|
|
|
2006-09-03 05:34:04 +02:00
|
|
|
/*
|
2006-10-04 02:30:14 +02:00
|
|
|
* Fractional months full days into days.
|
2006-09-03 05:34:04 +02:00
|
|
|
*
|
2016-03-18 14:38:59 +01:00
|
|
|
* Floating point calculation are inherently imprecise, so these
|
2006-10-04 02:30:14 +02:00
|
|
|
* calculations are crafted to produce the most reliable result possible.
|
|
|
|
* TSROUND() is needed to more accurately produce whole numbers where
|
|
|
|
* appropriate.
|
2006-09-03 05:34:04 +02:00
|
|
|
*/
|
2006-09-05 03:13:40 +02:00
|
|
|
month_remainder_days = (orig_month * factor - result->month) * DAYS_PER_MONTH;
|
|
|
|
month_remainder_days = TSROUND(month_remainder_days);
|
|
|
|
sec_remainder = (orig_day * factor - result->day +
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
|
2006-09-05 03:13:40 +02:00
|
|
|
sec_remainder = TSROUND(sec_remainder);
|
|
|
|
|
|
|
|
/*
|
2006-10-04 02:30:14 +02:00
|
|
|
* Might have 24:00:00 hours due to rounding, or >24 hours because of time
|
|
|
|
* cascade from months and days. It might still be >24 if the combination
|
|
|
|
* of cascade and the seconds factor operation itself.
|
2006-09-05 03:13:40 +02:00
|
|
|
*/
|
|
|
|
if (Abs(sec_remainder) >= SECS_PER_DAY)
|
|
|
|
{
|
2006-10-04 02:30:14 +02:00
|
|
|
result->day += (int) (sec_remainder / SECS_PER_DAY);
|
|
|
|
sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
|
2006-09-05 03:13:40 +02:00
|
|
|
}
|
2005-07-24 06:37:07 +02:00
|
|
|
|
2006-09-03 05:34:04 +02:00
|
|
|
/* cascade units down */
|
|
|
|
result->day += (int32) month_remainder_days;
|
2014-01-30 15:41:43 +01:00
|
|
|
result_double = rint(span->time * factor + sec_remainder * USECS_PER_SEC);
|
2019-11-07 17:22:52 +01:00
|
|
|
if (isnan(result_double) || !FLOAT8_FITS_IN_INT64(result_double))
|
2014-01-30 15:41:43 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
|
|
|
result->time = (int64) result_double;
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2005-08-25 05:53:22 +02:00
|
|
|
PG_RETURN_INTERVAL_P(result);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
mul_d_interval(PG_FUNCTION_ARGS)
|
2000-04-07 15:40:45 +02:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
/* Args are float8 and Interval *, but leave them as generic Datum */
|
|
|
|
Datum factor = PG_GETARG_DATUM(0);
|
2005-07-24 06:37:07 +02:00
|
|
|
Datum span = PG_GETARG_DATUM(1);
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2005-07-24 06:37:07 +02:00
|
|
|
return DirectFunctionCall2(interval_mul, span, factor);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
interval_div(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2002-04-21 21:52:18 +02:00
|
|
|
Interval *span = PG_GETARG_INTERVAL_P(0);
|
2000-06-09 03:11:16 +02:00
|
|
|
float8 factor = PG_GETARG_FLOAT8(1);
|
2006-10-04 02:30:14 +02:00
|
|
|
double month_remainder_days,
|
|
|
|
sec_remainder;
|
|
|
|
int32 orig_month = span->month,
|
|
|
|
orig_day = span->day;
|
2005-08-25 05:53:22 +02:00
|
|
|
Interval *result;
|
2006-10-04 02:30:14 +02:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
result = (Interval *) palloc(sizeof(Interval));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
if (factor == 0.0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DIVISION_BY_ZERO),
|
|
|
|
errmsg("division by zero")));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2006-09-03 05:34:04 +02:00
|
|
|
result->month = (int32) (span->month / factor);
|
|
|
|
result->day = (int32) (span->day / factor);
|
2005-07-20 18:42:32 +02:00
|
|
|
|
2005-10-25 19:13:07 +02:00
|
|
|
/*
|
2006-10-04 02:30:14 +02:00
|
|
|
* Fractional months full days into days. See comment in interval_mul().
|
2005-10-25 19:13:07 +02:00
|
|
|
*/
|
2006-09-05 03:13:40 +02:00
|
|
|
month_remainder_days = (orig_month / factor - result->month) * DAYS_PER_MONTH;
|
|
|
|
month_remainder_days = TSROUND(month_remainder_days);
|
|
|
|
sec_remainder = (orig_day / factor - result->day +
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
|
2006-09-05 03:13:40 +02:00
|
|
|
sec_remainder = TSROUND(sec_remainder);
|
|
|
|
if (Abs(sec_remainder) >= SECS_PER_DAY)
|
|
|
|
{
|
2006-10-04 02:30:14 +02:00
|
|
|
result->day += (int) (sec_remainder / SECS_PER_DAY);
|
|
|
|
sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
|
2006-09-05 03:13:40 +02:00
|
|
|
}
|
2005-07-20 18:42:32 +02:00
|
|
|
|
2006-09-03 05:34:04 +02:00
|
|
|
/* cascade units down */
|
2005-10-25 19:13:07 +02:00
|
|
|
result->day += (int32) month_remainder_days;
|
2006-09-03 05:34:04 +02:00
|
|
|
result->time = rint(span->time / factor + sec_remainder * USECS_PER_SEC);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2005-08-25 05:53:22 +02:00
|
|
|
PG_RETURN_INTERVAL_P(result);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
Support all SQL:2011 options for window frame clauses.
This patch adds the ability to use "RANGE offset PRECEDING/FOLLOWING"
frame boundaries in window functions. We'd punted on that back in the
original patch to add window functions, because it was not clear how to
do it in a reasonably data-type-extensible fashion. That problem is
resolved here by adding the ability for btree operator classes to provide
an "in_range" support function that defines how to add or subtract the
RANGE offset value. Factoring it this way also allows the operator class
to avoid overflow problems near the ends of the datatype's range, if it
wishes to expend effort on that. (In the committed patch, the integer
opclasses handle that issue, but it did not seem worth the trouble to
avoid overflow failures for datetime types.)
The patch includes in_range support for the integer_ops opfamily
(int2/int4/int8) as well as the standard datetime types. Support for
other numeric types has been requested, but that seems like suitable
material for a follow-on patch.
In addition, the patch adds GROUPS mode which counts the offset in
ORDER-BY peer groups rather than rows, and it adds the frame_exclusion
options specified by SQL:2011. As far as I can see, we are now fully
up to spec on window framing options.
Existing behaviors remain unchanged, except that I changed the errcode
for a couple of existing error reports to meet the SQL spec's expectation
that negative "offset" values should be reported as SQLSTATE 22013.
Internally and in relevant parts of the documentation, we now consistently
use the terminology "offset PRECEDING/FOLLOWING" rather than "value
PRECEDING/FOLLOWING", since the term "value" is confusingly vague.
Oliver Ford, reviewed and whacked around some by me
Discussion: https://postgr.es/m/CAGMVOdu9sivPAxbNN0X+q19Sfv9edEPv=HibOJhB14TJv_RCQg@mail.gmail.com
2018-02-07 06:06:50 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* in_range support functions for timestamps and intervals.
|
|
|
|
*
|
|
|
|
* Per SQL spec, we support these with interval as the offset type.
|
|
|
|
* The spec's restriction that the offset not be negative is a bit hard to
|
|
|
|
* decipher for intervals, but we choose to interpret it the same as our
|
|
|
|
* interval comparison operators would.
|
|
|
|
*/
|
|
|
|
|
|
|
|
Datum
|
|
|
|
in_range_timestamptz_interval(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
TimestampTz val = PG_GETARG_TIMESTAMPTZ(0);
|
|
|
|
TimestampTz base = PG_GETARG_TIMESTAMPTZ(1);
|
|
|
|
Interval *offset = PG_GETARG_INTERVAL_P(2);
|
|
|
|
bool sub = PG_GETARG_BOOL(3);
|
|
|
|
bool less = PG_GETARG_BOOL(4);
|
|
|
|
TimestampTz sum;
|
|
|
|
|
|
|
|
if (int128_compare(interval_cmp_value(offset), int64_to_int128(0)) < 0)
|
|
|
|
ereport(ERROR,
|
2018-06-11 17:15:28 +02:00
|
|
|
(errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
|
Support all SQL:2011 options for window frame clauses.
This patch adds the ability to use "RANGE offset PRECEDING/FOLLOWING"
frame boundaries in window functions. We'd punted on that back in the
original patch to add window functions, because it was not clear how to
do it in a reasonably data-type-extensible fashion. That problem is
resolved here by adding the ability for btree operator classes to provide
an "in_range" support function that defines how to add or subtract the
RANGE offset value. Factoring it this way also allows the operator class
to avoid overflow problems near the ends of the datatype's range, if it
wishes to expend effort on that. (In the committed patch, the integer
opclasses handle that issue, but it did not seem worth the trouble to
avoid overflow failures for datetime types.)
The patch includes in_range support for the integer_ops opfamily
(int2/int4/int8) as well as the standard datetime types. Support for
other numeric types has been requested, but that seems like suitable
material for a follow-on patch.
In addition, the patch adds GROUPS mode which counts the offset in
ORDER-BY peer groups rather than rows, and it adds the frame_exclusion
options specified by SQL:2011. As far as I can see, we are now fully
up to spec on window framing options.
Existing behaviors remain unchanged, except that I changed the errcode
for a couple of existing error reports to meet the SQL spec's expectation
that negative "offset" values should be reported as SQLSTATE 22013.
Internally and in relevant parts of the documentation, we now consistently
use the terminology "offset PRECEDING/FOLLOWING" rather than "value
PRECEDING/FOLLOWING", since the term "value" is confusingly vague.
Oliver Ford, reviewed and whacked around some by me
Discussion: https://postgr.es/m/CAGMVOdu9sivPAxbNN0X+q19Sfv9edEPv=HibOJhB14TJv_RCQg@mail.gmail.com
2018-02-07 06:06:50 +01:00
|
|
|
errmsg("invalid preceding or following size in window function")));
|
|
|
|
|
|
|
|
/* We don't currently bother to avoid overflow hazards here */
|
|
|
|
if (sub)
|
|
|
|
sum = DatumGetTimestampTz(DirectFunctionCall2(timestamptz_mi_interval,
|
|
|
|
TimestampTzGetDatum(base),
|
|
|
|
IntervalPGetDatum(offset)));
|
|
|
|
else
|
|
|
|
sum = DatumGetTimestampTz(DirectFunctionCall2(timestamptz_pl_interval,
|
|
|
|
TimestampTzGetDatum(base),
|
|
|
|
IntervalPGetDatum(offset)));
|
|
|
|
|
|
|
|
if (less)
|
|
|
|
PG_RETURN_BOOL(val <= sum);
|
|
|
|
else
|
|
|
|
PG_RETURN_BOOL(val >= sum);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
in_range_timestamp_interval(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Timestamp val = PG_GETARG_TIMESTAMP(0);
|
|
|
|
Timestamp base = PG_GETARG_TIMESTAMP(1);
|
|
|
|
Interval *offset = PG_GETARG_INTERVAL_P(2);
|
|
|
|
bool sub = PG_GETARG_BOOL(3);
|
|
|
|
bool less = PG_GETARG_BOOL(4);
|
|
|
|
Timestamp sum;
|
|
|
|
|
|
|
|
if (int128_compare(interval_cmp_value(offset), int64_to_int128(0)) < 0)
|
|
|
|
ereport(ERROR,
|
2018-06-11 17:15:28 +02:00
|
|
|
(errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
|
Support all SQL:2011 options for window frame clauses.
This patch adds the ability to use "RANGE offset PRECEDING/FOLLOWING"
frame boundaries in window functions. We'd punted on that back in the
original patch to add window functions, because it was not clear how to
do it in a reasonably data-type-extensible fashion. That problem is
resolved here by adding the ability for btree operator classes to provide
an "in_range" support function that defines how to add or subtract the
RANGE offset value. Factoring it this way also allows the operator class
to avoid overflow problems near the ends of the datatype's range, if it
wishes to expend effort on that. (In the committed patch, the integer
opclasses handle that issue, but it did not seem worth the trouble to
avoid overflow failures for datetime types.)
The patch includes in_range support for the integer_ops opfamily
(int2/int4/int8) as well as the standard datetime types. Support for
other numeric types has been requested, but that seems like suitable
material for a follow-on patch.
In addition, the patch adds GROUPS mode which counts the offset in
ORDER-BY peer groups rather than rows, and it adds the frame_exclusion
options specified by SQL:2011. As far as I can see, we are now fully
up to spec on window framing options.
Existing behaviors remain unchanged, except that I changed the errcode
for a couple of existing error reports to meet the SQL spec's expectation
that negative "offset" values should be reported as SQLSTATE 22013.
Internally and in relevant parts of the documentation, we now consistently
use the terminology "offset PRECEDING/FOLLOWING" rather than "value
PRECEDING/FOLLOWING", since the term "value" is confusingly vague.
Oliver Ford, reviewed and whacked around some by me
Discussion: https://postgr.es/m/CAGMVOdu9sivPAxbNN0X+q19Sfv9edEPv=HibOJhB14TJv_RCQg@mail.gmail.com
2018-02-07 06:06:50 +01:00
|
|
|
errmsg("invalid preceding or following size in window function")));
|
|
|
|
|
|
|
|
/* We don't currently bother to avoid overflow hazards here */
|
|
|
|
if (sub)
|
|
|
|
sum = DatumGetTimestamp(DirectFunctionCall2(timestamp_mi_interval,
|
|
|
|
TimestampGetDatum(base),
|
|
|
|
IntervalPGetDatum(offset)));
|
|
|
|
else
|
|
|
|
sum = DatumGetTimestamp(DirectFunctionCall2(timestamp_pl_interval,
|
|
|
|
TimestampGetDatum(base),
|
|
|
|
IntervalPGetDatum(offset)));
|
|
|
|
|
|
|
|
if (less)
|
|
|
|
PG_RETURN_BOOL(val <= sum);
|
|
|
|
else
|
|
|
|
PG_RETURN_BOOL(val >= sum);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
in_range_interval_interval(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Interval *val = PG_GETARG_INTERVAL_P(0);
|
|
|
|
Interval *base = PG_GETARG_INTERVAL_P(1);
|
|
|
|
Interval *offset = PG_GETARG_INTERVAL_P(2);
|
|
|
|
bool sub = PG_GETARG_BOOL(3);
|
|
|
|
bool less = PG_GETARG_BOOL(4);
|
|
|
|
Interval *sum;
|
|
|
|
|
|
|
|
if (int128_compare(interval_cmp_value(offset), int64_to_int128(0)) < 0)
|
|
|
|
ereport(ERROR,
|
2018-06-11 17:15:28 +02:00
|
|
|
(errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
|
Support all SQL:2011 options for window frame clauses.
This patch adds the ability to use "RANGE offset PRECEDING/FOLLOWING"
frame boundaries in window functions. We'd punted on that back in the
original patch to add window functions, because it was not clear how to
do it in a reasonably data-type-extensible fashion. That problem is
resolved here by adding the ability for btree operator classes to provide
an "in_range" support function that defines how to add or subtract the
RANGE offset value. Factoring it this way also allows the operator class
to avoid overflow problems near the ends of the datatype's range, if it
wishes to expend effort on that. (In the committed patch, the integer
opclasses handle that issue, but it did not seem worth the trouble to
avoid overflow failures for datetime types.)
The patch includes in_range support for the integer_ops opfamily
(int2/int4/int8) as well as the standard datetime types. Support for
other numeric types has been requested, but that seems like suitable
material for a follow-on patch.
In addition, the patch adds GROUPS mode which counts the offset in
ORDER-BY peer groups rather than rows, and it adds the frame_exclusion
options specified by SQL:2011. As far as I can see, we are now fully
up to spec on window framing options.
Existing behaviors remain unchanged, except that I changed the errcode
for a couple of existing error reports to meet the SQL spec's expectation
that negative "offset" values should be reported as SQLSTATE 22013.
Internally and in relevant parts of the documentation, we now consistently
use the terminology "offset PRECEDING/FOLLOWING" rather than "value
PRECEDING/FOLLOWING", since the term "value" is confusingly vague.
Oliver Ford, reviewed and whacked around some by me
Discussion: https://postgr.es/m/CAGMVOdu9sivPAxbNN0X+q19Sfv9edEPv=HibOJhB14TJv_RCQg@mail.gmail.com
2018-02-07 06:06:50 +01:00
|
|
|
errmsg("invalid preceding or following size in window function")));
|
|
|
|
|
|
|
|
/* We don't currently bother to avoid overflow hazards here */
|
|
|
|
if (sub)
|
|
|
|
sum = DatumGetIntervalP(DirectFunctionCall2(interval_mi,
|
|
|
|
IntervalPGetDatum(base),
|
|
|
|
IntervalPGetDatum(offset)));
|
|
|
|
else
|
|
|
|
sum = DatumGetIntervalP(DirectFunctionCall2(interval_pl,
|
|
|
|
IntervalPGetDatum(base),
|
|
|
|
IntervalPGetDatum(offset)));
|
|
|
|
|
|
|
|
if (less)
|
|
|
|
PG_RETURN_BOOL(interval_cmp_internal(val, sum) <= 0);
|
|
|
|
else
|
|
|
|
PG_RETURN_BOOL(interval_cmp_internal(val, sum) >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-17 05:05:41 +02:00
|
|
|
/*
|
2014-04-13 02:33:09 +02:00
|
|
|
* interval_accum, interval_accum_inv, and interval_avg implement the
|
|
|
|
* AVG(interval) aggregate.
|
2000-07-17 05:05:41 +02:00
|
|
|
*
|
|
|
|
* The transition datatype for this aggregate is a 2-element array of
|
|
|
|
* intervals, where the first is the running sum and the second contains
|
|
|
|
* the number of values so far in its 'time' field. This is a bit ugly
|
|
|
|
* but it beats inventing a specialized datatype for the purpose.
|
|
|
|
*/
|
|
|
|
|
|
|
|
Datum
|
|
|
|
interval_accum(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
Interval *newval = PG_GETARG_INTERVAL_P(1);
|
|
|
|
Datum *transdatums;
|
|
|
|
int ndatums;
|
|
|
|
Interval sumX,
|
|
|
|
N;
|
|
|
|
Interval *newsum;
|
|
|
|
ArrayType *result;
|
|
|
|
|
|
|
|
deconstruct_array(transarray,
|
2005-07-20 18:42:32 +02:00
|
|
|
INTERVALOID, sizeof(Interval), false, 'd',
|
2005-11-17 23:14:56 +01:00
|
|
|
&transdatums, NULL, &ndatums);
|
2000-07-17 05:05:41 +02:00
|
|
|
if (ndatums != 2)
|
2003-07-27 06:53:12 +02:00
|
|
|
elog(ERROR, "expected 2-element interval array");
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2014-04-13 02:33:09 +02:00
|
|
|
sumX = *(DatumGetIntervalP(transdatums[0]));
|
|
|
|
N = *(DatumGetIntervalP(transdatums[1]));
|
2000-07-17 05:05:41 +02:00
|
|
|
|
|
|
|
newsum = DatumGetIntervalP(DirectFunctionCall2(interval_pl,
|
2005-10-15 04:49:52 +02:00
|
|
|
IntervalPGetDatum(&sumX),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
IntervalPGetDatum(newval)));
|
2000-07-17 05:05:41 +02:00
|
|
|
N.time += 1;
|
|
|
|
|
|
|
|
transdatums[0] = IntervalPGetDatum(newsum);
|
|
|
|
transdatums[1] = IntervalPGetDatum(&N);
|
|
|
|
|
|
|
|
result = construct_array(transdatums, 2,
|
2005-07-20 18:42:32 +02:00
|
|
|
INTERVALOID, sizeof(Interval), false, 'd');
|
2000-07-17 05:05:41 +02:00
|
|
|
|
|
|
|
PG_RETURN_ARRAYTYPE_P(result);
|
|
|
|
}
|
|
|
|
|
2016-04-05 20:24:59 +02:00
|
|
|
Datum
|
|
|
|
interval_combine(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
ArrayType *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
|
|
|
|
Datum *transdatums1;
|
|
|
|
Datum *transdatums2;
|
|
|
|
int ndatums1;
|
|
|
|
int ndatums2;
|
|
|
|
Interval sum1,
|
|
|
|
N1;
|
|
|
|
Interval sum2,
|
|
|
|
N2;
|
|
|
|
|
|
|
|
Interval *newsum;
|
|
|
|
ArrayType *result;
|
|
|
|
|
|
|
|
deconstruct_array(transarray1,
|
|
|
|
INTERVALOID, sizeof(Interval), false, 'd',
|
|
|
|
&transdatums1, NULL, &ndatums1);
|
|
|
|
if (ndatums1 != 2)
|
|
|
|
elog(ERROR, "expected 2-element interval array");
|
|
|
|
|
|
|
|
sum1 = *(DatumGetIntervalP(transdatums1[0]));
|
|
|
|
N1 = *(DatumGetIntervalP(transdatums1[1]));
|
|
|
|
|
|
|
|
deconstruct_array(transarray2,
|
|
|
|
INTERVALOID, sizeof(Interval), false, 'd',
|
|
|
|
&transdatums2, NULL, &ndatums2);
|
|
|
|
if (ndatums2 != 2)
|
|
|
|
elog(ERROR, "expected 2-element interval array");
|
|
|
|
|
|
|
|
sum2 = *(DatumGetIntervalP(transdatums2[0]));
|
|
|
|
N2 = *(DatumGetIntervalP(transdatums2[1]));
|
|
|
|
|
|
|
|
newsum = DatumGetIntervalP(DirectFunctionCall2(interval_pl,
|
|
|
|
IntervalPGetDatum(&sum1),
|
|
|
|
IntervalPGetDatum(&sum2)));
|
|
|
|
N1.time += N2.time;
|
|
|
|
|
|
|
|
transdatums1[0] = IntervalPGetDatum(newsum);
|
|
|
|
transdatums1[1] = IntervalPGetDatum(&N1);
|
|
|
|
|
|
|
|
result = construct_array(transdatums1, 2,
|
|
|
|
INTERVALOID, sizeof(Interval), false, 'd');
|
|
|
|
|
|
|
|
PG_RETURN_ARRAYTYPE_P(result);
|
|
|
|
}
|
|
|
|
|
2014-04-13 02:33:09 +02:00
|
|
|
Datum
|
|
|
|
interval_accum_inv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
Interval *newval = PG_GETARG_INTERVAL_P(1);
|
|
|
|
Datum *transdatums;
|
|
|
|
int ndatums;
|
|
|
|
Interval sumX,
|
|
|
|
N;
|
|
|
|
Interval *newsum;
|
|
|
|
ArrayType *result;
|
|
|
|
|
|
|
|
deconstruct_array(transarray,
|
|
|
|
INTERVALOID, sizeof(Interval), false, 'd',
|
|
|
|
&transdatums, NULL, &ndatums);
|
|
|
|
if (ndatums != 2)
|
|
|
|
elog(ERROR, "expected 2-element interval array");
|
|
|
|
|
|
|
|
sumX = *(DatumGetIntervalP(transdatums[0]));
|
|
|
|
N = *(DatumGetIntervalP(transdatums[1]));
|
|
|
|
|
|
|
|
newsum = DatumGetIntervalP(DirectFunctionCall2(interval_mi,
|
|
|
|
IntervalPGetDatum(&sumX),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
IntervalPGetDatum(newval)));
|
2014-04-13 02:33:09 +02:00
|
|
|
N.time -= 1;
|
|
|
|
|
|
|
|
transdatums[0] = IntervalPGetDatum(newsum);
|
|
|
|
transdatums[1] = IntervalPGetDatum(&N);
|
|
|
|
|
|
|
|
result = construct_array(transdatums, 2,
|
|
|
|
INTERVALOID, sizeof(Interval), false, 'd');
|
|
|
|
|
|
|
|
PG_RETURN_ARRAYTYPE_P(result);
|
|
|
|
}
|
|
|
|
|
2000-07-17 05:05:41 +02:00
|
|
|
Datum
|
|
|
|
interval_avg(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
Datum *transdatums;
|
|
|
|
int ndatums;
|
|
|
|
Interval sumX,
|
|
|
|
N;
|
|
|
|
|
|
|
|
deconstruct_array(transarray,
|
2005-07-20 18:42:32 +02:00
|
|
|
INTERVALOID, sizeof(Interval), false, 'd',
|
2005-11-17 23:14:56 +01:00
|
|
|
&transdatums, NULL, &ndatums);
|
2000-07-17 05:05:41 +02:00
|
|
|
if (ndatums != 2)
|
2003-07-27 06:53:12 +02:00
|
|
|
elog(ERROR, "expected 2-element interval array");
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2014-04-13 02:33:09 +02:00
|
|
|
sumX = *(DatumGetIntervalP(transdatums[0]));
|
|
|
|
N = *(DatumGetIntervalP(transdatums[1]));
|
2000-07-17 05:05:41 +02:00
|
|
|
|
2013-04-20 17:04:41 +02:00
|
|
|
/* SQL defines AVG of no values to be NULL */
|
2000-07-17 05:05:41 +02:00
|
|
|
if (N.time == 0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
return DirectFunctionCall2(interval_div,
|
|
|
|
IntervalPGetDatum(&sumX),
|
2014-04-13 02:33:09 +02:00
|
|
|
Float8GetDatum((double) N.time));
|
2000-07-17 05:05:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
/* timestamp_age()
|
|
|
|
* Calculate time difference while retaining year/month fields.
|
|
|
|
* Note that this does not result in an accurate absolute time span
|
|
|
|
* since year and month are out of context once the arithmetic
|
|
|
|
* is done.
|
|
|
|
*/
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
timestamp_age(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2000-06-09 03:11:16 +02:00
|
|
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
|
|
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
Interval *result;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec,
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
fsec1,
|
|
|
|
fsec2;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*tm = &tt;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt1,
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*tm1 = &tt1;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt2,
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*tm2 = &tt2;
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
result = (Interval *) palloc(sizeof(Interval));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2005-06-15 02:34:11 +02:00
|
|
|
if (timestamp2tm(dt1, NULL, tm1, &fsec1, NULL, NULL) == 0 &&
|
|
|
|
timestamp2tm(dt2, NULL, tm2, &fsec2, NULL, NULL) == 0)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2007-07-18 05:13:13 +02:00
|
|
|
/* form the symbolic difference */
|
|
|
|
fsec = fsec1 - fsec2;
|
2005-05-24 04:09:45 +02:00
|
|
|
tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
|
|
|
|
tm->tm_min = tm1->tm_min - tm2->tm_min;
|
|
|
|
tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
|
|
|
|
tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
|
|
|
|
tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
|
|
|
|
tm->tm_year = tm1->tm_year - tm2->tm_year;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
/* flip sign if necessary... */
|
|
|
|
if (dt1 < dt2)
|
|
|
|
{
|
|
|
|
fsec = -fsec;
|
|
|
|
tm->tm_sec = -tm->tm_sec;
|
|
|
|
tm->tm_min = -tm->tm_min;
|
|
|
|
tm->tm_hour = -tm->tm_hour;
|
|
|
|
tm->tm_mday = -tm->tm_mday;
|
|
|
|
tm->tm_mon = -tm->tm_mon;
|
|
|
|
tm->tm_year = -tm->tm_year;
|
|
|
|
}
|
|
|
|
|
2007-07-18 05:13:13 +02:00
|
|
|
/* propagate any negative fields into the next higher field */
|
|
|
|
while (fsec < 0)
|
|
|
|
{
|
|
|
|
fsec += USECS_PER_SEC;
|
|
|
|
tm->tm_sec--;
|
|
|
|
}
|
|
|
|
|
2004-12-01 20:57:49 +01:00
|
|
|
while (tm->tm_sec < 0)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2005-07-21 05:56:25 +02:00
|
|
|
tm->tm_sec += SECS_PER_MINUTE;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
tm->tm_min--;
|
|
|
|
}
|
|
|
|
|
2004-12-01 20:57:49 +01:00
|
|
|
while (tm->tm_min < 0)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2005-07-21 20:06:13 +02:00
|
|
|
tm->tm_min += MINS_PER_HOUR;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
tm->tm_hour--;
|
|
|
|
}
|
|
|
|
|
2004-12-01 20:57:49 +01:00
|
|
|
while (tm->tm_hour < 0)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2005-07-21 05:56:25 +02:00
|
|
|
tm->tm_hour += HOURS_PER_DAY;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
tm->tm_mday--;
|
|
|
|
}
|
|
|
|
|
2004-12-01 20:57:49 +01:00
|
|
|
while (tm->tm_mday < 0)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
|
|
|
if (dt1 < dt2)
|
|
|
|
{
|
|
|
|
tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
|
|
|
|
tm->tm_mon--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
|
|
|
|
tm->tm_mon--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-12-01 20:57:49 +01:00
|
|
|
while (tm->tm_mon < 0)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2005-07-21 05:56:25 +02:00
|
|
|
tm->tm_mon += MONTHS_PER_YEAR;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
tm->tm_year--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* recover sign if necessary... */
|
|
|
|
if (dt1 < dt2)
|
|
|
|
{
|
|
|
|
fsec = -fsec;
|
|
|
|
tm->tm_sec = -tm->tm_sec;
|
|
|
|
tm->tm_min = -tm->tm_min;
|
|
|
|
tm->tm_hour = -tm->tm_hour;
|
|
|
|
tm->tm_mday = -tm->tm_mday;
|
|
|
|
tm->tm_mon = -tm->tm_mon;
|
|
|
|
tm->tm_year = -tm->tm_year;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tm2interval(tm, fsec, result) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
|
|
|
else
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
PG_RETURN_INTERVAL_P(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
/* timestamptz_age()
|
|
|
|
* Calculate time difference while retaining year/month fields.
|
|
|
|
* Note that this does not result in an accurate absolute time span
|
|
|
|
* since year and month are out of context once the arithmetic
|
|
|
|
* is done.
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*/
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
2001-09-28 10:09:14 +02:00
|
|
|
timestamptz_age(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2003-05-13 01:08:52 +02:00
|
|
|
TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
|
|
|
|
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
|
2001-09-28 10:09:14 +02:00
|
|
|
Interval *result;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec,
|
2001-09-28 10:09:14 +02:00
|
|
|
fsec1,
|
|
|
|
fsec2;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
2001-09-28 10:09:14 +02:00
|
|
|
*tm = &tt;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt1,
|
2001-09-28 10:09:14 +02:00
|
|
|
*tm1 = &tt1;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt2,
|
2001-09-28 10:09:14 +02:00
|
|
|
*tm2 = &tt2;
|
2004-12-01 20:57:49 +01:00
|
|
|
int tz1;
|
|
|
|
int tz2;
|
2001-09-28 10:09:14 +02:00
|
|
|
|
|
|
|
result = (Interval *) palloc(sizeof(Interval));
|
|
|
|
|
2012-03-15 20:13:35 +01:00
|
|
|
if (timestamp2tm(dt1, &tz1, tm1, &fsec1, NULL, NULL) == 0 &&
|
|
|
|
timestamp2tm(dt2, &tz2, tm2, &fsec2, NULL, NULL) == 0)
|
2001-09-28 10:09:14 +02:00
|
|
|
{
|
2007-07-18 05:13:13 +02:00
|
|
|
/* form the symbolic difference */
|
2005-05-24 04:09:45 +02:00
|
|
|
fsec = fsec1 - fsec2;
|
|
|
|
tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
|
|
|
|
tm->tm_min = tm1->tm_min - tm2->tm_min;
|
|
|
|
tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
|
|
|
|
tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
|
|
|
|
tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
|
|
|
|
tm->tm_year = tm1->tm_year - tm2->tm_year;
|
2001-09-28 10:09:14 +02:00
|
|
|
|
|
|
|
/* flip sign if necessary... */
|
|
|
|
if (dt1 < dt2)
|
|
|
|
{
|
|
|
|
fsec = -fsec;
|
|
|
|
tm->tm_sec = -tm->tm_sec;
|
|
|
|
tm->tm_min = -tm->tm_min;
|
|
|
|
tm->tm_hour = -tm->tm_hour;
|
|
|
|
tm->tm_mday = -tm->tm_mday;
|
|
|
|
tm->tm_mon = -tm->tm_mon;
|
|
|
|
tm->tm_year = -tm->tm_year;
|
|
|
|
}
|
|
|
|
|
2007-07-18 05:13:13 +02:00
|
|
|
/* propagate any negative fields into the next higher field */
|
|
|
|
while (fsec < 0)
|
|
|
|
{
|
|
|
|
fsec += USECS_PER_SEC;
|
|
|
|
tm->tm_sec--;
|
|
|
|
}
|
|
|
|
|
2004-12-01 20:57:49 +01:00
|
|
|
while (tm->tm_sec < 0)
|
2001-09-28 10:09:14 +02:00
|
|
|
{
|
2005-07-21 05:56:25 +02:00
|
|
|
tm->tm_sec += SECS_PER_MINUTE;
|
2001-09-28 10:09:14 +02:00
|
|
|
tm->tm_min--;
|
|
|
|
}
|
|
|
|
|
2004-12-01 20:57:49 +01:00
|
|
|
while (tm->tm_min < 0)
|
2001-09-28 10:09:14 +02:00
|
|
|
{
|
2005-07-21 20:06:13 +02:00
|
|
|
tm->tm_min += MINS_PER_HOUR;
|
2001-09-28 10:09:14 +02:00
|
|
|
tm->tm_hour--;
|
|
|
|
}
|
|
|
|
|
2004-12-01 20:57:49 +01:00
|
|
|
while (tm->tm_hour < 0)
|
2001-09-28 10:09:14 +02:00
|
|
|
{
|
2005-07-21 05:56:25 +02:00
|
|
|
tm->tm_hour += HOURS_PER_DAY;
|
2001-09-28 10:09:14 +02:00
|
|
|
tm->tm_mday--;
|
|
|
|
}
|
|
|
|
|
2004-12-01 20:57:49 +01:00
|
|
|
while (tm->tm_mday < 0)
|
2001-09-28 10:09:14 +02:00
|
|
|
{
|
|
|
|
if (dt1 < dt2)
|
|
|
|
{
|
|
|
|
tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
|
|
|
|
tm->tm_mon--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
|
|
|
|
tm->tm_mon--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-12-01 20:57:49 +01:00
|
|
|
while (tm->tm_mon < 0)
|
2001-09-28 10:09:14 +02:00
|
|
|
{
|
2005-07-21 05:56:25 +02:00
|
|
|
tm->tm_mon += MONTHS_PER_YEAR;
|
2001-09-28 10:09:14 +02:00
|
|
|
tm->tm_year--;
|
|
|
|
}
|
|
|
|
|
2004-12-01 20:57:49 +01:00
|
|
|
/*
|
|
|
|
* Note: we deliberately ignore any difference between tz1 and tz2.
|
|
|
|
*/
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
/* recover sign if necessary... */
|
|
|
|
if (dt1 < dt2)
|
|
|
|
{
|
|
|
|
fsec = -fsec;
|
|
|
|
tm->tm_sec = -tm->tm_sec;
|
|
|
|
tm->tm_min = -tm->tm_min;
|
|
|
|
tm->tm_hour = -tm->tm_hour;
|
|
|
|
tm->tm_mday = -tm->tm_mday;
|
|
|
|
tm->tm_mon = -tm->tm_mon;
|
|
|
|
tm->tm_year = -tm->tm_year;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tm2interval(tm, fsec, result) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
2001-09-28 10:09:14 +02:00
|
|
|
}
|
|
|
|
else
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
2001-09-28 10:09:14 +02:00
|
|
|
|
|
|
|
PG_RETURN_INTERVAL_P(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
* Conversion operators.
|
|
|
|
*---------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
/* timestamp_trunc()
|
2001-09-28 10:09:14 +02:00
|
|
|
* Truncate timestamp to specified units.
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*/
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
timestamp_trunc(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2008-03-25 23:42:46 +01:00
|
|
|
text *units = PG_GETARG_TEXT_PP(0);
|
2005-10-15 04:49:52 +02:00
|
|
|
Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
|
2000-06-09 03:11:16 +02:00
|
|
|
Timestamp result;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
int type,
|
|
|
|
val;
|
2004-05-07 02:24:59 +02:00
|
|
|
char *lowunits;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*tm = &tt;
|
|
|
|
|
2004-05-07 02:24:59 +02:00
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
|
|
|
PG_RETURN_TIMESTAMP(timestamp);
|
2003-07-27 06:53:12 +02:00
|
|
|
|
2008-03-25 23:42:46 +01:00
|
|
|
lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
|
|
|
|
VARSIZE_ANY_EXHDR(units),
|
2004-05-07 02:24:59 +02:00
|
|
|
false);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
type = DecodeUnits(0, lowunits, &val);
|
|
|
|
|
2003-07-27 06:53:12 +02:00
|
|
|
if (type == UNITS)
|
2001-09-28 10:09:14 +02:00
|
|
|
{
|
2005-07-21 06:41:43 +02:00
|
|
|
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
switch (val)
|
|
|
|
{
|
2004-03-05 03:41:14 +01:00
|
|
|
case DTK_WEEK:
|
2005-10-15 04:49:52 +02:00
|
|
|
{
|
|
|
|
int woy;
|
|
|
|
|
|
|
|
woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If it is week 52/53 and the month is January, then the
|
|
|
|
* week must belong to the previous year. Also, some
|
|
|
|
* December dates belong to the next year.
|
|
|
|
*/
|
|
|
|
if (woy >= 52 && tm->tm_mon == 1)
|
|
|
|
--tm->tm_year;
|
|
|
|
if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
|
|
|
|
++tm->tm_year;
|
|
|
|
isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
|
|
|
|
tm->tm_hour = 0;
|
|
|
|
tm->tm_min = 0;
|
|
|
|
tm->tm_sec = 0;
|
|
|
|
fsec = 0;
|
|
|
|
break;
|
|
|
|
}
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_MILLENNIUM:
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
/* see comments in timestamptz_trunc */
|
|
|
|
if (tm->tm_year > 0)
|
2004-08-29 07:07:03 +02:00
|
|
|
tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
else
|
2004-08-29 07:07:03 +02:00
|
|
|
tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_CENTURY:
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
/* see comments in timestamptz_trunc */
|
|
|
|
if (tm->tm_year > 0)
|
2004-08-29 07:07:03 +02:00
|
|
|
tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
else
|
2004-08-29 07:07:03 +02:00
|
|
|
tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_DECADE:
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
/* see comments in timestamptz_trunc */
|
|
|
|
if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
|
|
|
|
{
|
|
|
|
if (tm->tm_year > 0)
|
|
|
|
tm->tm_year = (tm->tm_year / 10) * 10;
|
|
|
|
else
|
2004-08-29 07:07:03 +02:00
|
|
|
tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
}
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_YEAR:
|
|
|
|
tm->tm_mon = 1;
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_QUARTER:
|
2003-07-26 17:17:36 +02:00
|
|
|
tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_MONTH:
|
|
|
|
tm->tm_mday = 1;
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_DAY:
|
|
|
|
tm->tm_hour = 0;
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_HOUR:
|
|
|
|
tm->tm_min = 0;
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_MINUTE:
|
|
|
|
tm->tm_sec = 0;
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_SECOND:
|
|
|
|
fsec = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_MILLISEC:
|
2005-05-23 19:13:14 +02:00
|
|
|
fsec = (fsec / 1000) * 1000;
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_MICROSEC:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("timestamp units \"%s\" not supported",
|
|
|
|
lowunits)));
|
2001-09-28 10:09:14 +02:00
|
|
|
result = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tm2timestamp(tm, fsec, NULL, &result) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
2001-09-28 10:09:14 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
else
|
|
|
|
{
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("timestamp units \"%s\" not recognized",
|
|
|
|
lowunits)));
|
2001-09-28 10:09:14 +02:00
|
|
|
result = 0;
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
PG_RETURN_TIMESTAMP(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2018-11-14 21:41:07 +01:00
|
|
|
/*
|
|
|
|
* Common code for timestamptz_trunc() and timestamptz_trunc_zone().
|
|
|
|
*
|
|
|
|
* tzp identifies the zone to truncate with respect to. We assume
|
|
|
|
* infinite timestamps have already been rejected.
|
2001-09-28 10:09:14 +02:00
|
|
|
*/
|
2018-11-14 21:41:07 +01:00
|
|
|
static TimestampTz
|
|
|
|
timestamptz_trunc_internal(text *units, TimestampTz timestamp, pg_tz *tzp)
|
2001-09-28 10:09:14 +02:00
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
TimestampTz result;
|
2001-09-28 10:09:14 +02:00
|
|
|
int tz;
|
|
|
|
int type,
|
|
|
|
val;
|
2004-11-01 23:00:30 +01:00
|
|
|
bool redotz = false;
|
2004-05-07 02:24:59 +02:00
|
|
|
char *lowunits;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
2001-09-28 10:09:14 +02:00
|
|
|
*tm = &tt;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2008-03-25 23:42:46 +01:00
|
|
|
lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
|
|
|
|
VARSIZE_ANY_EXHDR(units),
|
2004-05-07 02:24:59 +02:00
|
|
|
false);
|
|
|
|
|
|
|
|
type = DecodeUnits(0, lowunits, &val);
|
|
|
|
|
2003-07-27 06:53:12 +02:00
|
|
|
if (type == UNITS)
|
2001-09-28 10:09:14 +02:00
|
|
|
{
|
2018-11-14 21:41:07 +01:00
|
|
|
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, tzp) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
switch (val)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2004-03-05 03:41:14 +01:00
|
|
|
case DTK_WEEK:
|
2005-10-15 04:49:52 +02:00
|
|
|
{
|
|
|
|
int woy;
|
|
|
|
|
|
|
|
woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If it is week 52/53 and the month is January, then the
|
|
|
|
* week must belong to the previous year. Also, some
|
|
|
|
* December dates belong to the next year.
|
|
|
|
*/
|
|
|
|
if (woy >= 52 && tm->tm_mon == 1)
|
|
|
|
--tm->tm_year;
|
|
|
|
if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
|
|
|
|
++tm->tm_year;
|
|
|
|
isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
|
|
|
|
tm->tm_hour = 0;
|
|
|
|
tm->tm_min = 0;
|
|
|
|
tm->tm_sec = 0;
|
|
|
|
fsec = 0;
|
|
|
|
redotz = true;
|
|
|
|
break;
|
|
|
|
}
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
/* one may consider DTK_THOUSAND and DTK_HUNDRED... */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_MILLENNIUM:
|
2004-08-29 07:07:03 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* truncating to the millennium? what is this supposed to
|
2005-10-15 04:49:52 +02:00
|
|
|
* mean? let us put the first year of the millennium... i.e.
|
|
|
|
* -1000, 1, 1001, 2001...
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
*/
|
|
|
|
if (tm->tm_year > 0)
|
2004-08-29 07:07:03 +02:00
|
|
|
tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
else
|
2004-08-29 07:07:03 +02:00
|
|
|
tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
|
2004-11-01 23:00:30 +01:00
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_CENTURY:
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
/* truncating to the century? as above: -100, 1, 101... */
|
|
|
|
if (tm->tm_year > 0)
|
2004-08-29 07:07:03 +02:00
|
|
|
tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
else
|
2004-08-29 07:07:03 +02:00
|
|
|
tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
|
2004-11-01 23:00:30 +01:00
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_DECADE:
|
2004-08-29 07:07:03 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* truncating to the decade? first year of the decade. must
|
|
|
|
* not be applied if year was truncated before!
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
*/
|
|
|
|
if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
|
|
|
|
{
|
|
|
|
if (tm->tm_year > 0)
|
|
|
|
tm->tm_year = (tm->tm_year / 10) * 10;
|
|
|
|
else
|
2004-08-29 07:07:03 +02:00
|
|
|
tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
}
|
2004-11-01 23:00:30 +01:00
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_YEAR:
|
|
|
|
tm->tm_mon = 1;
|
2004-11-01 23:00:30 +01:00
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_QUARTER:
|
2003-07-26 17:17:36 +02:00
|
|
|
tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
|
2004-11-01 23:00:30 +01:00
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_MONTH:
|
|
|
|
tm->tm_mday = 1;
|
2004-11-01 23:00:30 +01:00
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_DAY:
|
|
|
|
tm->tm_hour = 0;
|
2004-11-01 23:00:30 +01:00
|
|
|
redotz = true; /* for all cases >= DAY */
|
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_HOUR:
|
|
|
|
tm->tm_min = 0;
|
2004-11-01 23:00:30 +01:00
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_MINUTE:
|
|
|
|
tm->tm_sec = 0;
|
2004-11-01 23:00:30 +01:00
|
|
|
/* FALL THRU */
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_SECOND:
|
|
|
|
fsec = 0;
|
|
|
|
break;
|
|
|
|
case DTK_MILLISEC:
|
2005-07-22 23:16:15 +02:00
|
|
|
fsec = (fsec / 1000) * 1000;
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
case DTK_MICROSEC:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("timestamp with time zone units \"%s\" not "
|
|
|
|
"supported", lowunits)));
|
2001-09-28 10:09:14 +02:00
|
|
|
result = 0;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
2001-09-28 10:09:14 +02:00
|
|
|
|
2004-11-01 23:00:30 +01:00
|
|
|
if (redotz)
|
2018-11-14 21:41:07 +01:00
|
|
|
tz = DetermineTimeZoneOffset(tm, tzp);
|
2001-09-28 10:09:14 +02:00
|
|
|
|
|
|
|
if (tm2timestamp(tm, fsec, &tz, &result) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
2001-09-28 10:09:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("timestamp with time zone units \"%s\" not recognized",
|
|
|
|
lowunits)));
|
2003-07-27 06:53:12 +02:00
|
|
|
result = 0;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
|
|
|
|
2018-11-14 21:41:07 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* timestamptz_trunc()
|
|
|
|
* Truncate timestamptz to specified units in session timezone.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
timestamptz_trunc(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
text *units = PG_GETARG_TEXT_PP(0);
|
|
|
|
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
|
|
|
|
TimestampTz result;
|
|
|
|
|
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
|
|
|
PG_RETURN_TIMESTAMPTZ(timestamp);
|
|
|
|
|
|
|
|
result = timestamptz_trunc_internal(units, timestamp, session_timezone);
|
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMPTZ(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* timestamptz_trunc_zone()
|
|
|
|
* Truncate timestamptz to specified units in specified timezone.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
timestamptz_trunc_zone(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
text *units = PG_GETARG_TEXT_PP(0);
|
|
|
|
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
|
|
|
|
text *zone = PG_GETARG_TEXT_PP(2);
|
|
|
|
TimestampTz result;
|
|
|
|
char tzname[TZ_STRLEN_MAX + 1];
|
|
|
|
char *lowzone;
|
|
|
|
int type,
|
|
|
|
val;
|
|
|
|
pg_tz *tzp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* timestamptz_zone() doesn't look up the zone for infinite inputs, so we
|
|
|
|
* don't do so here either.
|
|
|
|
*/
|
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
|
|
|
PG_RETURN_TIMESTAMP(timestamp);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up the requested timezone (see notes in timestamptz_zone()).
|
|
|
|
*/
|
|
|
|
text_to_cstring_buffer(zone, tzname, sizeof(tzname));
|
|
|
|
|
|
|
|
/* DecodeTimezoneAbbrev requires lowercase input */
|
|
|
|
lowzone = downcase_truncate_identifier(tzname,
|
|
|
|
strlen(tzname),
|
|
|
|
false);
|
|
|
|
|
|
|
|
type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
|
|
|
|
|
|
|
|
if (type == TZ || type == DTZ)
|
|
|
|
{
|
|
|
|
/* fixed-offset abbreviation, get a pg_tz descriptor for that */
|
|
|
|
tzp = pg_tzset_offset(-val);
|
|
|
|
}
|
|
|
|
else if (type == DYNTZ)
|
|
|
|
{
|
|
|
|
/* dynamic-offset abbreviation, use its referenced timezone */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* try it as a full zone name */
|
|
|
|
tzp = pg_tzset(tzname);
|
|
|
|
if (!tzp)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("time zone \"%s\" not recognized", tzname)));
|
|
|
|
}
|
|
|
|
|
|
|
|
result = timestamptz_trunc_internal(units, timestamp, tzp);
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
PG_RETURN_TIMESTAMPTZ(result);
|
2000-06-09 03:11:16 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
/* interval_trunc()
|
|
|
|
* Extract specified field from interval.
|
|
|
|
*/
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_trunc(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2008-03-25 23:42:46 +01:00
|
|
|
text *units = PG_GETARG_TEXT_PP(0);
|
2000-06-09 03:11:16 +02:00
|
|
|
Interval *interval = PG_GETARG_INTERVAL_P(1);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
Interval *result;
|
|
|
|
int type,
|
|
|
|
val;
|
2004-05-07 02:24:59 +02:00
|
|
|
char *lowunits;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*tm = &tt;
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
result = (Interval *) palloc(sizeof(Interval));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2008-03-25 23:42:46 +01:00
|
|
|
lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
|
|
|
|
VARSIZE_ANY_EXHDR(units),
|
2004-05-07 02:24:59 +02:00
|
|
|
false);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
type = DecodeUnits(0, lowunits, &val);
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
if (type == UNITS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
|
|
|
if (interval2tm(*interval, tm, &fsec) == 0)
|
|
|
|
{
|
|
|
|
switch (val)
|
|
|
|
{
|
2000-04-14 17:22:10 +02:00
|
|
|
case DTK_MILLENNIUM:
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
/* caution: C division may have negative remainder */
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
tm->tm_year = (tm->tm_year / 1000) * 1000;
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
case DTK_CENTURY:
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
/* caution: C division may have negative remainder */
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
tm->tm_year = (tm->tm_year / 100) * 100;
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
case DTK_DECADE:
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
/* caution: C division may have negative remainder */
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
tm->tm_year = (tm->tm_year / 10) * 10;
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
case DTK_YEAR:
|
|
|
|
tm->tm_mon = 0;
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
case DTK_QUARTER:
|
2005-05-24 04:09:45 +02:00
|
|
|
tm->tm_mon = 3 * (tm->tm_mon / 3);
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
case DTK_MONTH:
|
|
|
|
tm->tm_mday = 0;
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
case DTK_DAY:
|
|
|
|
tm->tm_hour = 0;
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
case DTK_HOUR:
|
|
|
|
tm->tm_min = 0;
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
case DTK_MINUTE:
|
|
|
|
tm->tm_sec = 0;
|
2018-05-02 01:35:08 +02:00
|
|
|
/* FALL THRU */
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
case DTK_SECOND:
|
|
|
|
fsec = 0;
|
|
|
|
break;
|
|
|
|
case DTK_MILLISEC:
|
2005-07-22 23:16:15 +02:00
|
|
|
fsec = (fsec / 1000) * 1000;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
break;
|
|
|
|
case DTK_MICROSEC:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2012-08-15 22:48:05 +02:00
|
|
|
if (val == DTK_WEEK)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("interval units \"%s\" not supported "
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
"because months usually have fractional weeks",
|
2012-08-15 22:48:05 +02:00
|
|
|
lowunits)));
|
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("interval units \"%s\" not supported",
|
|
|
|
lowunits)));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (tm2interval(tm, fsec, result) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("interval out of range")));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
|
|
|
else
|
2003-07-27 06:53:12 +02:00
|
|
|
elog(ERROR, "could not convert interval to tm");
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("interval units \"%s\" not recognized",
|
2008-03-25 23:42:46 +01:00
|
|
|
lowunits)));
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
PG_RETURN_INTERVAL_P(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2007-02-16 04:39:46 +01:00
|
|
|
/* isoweek2j()
|
|
|
|
*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Return the Julian day which corresponds to the first day (Monday) of the given ISO 8601 year and week.
|
|
|
|
* Julian days are used to convert between ISO week dates and Gregorian dates.
|
2000-08-29 06:41:48 +02:00
|
|
|
*/
|
2007-02-16 04:39:46 +01:00
|
|
|
int
|
|
|
|
isoweek2j(int year, int week)
|
2000-08-29 06:41:48 +02:00
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
int day0,
|
2007-02-16 04:39:46 +01:00
|
|
|
day4;
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-08-29 06:41:48 +02:00
|
|
|
/* fourth day of current year */
|
2007-02-16 04:39:46 +01:00
|
|
|
day4 = date2j(year, 1, 4);
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-08-29 06:41:48 +02:00
|
|
|
/* day0 == offset to first day of week (Monday) */
|
2003-04-04 06:50:44 +02:00
|
|
|
day0 = j2day(day4 - 1);
|
2000-08-29 06:41:48 +02:00
|
|
|
|
2007-02-16 04:39:46 +01:00
|
|
|
return ((week - 1) * 7) + (day4 - day0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* isoweek2date()
|
|
|
|
* Convert ISO week of year number to date.
|
|
|
|
* The year field must be specified with the ISO year!
|
|
|
|
* karel 2000/08/07
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
isoweek2date(int woy, int *year, int *mon, int *mday)
|
|
|
|
{
|
|
|
|
j2date(isoweek2j(*year, woy), year, mon, mday);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* isoweekdate2date()
|
|
|
|
*
|
2012-09-04 04:52:34 +02:00
|
|
|
* Convert an ISO 8601 week date (ISO year, ISO week) into a Gregorian date.
|
|
|
|
* Gregorian day of week sent so weekday strings can be supplied.
|
2007-11-15 22:14:46 +01:00
|
|
|
* Populates year, mon, and mday with the correct Gregorian values.
|
|
|
|
* year must be passed in as the ISO year.
|
2007-02-16 04:39:46 +01:00
|
|
|
*/
|
|
|
|
void
|
2012-09-04 04:52:34 +02:00
|
|
|
isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
|
2007-02-16 04:39:46 +01:00
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
int jday;
|
2007-02-16 04:39:46 +01:00
|
|
|
|
|
|
|
jday = isoweek2j(*year, isoweek);
|
2012-09-04 04:52:34 +02:00
|
|
|
/* convert Gregorian week start (Sunday=1) to ISO week start (Monday=1) */
|
|
|
|
if (wday > 1)
|
|
|
|
jday += wday - 2;
|
|
|
|
else
|
|
|
|
jday += 6;
|
2007-02-16 04:39:46 +01:00
|
|
|
j2date(jday, year, mon, mday);
|
2000-08-29 06:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* date2isoweek()
|
2001-03-22 05:01:46 +01:00
|
|
|
*
|
2000-08-29 06:41:48 +02:00
|
|
|
* Returns ISO week number of year.
|
|
|
|
*/
|
|
|
|
int
|
2001-03-22 05:01:46 +01:00
|
|
|
date2isoweek(int year, int mon, int mday)
|
2000-08-29 06:41:48 +02:00
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
float8 result;
|
|
|
|
int day0,
|
|
|
|
day4,
|
|
|
|
dayn;
|
|
|
|
|
|
|
|
/* current day */
|
2000-08-29 06:41:48 +02:00
|
|
|
dayn = date2j(year, mon, mday);
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-08-29 06:41:48 +02:00
|
|
|
/* fourth day of current year */
|
|
|
|
day4 = date2j(year, 1, 4);
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-08-29 06:41:48 +02:00
|
|
|
/* day0 == offset to first day of week (Monday) */
|
2003-04-04 06:50:44 +02:00
|
|
|
day0 = j2day(day4 - 1);
|
2001-03-22 05:01:46 +01:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* We need the first week containing a Thursday, otherwise this day falls
|
|
|
|
* into the previous year for purposes of counting weeks
|
2000-08-29 06:41:48 +02:00
|
|
|
*/
|
2005-05-23 19:13:14 +02:00
|
|
|
if (dayn < day4 - day0)
|
2000-08-29 06:41:48 +02:00
|
|
|
{
|
2003-04-04 06:50:44 +02:00
|
|
|
day4 = date2j(year - 1, 1, 4);
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-08-29 06:41:48 +02:00
|
|
|
/* day0 == offset to first day of week (Monday) */
|
2003-04-04 06:50:44 +02:00
|
|
|
day0 = j2day(day4 - 1);
|
2000-08-29 06:41:48 +02:00
|
|
|
}
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2005-05-23 19:13:14 +02:00
|
|
|
result = (dayn - (day4 - day0)) / 7 + 1;
|
2001-03-22 05:01:46 +01:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Sometimes the last few days in a year will fall into the first week of
|
|
|
|
* the next year, so check for this.
|
2000-08-29 06:41:48 +02:00
|
|
|
*/
|
2005-04-01 16:25:23 +02:00
|
|
|
if (result >= 52)
|
2000-08-29 06:41:48 +02:00
|
|
|
{
|
2003-04-04 06:50:44 +02:00
|
|
|
day4 = date2j(year + 1, 1, 4);
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-08-29 06:41:48 +02:00
|
|
|
/* day0 == offset to first day of week (Monday) */
|
2003-04-04 06:50:44 +02:00
|
|
|
day0 = j2day(day4 - 1);
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2005-05-23 19:13:14 +02:00
|
|
|
if (dayn >= day4 - day0)
|
|
|
|
result = (dayn - (day4 - day0)) / 7 + 1;
|
2000-08-29 06:41:48 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-08-29 06:41:48 +02:00
|
|
|
return (int) result;
|
2001-03-22 05:01:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-25 04:36:24 +01:00
|
|
|
/* date2isoyear()
|
|
|
|
*
|
|
|
|
* Returns ISO 8601 year number.
|
2019-12-12 18:30:43 +01:00
|
|
|
* Note: zero or negative results follow the year-zero-exists convention.
|
2003-12-25 04:36:24 +01:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
date2isoyear(int year, int mon, int mday)
|
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
float8 result;
|
|
|
|
int day0,
|
|
|
|
day4,
|
|
|
|
dayn;
|
2003-12-25 04:36:24 +01:00
|
|
|
|
|
|
|
/* current day */
|
|
|
|
dayn = date2j(year, mon, mday);
|
|
|
|
|
|
|
|
/* fourth day of current year */
|
|
|
|
day4 = date2j(year, 1, 4);
|
|
|
|
|
|
|
|
/* day0 == offset to first day of week (Monday) */
|
|
|
|
day0 = j2day(day4 - 1);
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* We need the first week containing a Thursday, otherwise this day falls
|
|
|
|
* into the previous year for purposes of counting weeks
|
2003-12-25 04:36:24 +01:00
|
|
|
*/
|
2005-05-23 19:13:14 +02:00
|
|
|
if (dayn < day4 - day0)
|
2003-12-25 04:36:24 +01:00
|
|
|
{
|
|
|
|
day4 = date2j(year - 1, 1, 4);
|
|
|
|
|
|
|
|
/* day0 == offset to first day of week (Monday) */
|
|
|
|
day0 = j2day(day4 - 1);
|
|
|
|
|
|
|
|
year--;
|
|
|
|
}
|
|
|
|
|
2005-05-23 19:13:14 +02:00
|
|
|
result = (dayn - (day4 - day0)) / 7 + 1;
|
2003-12-25 04:36:24 +01:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Sometimes the last few days in a year will fall into the first week of
|
|
|
|
* the next year, so check for this.
|
2003-12-25 04:36:24 +01:00
|
|
|
*/
|
2005-04-01 16:25:23 +02:00
|
|
|
if (result >= 52)
|
2003-12-25 04:36:24 +01:00
|
|
|
{
|
|
|
|
day4 = date2j(year + 1, 1, 4);
|
|
|
|
|
|
|
|
/* day0 == offset to first day of week (Monday) */
|
|
|
|
day0 = j2day(day4 - 1);
|
|
|
|
|
2005-05-23 19:13:14 +02:00
|
|
|
if (dayn >= day4 - day0)
|
2003-12-25 04:36:24 +01:00
|
|
|
year++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return year;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-02-16 04:39:46 +01:00
|
|
|
/* date2isoyearday()
|
|
|
|
*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Returns the ISO 8601 day-of-year, given a Gregorian year, month and day.
|
|
|
|
* Possible return values are 1 through 371 (364 in non-leap years).
|
2007-02-16 04:39:46 +01:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
date2isoyearday(int year, int mon, int mday)
|
|
|
|
{
|
|
|
|
return date2j(year, mon, mday) - isoweek2j(date2isoyear(year, mon, mday), 1) + 1;
|
|
|
|
}
|
|
|
|
|
2016-01-22 04:26:20 +01:00
|
|
|
/*
|
|
|
|
* NonFiniteTimestampTzPart
|
|
|
|
*
|
|
|
|
* Used by timestamp_part and timestamptz_part when extracting from infinite
|
|
|
|
* timestamp[tz]. Returns +/-Infinity if that is the appropriate result,
|
|
|
|
* otherwise returns zero (which should be taken as meaning to return NULL).
|
|
|
|
*
|
|
|
|
* Errors thrown here for invalid units should exactly match those that
|
|
|
|
* would be thrown in the calling functions, else there will be unexpected
|
|
|
|
* discrepancies between finite- and infinite-input cases.
|
|
|
|
*/
|
|
|
|
static float8
|
|
|
|
NonFiniteTimestampTzPart(int type, int unit, char *lowunits,
|
|
|
|
bool isNegative, bool isTz)
|
|
|
|
{
|
|
|
|
if ((type != UNITS) && (type != RESERV))
|
|
|
|
{
|
|
|
|
if (isTz)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("timestamp with time zone units \"%s\" not recognized",
|
|
|
|
lowunits)));
|
2016-01-22 04:26:20 +01:00
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("timestamp units \"%s\" not recognized",
|
|
|
|
lowunits)));
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (unit)
|
|
|
|
{
|
|
|
|
/* Oscillating units */
|
|
|
|
case DTK_MICROSEC:
|
|
|
|
case DTK_MILLISEC:
|
|
|
|
case DTK_SECOND:
|
|
|
|
case DTK_MINUTE:
|
|
|
|
case DTK_HOUR:
|
|
|
|
case DTK_DAY:
|
|
|
|
case DTK_MONTH:
|
|
|
|
case DTK_QUARTER:
|
|
|
|
case DTK_WEEK:
|
|
|
|
case DTK_DOW:
|
|
|
|
case DTK_ISODOW:
|
|
|
|
case DTK_DOY:
|
|
|
|
case DTK_TZ:
|
|
|
|
case DTK_TZ_MINUTE:
|
|
|
|
case DTK_TZ_HOUR:
|
|
|
|
return 0.0;
|
|
|
|
|
|
|
|
/* Monotonically-increasing units */
|
|
|
|
case DTK_YEAR:
|
|
|
|
case DTK_DECADE:
|
|
|
|
case DTK_CENTURY:
|
|
|
|
case DTK_MILLENNIUM:
|
|
|
|
case DTK_JULIAN:
|
|
|
|
case DTK_ISOYEAR:
|
|
|
|
case DTK_EPOCH:
|
|
|
|
if (isNegative)
|
|
|
|
return -get_float8_infinity();
|
|
|
|
else
|
|
|
|
return get_float8_infinity();
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (isTz)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("timestamp with time zone units \"%s\" not supported",
|
|
|
|
lowunits)));
|
2016-01-22 04:26:20 +01:00
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("timestamp units \"%s\" not supported",
|
|
|
|
lowunits)));
|
|
|
|
return 0.0; /* keep compiler quiet */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
/* timestamp_part()
|
|
|
|
* Extract specified field from timestamp.
|
|
|
|
*/
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
timestamp_part(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2008-03-25 23:42:46 +01:00
|
|
|
text *units = PG_GETARG_TEXT_PP(0);
|
2005-10-15 04:49:52 +02:00
|
|
|
Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
|
2000-06-09 03:11:16 +02:00
|
|
|
float8 result;
|
2016-03-17 00:09:04 +01:00
|
|
|
Timestamp epoch;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
int type,
|
|
|
|
val;
|
2004-05-07 02:24:59 +02:00
|
|
|
char *lowunits;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*tm = &tt;
|
|
|
|
|
2008-03-25 23:42:46 +01:00
|
|
|
lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
|
|
|
|
VARSIZE_ANY_EXHDR(units),
|
2004-05-07 02:24:59 +02:00
|
|
|
false);
|
|
|
|
|
|
|
|
type = DecodeUnits(0, lowunits, &val);
|
|
|
|
if (type == UNKNOWN_FIELD)
|
|
|
|
type = DecodeSpecial(0, lowunits, &val);
|
|
|
|
|
2016-01-22 04:26:20 +01:00
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
|
|
|
{
|
|
|
|
result = NonFiniteTimestampTzPart(type, val, lowunits,
|
|
|
|
TIMESTAMP_IS_NOBEGIN(timestamp),
|
|
|
|
false);
|
|
|
|
if (result)
|
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
else
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
2003-07-27 06:53:12 +02:00
|
|
|
if (type == UNITS)
|
2001-09-28 10:09:14 +02:00
|
|
|
{
|
2005-07-21 06:41:43 +02:00
|
|
|
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
switch (val)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_MICROSEC:
|
2005-07-12 17:17:44 +02:00
|
|
|
result = tm->tm_sec * 1000000.0 + fsec;
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_MILLISEC:
|
2005-07-12 17:17:44 +02:00
|
|
|
result = tm->tm_sec * 1000.0 + fsec / 1000.0;
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_SECOND:
|
2005-07-12 17:17:44 +02:00
|
|
|
result = tm->tm_sec + fsec / 1000000.0;
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_MINUTE:
|
|
|
|
result = tm->tm_min;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_HOUR:
|
|
|
|
result = tm->tm_hour;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_DAY:
|
|
|
|
result = tm->tm_mday;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_MONTH:
|
|
|
|
result = tm->tm_mon;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_QUARTER:
|
2005-05-23 19:13:14 +02:00
|
|
|
result = (tm->tm_mon - 1) / 3 + 1;
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_WEEK:
|
|
|
|
result = (float8) date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_YEAR:
|
2004-03-30 17:53:18 +02:00
|
|
|
if (tm->tm_year > 0)
|
|
|
|
result = tm->tm_year;
|
|
|
|
else
|
2004-08-29 07:07:03 +02:00
|
|
|
/* there is no year 0, just 1 BC and 1 AD */
|
|
|
|
result = tm->tm_year - 1;
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_DECADE:
|
2004-08-29 07:07:03 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* what is a decade wrt dates? let us assume that decade 199
|
|
|
|
* is 1990 thru 1999... decade 0 starts on year 1 BC, and -1
|
|
|
|
* is 11 BC thru 2 BC...
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
*/
|
2004-08-29 07:07:03 +02:00
|
|
|
if (tm->tm_year >= 0)
|
2005-07-21 06:41:43 +02:00
|
|
|
result = tm->tm_year / 10;
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
else
|
2004-08-29 07:07:03 +02:00
|
|
|
result = -((8 - (tm->tm_year - 1)) / 10);
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_CENTURY:
|
2004-08-29 07:07:03 +02:00
|
|
|
|
2005-05-23 19:13:14 +02:00
|
|
|
/* ----
|
|
|
|
* centuries AD, c>0: year in [ (c-1)* 100 + 1 : c*100 ]
|
|
|
|
* centuries BC, c<0: year in [ c*100 : (c+1) * 100 - 1]
|
|
|
|
* there is no number 0 century.
|
|
|
|
* ----
|
Please find a small patch to fix the brain damage "century" and
"millennium" date part implementation in postgresql, both in the code
and the documentation, so that it conforms to the official definition.
If you do not agree with the official definition, please send your
complaint to "pope@vatican.org". I'm not responsible for them;-)
With the previous version, the centuries and millenniums had a wrong
number and started the wrong year. Moreover century number 0, which does
not exist in reality, lasted 200 years. Also, millennium number 0 lasted
2000 years.
If you want postgresql to have it's own definition of "century" and
"millennium" that does not conform to the one of the society, just give
them another name. I would suggest "pgCENTURY" and "pgMILLENNIUM";-)
IMO, if someone may use the options, it means that postgresql is used for
historical data, so it make sense to have an historical definition. Also,
I just want to divide the year by 100 or 1000, I can do that quite easily.
BACKWARD INCOMPATIBLE CHANGE
Fabien Coelho - coelho@cri.ensmp.fr
2004-04-10 20:02:59 +02:00
|
|
|
*/
|
|
|
|
if (tm->tm_year > 0)
|
2005-05-24 04:09:45 +02:00
|
|
|
result = (tm->tm_year + 99) / 100;
|
Please find a small patch to fix the brain damage "century" and
"millennium" date part implementation in postgresql, both in the code
and the documentation, so that it conforms to the official definition.
If you do not agree with the official definition, please send your
complaint to "pope@vatican.org". I'm not responsible for them;-)
With the previous version, the centuries and millenniums had a wrong
number and started the wrong year. Moreover century number 0, which does
not exist in reality, lasted 200 years. Also, millennium number 0 lasted
2000 years.
If you want postgresql to have it's own definition of "century" and
"millennium" that does not conform to the one of the society, just give
them another name. I would suggest "pgCENTURY" and "pgMILLENNIUM";-)
IMO, if someone may use the options, it means that postgresql is used for
historical data, so it make sense to have an historical definition. Also,
I just want to divide the year by 100 or 1000, I can do that quite easily.
BACKWARD INCOMPATIBLE CHANGE
Fabien Coelho - coelho@cri.ensmp.fr
2004-04-10 20:02:59 +02:00
|
|
|
else
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
/* caution: C division may have negative remainder */
|
2004-08-29 07:07:03 +02:00
|
|
|
result = -((99 - (tm->tm_year - 1)) / 100);
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_MILLENNIUM:
|
Please find a small patch to fix the brain damage "century" and
"millennium" date part implementation in postgresql, both in the code
and the documentation, so that it conforms to the official definition.
If you do not agree with the official definition, please send your
complaint to "pope@vatican.org". I'm not responsible for them;-)
With the previous version, the centuries and millenniums had a wrong
number and started the wrong year. Moreover century number 0, which does
not exist in reality, lasted 200 years. Also, millennium number 0 lasted
2000 years.
If you want postgresql to have it's own definition of "century" and
"millennium" that does not conform to the one of the society, just give
them another name. I would suggest "pgCENTURY" and "pgMILLENNIUM";-)
IMO, if someone may use the options, it means that postgresql is used for
historical data, so it make sense to have an historical definition. Also,
I just want to divide the year by 100 or 1000, I can do that quite easily.
BACKWARD INCOMPATIBLE CHANGE
Fabien Coelho - coelho@cri.ensmp.fr
2004-04-10 20:02:59 +02:00
|
|
|
/* see comments above. */
|
|
|
|
if (tm->tm_year > 0)
|
2005-07-21 06:41:43 +02:00
|
|
|
result = (tm->tm_year + 999) / 1000;
|
Please find a small patch to fix the brain damage "century" and
"millennium" date part implementation in postgresql, both in the code
and the documentation, so that it conforms to the official definition.
If you do not agree with the official definition, please send your
complaint to "pope@vatican.org". I'm not responsible for them;-)
With the previous version, the centuries and millenniums had a wrong
number and started the wrong year. Moreover century number 0, which does
not exist in reality, lasted 200 years. Also, millennium number 0 lasted
2000 years.
If you want postgresql to have it's own definition of "century" and
"millennium" that does not conform to the one of the society, just give
them another name. I would suggest "pgCENTURY" and "pgMILLENNIUM";-)
IMO, if someone may use the options, it means that postgresql is used for
historical data, so it make sense to have an historical definition. Also,
I just want to divide the year by 100 or 1000, I can do that quite easily.
BACKWARD INCOMPATIBLE CHANGE
Fabien Coelho - coelho@cri.ensmp.fr
2004-04-10 20:02:59 +02:00
|
|
|
else
|
2004-08-29 07:07:03 +02:00
|
|
|
result = -((999 - (tm->tm_year - 1)) / 1000);
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
2001-12-29 19:31:48 +01:00
|
|
|
case DTK_JULIAN:
|
|
|
|
result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
|
2005-07-21 20:06:13 +02:00
|
|
|
result += ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY;
|
2001-12-29 19:31:48 +01:00
|
|
|
break;
|
|
|
|
|
2007-02-16 04:39:46 +01:00
|
|
|
case DTK_ISOYEAR:
|
|
|
|
result = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
|
2019-12-12 18:30:43 +01:00
|
|
|
/* Adjust BC years */
|
|
|
|
if (result <= 0)
|
|
|
|
result -= 1;
|
2007-02-16 04:39:46 +01:00
|
|
|
break;
|
|
|
|
|
2015-09-06 03:04:37 +02:00
|
|
|
case DTK_DOW:
|
|
|
|
case DTK_ISODOW:
|
|
|
|
result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
|
|
|
|
if (val == DTK_ISODOW && result == 0)
|
|
|
|
result = 7;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_DOY:
|
|
|
|
result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
|
|
|
|
- date2j(tm->tm_year, 1, 1) + 1);
|
|
|
|
break;
|
|
|
|
|
2001-10-03 07:29:27 +02:00
|
|
|
case DTK_TZ:
|
|
|
|
case DTK_TZ_MINUTE:
|
|
|
|
case DTK_TZ_HOUR:
|
2001-09-28 10:09:14 +02:00
|
|
|
default:
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("timestamp units \"%s\" not supported",
|
2003-08-04 02:43:34 +02:00
|
|
|
lowunits)));
|
2001-09-28 10:09:14 +02:00
|
|
|
result = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (type == RESERV)
|
|
|
|
{
|
|
|
|
switch (val)
|
|
|
|
{
|
|
|
|
case DTK_EPOCH:
|
2016-03-17 00:09:04 +01:00
|
|
|
epoch = SetEpochTimestamp();
|
|
|
|
/* try to avoid precision loss in subtraction */
|
|
|
|
if (timestamp < (PG_INT64_MAX + epoch))
|
|
|
|
result = (timestamp - epoch) / 1000000.0;
|
|
|
|
else
|
|
|
|
result = ((float8) timestamp - epoch) / 1000000.0;
|
2012-06-10 21:20:04 +02:00
|
|
|
break;
|
2012-04-10 18:04:42 +02:00
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
default:
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("timestamp units \"%s\" not supported",
|
2003-08-04 02:43:34 +02:00
|
|
|
lowunits)));
|
2001-09-28 10:09:14 +02:00
|
|
|
result = 0;
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("timestamp units \"%s\" not recognized", lowunits)));
|
2001-09-28 10:09:14 +02:00
|
|
|
result = 0;
|
|
|
|
}
|
2000-04-14 17:22:10 +02:00
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
/* timestamptz_part()
|
|
|
|
* Extract specified field from timestamp with time zone.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
timestamptz_part(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2008-03-25 23:42:46 +01:00
|
|
|
text *units = PG_GETARG_TEXT_PP(0);
|
2003-05-13 01:08:52 +02:00
|
|
|
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
|
2001-09-28 10:09:14 +02:00
|
|
|
float8 result;
|
2016-03-17 00:09:04 +01:00
|
|
|
Timestamp epoch;
|
2001-09-28 10:09:14 +02:00
|
|
|
int tz;
|
|
|
|
int type,
|
|
|
|
val;
|
2004-05-07 02:24:59 +02:00
|
|
|
char *lowunits;
|
2001-09-28 10:09:14 +02:00
|
|
|
double dummy;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
2001-09-28 10:09:14 +02:00
|
|
|
*tm = &tt;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2008-03-25 23:42:46 +01:00
|
|
|
lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
|
|
|
|
VARSIZE_ANY_EXHDR(units),
|
2004-05-07 02:24:59 +02:00
|
|
|
false);
|
|
|
|
|
|
|
|
type = DecodeUnits(0, lowunits, &val);
|
|
|
|
if (type == UNKNOWN_FIELD)
|
|
|
|
type = DecodeSpecial(0, lowunits, &val);
|
|
|
|
|
2016-01-22 04:26:20 +01:00
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
|
|
|
{
|
|
|
|
result = NonFiniteTimestampTzPart(type, val, lowunits,
|
|
|
|
TIMESTAMP_IS_NOBEGIN(timestamp),
|
|
|
|
true);
|
|
|
|
if (result)
|
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
else
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
2003-07-27 06:53:12 +02:00
|
|
|
if (type == UNITS)
|
2001-09-28 10:09:14 +02:00
|
|
|
{
|
2012-03-15 20:13:35 +01:00
|
|
|
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
switch (val)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2001-09-28 10:09:14 +02:00
|
|
|
case DTK_TZ:
|
2003-07-17 02:55:37 +02:00
|
|
|
result = -tz;
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_TZ_MINUTE:
|
2003-07-17 02:55:37 +02:00
|
|
|
result = -tz;
|
2005-07-21 20:06:13 +02:00
|
|
|
result /= MINS_PER_HOUR;
|
2005-10-15 04:49:52 +02:00
|
|
|
FMODULO(result, dummy, (double) MINS_PER_HOUR);
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_TZ_HOUR:
|
2003-07-17 02:55:37 +02:00
|
|
|
dummy = -tz;
|
2005-10-15 04:49:52 +02:00
|
|
|
FMODULO(dummy, result, (double) SECS_PER_HOUR);
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_MICROSEC:
|
2005-07-12 17:17:44 +02:00
|
|
|
result = tm->tm_sec * 1000000.0 + fsec;
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_MILLISEC:
|
2005-07-12 17:17:44 +02:00
|
|
|
result = tm->tm_sec * 1000.0 + fsec / 1000.0;
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_SECOND:
|
2005-07-12 17:17:44 +02:00
|
|
|
result = tm->tm_sec + fsec / 1000000.0;
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_MINUTE:
|
|
|
|
result = tm->tm_min;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_HOUR:
|
|
|
|
result = tm->tm_hour;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_DAY:
|
|
|
|
result = tm->tm_mday;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_MONTH:
|
|
|
|
result = tm->tm_mon;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_QUARTER:
|
2005-05-23 19:13:14 +02:00
|
|
|
result = (tm->tm_mon - 1) / 3 + 1;
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_WEEK:
|
|
|
|
result = (float8) date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_YEAR:
|
2004-11-20 23:12:44 +01:00
|
|
|
if (tm->tm_year > 0)
|
|
|
|
result = tm->tm_year;
|
|
|
|
else
|
|
|
|
/* there is no year 0, just 1 BC and 1 AD */
|
|
|
|
result = tm->tm_year - 1;
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_DECADE:
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
/* see comments in timestamp_part */
|
2004-08-29 07:07:03 +02:00
|
|
|
if (tm->tm_year > 0)
|
2005-07-21 06:41:43 +02:00
|
|
|
result = tm->tm_year / 10;
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
else
|
2004-08-29 07:07:03 +02:00
|
|
|
result = -((8 - (tm->tm_year - 1)) / 10);
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_CENTURY:
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
/* see comments in timestamp_part */
|
|
|
|
if (tm->tm_year > 0)
|
2005-05-23 19:13:14 +02:00
|
|
|
result = (tm->tm_year + 99) / 100;
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
else
|
2004-08-29 07:07:03 +02:00
|
|
|
result = -((99 - (tm->tm_year - 1)) / 100);
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_MILLENNIUM:
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
/* see comments in timestamp_part */
|
|
|
|
if (tm->tm_year > 0)
|
2005-05-23 19:13:14 +02:00
|
|
|
result = (tm->tm_year + 999) / 1000;
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
else
|
2004-08-29 07:07:03 +02:00
|
|
|
result = -((999 - (tm->tm_year - 1)) / 1000);
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
|
|
|
|
2001-12-29 19:31:48 +01:00
|
|
|
case DTK_JULIAN:
|
|
|
|
result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
|
2005-07-21 20:06:13 +02:00
|
|
|
result += ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY;
|
2001-12-29 19:31:48 +01:00
|
|
|
break;
|
|
|
|
|
2007-02-16 04:39:46 +01:00
|
|
|
case DTK_ISOYEAR:
|
|
|
|
result = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
|
2019-12-12 18:30:43 +01:00
|
|
|
/* Adjust BC years */
|
|
|
|
if (result <= 0)
|
|
|
|
result -= 1;
|
2007-02-16 04:39:46 +01:00
|
|
|
break;
|
|
|
|
|
2015-09-06 03:04:37 +02:00
|
|
|
case DTK_DOW:
|
|
|
|
case DTK_ISODOW:
|
|
|
|
result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
|
|
|
|
if (val == DTK_ISODOW && result == 0)
|
|
|
|
result = 7;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_DOY:
|
|
|
|
result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
|
|
|
|
- date2j(tm->tm_year, 1, 1) + 1);
|
|
|
|
break;
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
default:
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("timestamp with time zone units \"%s\" not supported",
|
|
|
|
lowunits)));
|
2001-09-28 10:09:14 +02:00
|
|
|
result = 0;
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
}
|
|
|
|
else if (type == RESERV)
|
|
|
|
{
|
|
|
|
switch (val)
|
|
|
|
{
|
|
|
|
case DTK_EPOCH:
|
2016-03-17 00:09:04 +01:00
|
|
|
epoch = SetEpochTimestamp();
|
|
|
|
/* try to avoid precision loss in subtraction */
|
|
|
|
if (timestamp < (PG_INT64_MAX + epoch))
|
|
|
|
result = (timestamp - epoch) / 1000000.0;
|
|
|
|
else
|
|
|
|
result = ((float8) timestamp - epoch) / 1000000.0;
|
2001-09-28 10:09:14 +02:00
|
|
|
break;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
default:
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("timestamp with time zone units \"%s\" not supported",
|
|
|
|
lowunits)));
|
2001-09-28 10:09:14 +02:00
|
|
|
result = 0;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
|
|
|
}
|
2001-09-28 10:09:14 +02:00
|
|
|
else
|
|
|
|
{
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("timestamp with time zone units \"%s\" not recognized",
|
|
|
|
lowunits)));
|
2003-07-27 06:53:12 +02:00
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
result = 0;
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
|
|
|
|
/* interval_part()
|
|
|
|
* Extract specified field from interval.
|
|
|
|
*/
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
interval_part(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2008-03-25 23:42:46 +01:00
|
|
|
text *units = PG_GETARG_TEXT_PP(0);
|
2000-06-09 03:11:16 +02:00
|
|
|
Interval *interval = PG_GETARG_INTERVAL_P(1);
|
|
|
|
float8 result;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
int type,
|
|
|
|
val;
|
2004-05-07 02:24:59 +02:00
|
|
|
char *lowunits;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*tm = &tt;
|
|
|
|
|
2008-03-25 23:42:46 +01:00
|
|
|
lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
|
|
|
|
VARSIZE_ANY_EXHDR(units),
|
2004-05-07 02:24:59 +02:00
|
|
|
false);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
type = DecodeUnits(0, lowunits, &val);
|
2001-10-18 19:30:21 +02:00
|
|
|
if (type == UNKNOWN_FIELD)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
type = DecodeSpecial(0, lowunits, &val);
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
if (type == UNITS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
|
|
|
if (interval2tm(*interval, tm, &fsec) == 0)
|
|
|
|
{
|
|
|
|
switch (val)
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
case DTK_MICROSEC:
|
2005-07-12 17:17:44 +02:00
|
|
|
result = tm->tm_sec * 1000000.0 + fsec;
|
2002-09-04 22:31:48 +02:00
|
|
|
break;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
case DTK_MILLISEC:
|
2005-07-12 17:17:44 +02:00
|
|
|
result = tm->tm_sec * 1000.0 + fsec / 1000.0;
|
2002-09-04 22:31:48 +02:00
|
|
|
break;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
case DTK_SECOND:
|
2005-07-12 17:17:44 +02:00
|
|
|
result = tm->tm_sec + fsec / 1000000.0;
|
2002-09-04 22:31:48 +02:00
|
|
|
break;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
case DTK_MINUTE:
|
2000-06-09 03:11:16 +02:00
|
|
|
result = tm->tm_min;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_HOUR:
|
2000-06-09 03:11:16 +02:00
|
|
|
result = tm->tm_hour;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_DAY:
|
2000-06-09 03:11:16 +02:00
|
|
|
result = tm->tm_mday;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_MONTH:
|
2000-06-09 03:11:16 +02:00
|
|
|
result = tm->tm_mon;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_QUARTER:
|
2003-07-26 17:17:36 +02:00
|
|
|
result = (tm->tm_mon / 3) + 1;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_YEAR:
|
2000-06-09 03:11:16 +02:00
|
|
|
result = tm->tm_year;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_DECADE:
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
/* caution: C division may have negative remainder */
|
2005-07-21 06:41:43 +02:00
|
|
|
result = tm->tm_year / 10;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DTK_CENTURY:
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
/* caution: C division may have negative remainder */
|
2005-07-21 06:41:43 +02:00
|
|
|
result = tm->tm_year / 100;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
break;
|
|
|
|
|
2000-04-14 17:22:10 +02:00
|
|
|
case DTK_MILLENNIUM:
|
> After all that about numbering centuries and millenia correctly,
> why does CVS tip still give me
>
> regression=# select extract(century from now());
> date_part
> -----------
> 20
> (1 row)
> [ ... looks in code ... ]
>
> Apparently it's because you fixed only timestamp_part, and not
> timestamptz_part. I'm not too sure about what timestamp_trunc or
> timestamptz_trunc should do, but they may be wrong as well.
Sigh... as usual, what is not tested does not work:-(
> Could we have a more complete patch?
Please find a submission attached. I hope it really fixes all decade,
century and millenium issues for extract and *_trunc functions on
interval
and other timestamp types. If someone could check that the results
are reasonnable, it would be great.
I indeed overlooked the fact that there were two functions. The patch
fixes the code so that both variants agree.
I added comments to interval extractions, because it relies on the C
division to have a negative remainder: -7/10 = 0 and remains -7.
As for *_trunc functions, I have chosen to put the first year of the
century or millennium: -100, 1, 101... 1001 2001 etc. Indeed, I don't
think it would make sense to put 2000 (last year of the 2nd millennium)
for rounding all years of the third millenium.
I also fixed the code so that all decades last 10 years and decade 199
means the 1990's.
I have added some tests that are relevant to deal with tricky cases. The
formula may be simplified, but all these cases must pass. Please keep
them.
Fabien Coelho
2004-08-20 05:45:14 +02:00
|
|
|
/* caution: C division may have negative remainder */
|
2005-07-21 06:41:43 +02:00
|
|
|
result = tm->tm_year / 1000;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("interval units \"%s\" not supported",
|
2008-03-25 23:42:46 +01:00
|
|
|
lowunits)));
|
2000-06-09 03:11:16 +02:00
|
|
|
result = 0;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-07-27 06:53:12 +02:00
|
|
|
elog(ERROR, "could not convert interval to tm");
|
2000-06-09 03:11:16 +02:00
|
|
|
result = 0;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
|
|
|
}
|
2005-05-23 19:13:14 +02:00
|
|
|
else if (type == RESERV && val == DTK_EPOCH)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2005-07-12 17:17:44 +02:00
|
|
|
result = interval->time / 1000000.0;
|
2007-09-16 17:56:20 +02:00
|
|
|
result += ((double) DAYS_PER_YEAR * SECS_PER_DAY) * (interval->month / MONTHS_PER_YEAR);
|
2005-10-15 04:49:52 +02:00
|
|
|
result += ((double) DAYS_PER_MONTH * SECS_PER_DAY) * (interval->month % MONTHS_PER_YEAR);
|
2007-09-16 17:56:20 +02:00
|
|
|
result += ((double) SECS_PER_DAY) * interval->day;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("interval units \"%s\" not recognized",
|
2008-03-25 23:42:46 +01:00
|
|
|
lowunits)));
|
2000-06-09 03:11:16 +02:00
|
|
|
result = 0;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
|
|
|
|
2005-10-15 04:49:52 +02:00
|
|
|
/* timestamp_zone()
|
|
|
|
* Encode timestamp type with specified time zone.
|
|
|
|
* This function is just timestamp2timestamptz() except instead of
|
2005-07-23 16:25:34 +02:00
|
|
|
* shifting to the global timezone, we shift to the specified timezone.
|
|
|
|
* This is different from the other AT TIME ZONE cases because instead
|
2016-04-02 03:53:10 +02:00
|
|
|
* of shifting _to_ a new time zone, it sets the time to _be_ the
|
2005-07-23 16:25:34 +02:00
|
|
|
* specified timezone.
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
*/
|
2000-06-09 03:11:16 +02:00
|
|
|
Datum
|
|
|
|
timestamp_zone(PG_FUNCTION_ARGS)
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
{
|
2008-03-25 23:42:46 +01:00
|
|
|
text *zone = PG_GETARG_TEXT_PP(0);
|
2005-09-09 04:31:50 +02:00
|
|
|
Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
|
2005-10-15 04:49:52 +02:00
|
|
|
TimestampTz result;
|
2001-09-28 10:09:14 +02:00
|
|
|
int tz;
|
2005-10-15 04:49:52 +02:00
|
|
|
char tzname[TZ_STRLEN_MAX + 1];
|
2008-07-07 20:09:46 +02:00
|
|
|
char *lowzone;
|
|
|
|
int type,
|
|
|
|
val;
|
|
|
|
pg_tz *tzp;
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
struct pg_tm tm;
|
|
|
|
fsec_t fsec;
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
|
|
|
PG_RETURN_TIMESTAMPTZ(timestamp);
|
|
|
|
|
2005-09-09 04:31:50 +02:00
|
|
|
/*
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
* Look up the requested timezone. First we look in the timezone
|
|
|
|
* abbreviation table (to handle cases like "EST"), and if that fails, we
|
|
|
|
* look in the timezone database (to handle cases like
|
|
|
|
* "America/New_York"). (This matches the order in which timestamp input
|
|
|
|
* checks the cases; it's important because the timezone database unwisely
|
|
|
|
* uses a few zone names that are identical to offset abbreviations.)
|
2005-10-15 04:49:52 +02:00
|
|
|
*/
|
2008-03-25 23:42:46 +01:00
|
|
|
text_to_cstring_buffer(zone, tzname, sizeof(tzname));
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
|
|
|
|
/* DecodeTimezoneAbbrev requires lowercase input */
|
2008-07-07 20:09:46 +02:00
|
|
|
lowzone = downcase_truncate_identifier(tzname,
|
|
|
|
strlen(tzname),
|
|
|
|
false);
|
2001-09-28 10:09:14 +02:00
|
|
|
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
|
2008-07-07 20:09:46 +02:00
|
|
|
|
|
|
|
if (type == TZ || type == DTZ)
|
|
|
|
{
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
/* fixed-offset abbreviation */
|
|
|
|
tz = val;
|
|
|
|
result = dt2local(timestamp, tz);
|
|
|
|
}
|
|
|
|
else if (type == DYNTZ)
|
|
|
|
{
|
|
|
|
/* dynamic-offset abbreviation, resolve using specified time */
|
|
|
|
if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
tz = -DetermineTimeZoneAbbrevOffset(&tm, tzname, tzp);
|
2008-07-07 20:09:46 +02:00
|
|
|
result = dt2local(timestamp, tz);
|
2005-07-23 16:25:34 +02:00
|
|
|
}
|
2005-09-09 04:31:50 +02:00
|
|
|
else
|
2005-07-22 17:15:38 +02:00
|
|
|
{
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
/* try it as a full zone name */
|
2008-07-07 20:09:46 +02:00
|
|
|
tzp = pg_tzset(tzname);
|
|
|
|
if (tzp)
|
|
|
|
{
|
|
|
|
/* Apply the timezone change */
|
|
|
|
if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
tz = DetermineTimeZoneOffset(&tm, tzp);
|
|
|
|
if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
|
|
|
|
ereport(ERROR,
|
2016-03-17 00:09:04 +01:00
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
2008-07-07 20:09:46 +02:00
|
|
|
}
|
2005-09-09 04:31:50 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("time zone \"%s\" not recognized", tzname)));
|
2009-06-11 16:49:15 +02:00
|
|
|
result = 0; /* keep compiler quiet */
|
2005-09-09 04:31:50 +02:00
|
|
|
}
|
2005-06-15 02:34:11 +02:00
|
|
|
}
|
2005-07-23 04:02:27 +02:00
|
|
|
|
2016-03-17 00:09:04 +01:00
|
|
|
if (!IS_VALID_TIMESTAMP(result))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
2005-07-22 23:16:15 +02:00
|
|
|
PG_RETURN_TIMESTAMPTZ(result);
|
2005-07-22 17:15:38 +02:00
|
|
|
}
|
2001-09-28 10:09:14 +02:00
|
|
|
|
|
|
|
/* timestamp_izone()
|
|
|
|
* Encode timestamp type with specified time interval as time zone.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
timestamp_izone(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Interval *zone = PG_GETARG_INTERVAL_P(0);
|
2005-10-15 04:49:52 +02:00
|
|
|
Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
|
2001-10-25 07:50:21 +02:00
|
|
|
TimestampTz result;
|
2001-09-28 10:09:14 +02:00
|
|
|
int tz;
|
|
|
|
|
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
|
|
|
PG_RETURN_TIMESTAMPTZ(timestamp);
|
|
|
|
|
2013-01-31 18:12:23 +01:00
|
|
|
if (zone->month != 0 || zone->day != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("interval time zone \"%s\" must not include months or days",
|
|
|
|
DatumGetCString(DirectFunctionCall1(interval_out,
|
|
|
|
PointerGetDatum(zone))))));
|
2001-09-28 10:09:14 +02:00
|
|
|
|
2005-05-23 20:56:55 +02:00
|
|
|
tz = zone->time / USECS_PER_SEC;
|
2002-04-21 21:52:18 +02:00
|
|
|
|
|
|
|
result = dt2local(timestamp, tz);
|
2001-09-28 10:09:14 +02:00
|
|
|
|
2016-03-17 00:09:04 +01:00
|
|
|
if (!IS_VALID_TIMESTAMP(result))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
PG_RETURN_TIMESTAMPTZ(result);
|
2017-06-21 20:39:04 +02:00
|
|
|
} /* timestamp_izone() */
|
2001-09-28 10:09:14 +02:00
|
|
|
|
2019-03-09 05:16:27 +01:00
|
|
|
/* TimestampTimestampTzRequiresRewrite()
|
|
|
|
*
|
|
|
|
* Returns false if the TimeZone GUC setting causes timestamp_timestamptz and
|
|
|
|
* timestamptz_timestamp to be no-ops, where the return value has the same
|
|
|
|
* bits as the argument. Since project convention is to assume a GUC changes
|
|
|
|
* no more often than STABLE functions change, the answer is valid that long.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
TimestampTimestampTzRequiresRewrite(void)
|
|
|
|
{
|
|
|
|
long offset;
|
|
|
|
|
|
|
|
if (pg_get_timezone_offset(session_timezone, &offset) && offset == 0)
|
2019-06-23 21:02:19 +02:00
|
|
|
return false;
|
|
|
|
return true;
|
2019-03-09 05:16:27 +01:00
|
|
|
}
|
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
/* timestamp_timestamptz()
|
|
|
|
* Convert local timestamp to timestamp at GMT
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
timestamp_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
|
2004-03-22 02:38:18 +01:00
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(timestamp));
|
|
|
|
}
|
|
|
|
|
2019-09-25 20:51:47 +02:00
|
|
|
/*
|
|
|
|
* Convert timestamp to timestamp with time zone.
|
|
|
|
*
|
2019-10-21 22:04:14 +02:00
|
|
|
* On overflow error is thrown if 'overflow' is NULL. Otherwise, '*overflow'
|
|
|
|
* is set to -1 (+1) when result value exceed lower (upper) boundary and zero
|
|
|
|
* returned.
|
2019-09-25 20:51:47 +02:00
|
|
|
*/
|
|
|
|
TimestampTz
|
2019-10-21 22:04:14 +02:00
|
|
|
timestamp2timestamptz_opt_overflow(Timestamp timestamp, int *overflow)
|
2004-03-22 02:38:18 +01:00
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
TimestampTz result;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
2001-09-28 10:09:14 +02:00
|
|
|
*tm = &tt;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec;
|
2001-09-28 10:09:14 +02:00
|
|
|
int tz;
|
|
|
|
|
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
2019-09-25 20:51:47 +02:00
|
|
|
return timestamp;
|
2001-09-28 10:09:14 +02:00
|
|
|
|
2019-09-25 20:51:47 +02:00
|
|
|
if (!timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL))
|
|
|
|
{
|
2007-08-04 03:26:54 +02:00
|
|
|
tz = DetermineTimeZoneOffset(tm, session_timezone);
|
2001-09-28 10:09:14 +02:00
|
|
|
|
2019-10-21 22:03:55 +02:00
|
|
|
result = dt2local(timestamp, -tz);
|
|
|
|
|
|
|
|
if (IS_VALID_TIMESTAMP(result))
|
|
|
|
{
|
2019-09-25 20:51:47 +02:00
|
|
|
return result;
|
2019-10-21 22:03:55 +02:00
|
|
|
}
|
2019-10-21 22:04:14 +02:00
|
|
|
else if (overflow)
|
2019-10-21 22:03:55 +02:00
|
|
|
{
|
2019-10-21 22:04:14 +02:00
|
|
|
if (result < MIN_TIMESTAMP)
|
|
|
|
*overflow = -1;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Assert(result >= END_TIMESTAMP);
|
|
|
|
*overflow = 1;
|
|
|
|
}
|
2019-10-21 22:03:55 +02:00
|
|
|
return (TimestampTz) 0;
|
|
|
|
}
|
2001-09-28 10:09:14 +02:00
|
|
|
}
|
|
|
|
|
2019-10-21 22:04:14 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
2019-09-25 20:51:47 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2019-10-21 22:04:14 +02:00
|
|
|
* Single-argument version of timestamp2timestamptz_opt_overflow().
|
2019-09-25 20:51:47 +02:00
|
|
|
*/
|
|
|
|
static TimestampTz
|
|
|
|
timestamp2timestamptz(Timestamp timestamp)
|
|
|
|
{
|
2019-10-21 22:04:14 +02:00
|
|
|
return timestamp2timestamptz_opt_overflow(timestamp, NULL);
|
2001-09-28 10:09:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* timestamptz_timestamp()
|
|
|
|
* Convert timestamp at GMT to local timestamp
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
timestamptz_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2003-05-13 01:08:52 +02:00
|
|
|
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
|
2016-08-17 02:33:01 +02:00
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMP(timestamptz2timestamp(timestamp));
|
|
|
|
}
|
|
|
|
|
|
|
|
static Timestamp
|
|
|
|
timestamptz2timestamp(TimestampTz timestamp)
|
|
|
|
{
|
2001-09-28 10:09:14 +02:00
|
|
|
Timestamp result;
|
2004-08-29 07:07:03 +02:00
|
|
|
struct pg_tm tt,
|
2001-09-28 10:09:14 +02:00
|
|
|
*tm = &tt;
|
2002-04-21 21:52:18 +02:00
|
|
|
fsec_t fsec;
|
2001-09-28 10:09:14 +02:00
|
|
|
int tz;
|
|
|
|
|
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
|
|
|
result = timestamp;
|
|
|
|
else
|
|
|
|
{
|
2012-03-15 20:13:35 +01:00
|
|
|
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
2001-09-28 10:09:14 +02:00
|
|
|
if (tm2timestamp(tm, fsec, NULL, &result) != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
2001-09-28 10:09:14 +02:00
|
|
|
}
|
2016-08-17 02:33:01 +02:00
|
|
|
return result;
|
2001-09-28 10:09:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* timestamptz_zone()
|
2002-04-21 21:52:18 +02:00
|
|
|
* Evaluate timestamp with time zone type at the specified time zone.
|
|
|
|
* Returns a timestamp without time zone.
|
2001-09-28 10:09:14 +02:00
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
timestamptz_zone(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2008-03-25 23:42:46 +01:00
|
|
|
text *zone = PG_GETARG_TEXT_PP(0);
|
2003-05-13 01:08:52 +02:00
|
|
|
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
|
2002-04-21 21:52:18 +02:00
|
|
|
Timestamp result;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
int tz;
|
2005-10-15 04:49:52 +02:00
|
|
|
char tzname[TZ_STRLEN_MAX + 1];
|
2008-07-07 20:09:46 +02:00
|
|
|
char *lowzone;
|
|
|
|
int type,
|
|
|
|
val;
|
|
|
|
pg_tz *tzp;
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
2000-06-09 03:11:16 +02:00
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
2005-09-09 04:31:50 +02:00
|
|
|
PG_RETURN_TIMESTAMP(timestamp);
|
2001-09-28 10:09:14 +02:00
|
|
|
|
2005-09-09 04:31:50 +02:00
|
|
|
/*
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
* Look up the requested timezone. First we look in the timezone
|
|
|
|
* abbreviation table (to handle cases like "EST"), and if that fails, we
|
|
|
|
* look in the timezone database (to handle cases like
|
|
|
|
* "America/New_York"). (This matches the order in which timestamp input
|
|
|
|
* checks the cases; it's important because the timezone database unwisely
|
|
|
|
* uses a few zone names that are identical to offset abbreviations.)
|
2005-10-15 04:49:52 +02:00
|
|
|
*/
|
2008-03-25 23:42:46 +01:00
|
|
|
text_to_cstring_buffer(zone, tzname, sizeof(tzname));
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
|
|
|
|
/* DecodeTimezoneAbbrev requires lowercase input */
|
2008-07-07 20:09:46 +02:00
|
|
|
lowzone = downcase_truncate_identifier(tzname,
|
|
|
|
strlen(tzname),
|
|
|
|
false);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
|
2008-07-07 20:09:46 +02:00
|
|
|
|
|
|
|
if (type == TZ || type == DTZ)
|
|
|
|
{
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
/* fixed-offset abbreviation */
|
|
|
|
tz = -val;
|
|
|
|
result = dt2local(timestamp, tz);
|
|
|
|
}
|
|
|
|
else if (type == DYNTZ)
|
|
|
|
{
|
|
|
|
/* dynamic-offset abbreviation, resolve using specified time */
|
|
|
|
int isdst;
|
|
|
|
|
|
|
|
tz = DetermineTimeZoneAbbrevOffsetTS(timestamp, tzname, tzp, &isdst);
|
2008-07-07 20:09:46 +02:00
|
|
|
result = dt2local(timestamp, tz);
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
2005-09-09 04:31:50 +02:00
|
|
|
else
|
|
|
|
{
|
Support timezone abbreviations that sometimes change.
Up to now, PG has assumed that any given timezone abbreviation (such as
"EDT") represents a constant GMT offset in the usage of any particular
region; we had a way to configure what that offset was, but not for it
to be changeable over time. But, as with most things horological, this
view of the world is too simplistic: there are numerous regions that have
at one time or another switched to a different GMT offset but kept using
the same timezone abbreviation. Almost the entire Russian Federation did
that a few years ago, and later this month they're going to do it again.
And there are similar examples all over the world.
To cope with this, invent the notion of a "dynamic timezone abbreviation",
which is one that is referenced to a particular underlying timezone
(as defined in the IANA timezone database) and means whatever it currently
means in that zone. For zones that use or have used daylight-savings time,
the standard and DST abbreviations continue to have the property that you
can specify standard or DST time and get that time offset whether or not
DST was theoretically in effect at the time. However, the abbreviations
mean what they meant at the time in question (or most recently before that
time) rather than being absolutely fixed.
The standard abbreviation-list files have been changed to use this behavior
for abbreviations that have actually varied in meaning since 1970. The
old simple-numeric definitions are kept for abbreviations that have not
changed, since they are a bit faster to resolve.
While this is clearly a new feature, it seems necessary to back-patch it
into all active branches, because otherwise use of Russian zone
abbreviations is going to become even more problematic than it already was.
This change supersedes the changes in commit 513d06ded et al to modify the
fixed meanings of the Russian abbreviations; since we've not shipped that
yet, this will avoid an undesirably incompatible (not to mention incorrect)
change in behavior for timestamps between 2011 and 2014.
This patch makes some cosmetic changes in ecpglib to keep its usage of
datetime lookup tables as similar as possible to the backend code, but
doesn't do anything about the increasingly obsolete set of timezone
abbreviation definitions that are hard-wired into ecpglib. Whatever we
do about that will likely not be appropriate material for back-patching.
Also, a potential free() of a garbage pointer after an out-of-memory
failure in ecpglib has been fixed.
This patch also fixes pre-existing bugs in DetermineTimeZoneOffset() that
caused it to produce unexpected results near a timezone transition, if
both the "before" and "after" states are marked as standard time. We'd
only ever thought about or tested transitions between standard and DST
time, but that's not what's happening when a zone simply redefines their
base GMT offset.
In passing, update the SGML documentation to refer to the Olson/zoneinfo/
zic timezone database as the "IANA" database, since it's now being
maintained under the auspices of IANA.
2014-10-16 21:22:10 +02:00
|
|
|
/* try it as a full zone name */
|
2008-07-07 20:09:46 +02:00
|
|
|
tzp = pg_tzset(tzname);
|
|
|
|
if (tzp)
|
|
|
|
{
|
|
|
|
/* Apply the timezone change */
|
|
|
|
struct pg_tm tm;
|
|
|
|
fsec_t fsec;
|
2005-09-09 04:31:50 +02:00
|
|
|
|
2008-07-07 20:09:46 +02:00
|
|
|
if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
|
|
|
|
ereport(ERROR,
|
2016-03-17 00:09:04 +01:00
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
2008-07-07 20:09:46 +02:00
|
|
|
}
|
2005-09-09 04:31:50 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("time zone \"%s\" not recognized", tzname)));
|
2009-06-11 16:49:15 +02:00
|
|
|
result = 0; /* keep compiler quiet */
|
2005-09-09 04:31:50 +02:00
|
|
|
}
|
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
2000-02-16 18:26:26 +01:00
|
|
|
}
|
|
|
|
|
2016-03-17 00:09:04 +01:00
|
|
|
if (!IS_VALID_TIMESTAMP(result))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
2002-04-21 21:52:18 +02:00
|
|
|
PG_RETURN_TIMESTAMP(result);
|
2005-07-22 17:15:38 +02:00
|
|
|
}
|
2000-11-06 16:57:00 +01:00
|
|
|
|
2001-09-28 10:09:14 +02:00
|
|
|
/* timestamptz_izone()
|
|
|
|
* Encode timestamp with time zone type with specified time interval as time zone.
|
2002-04-21 21:52:18 +02:00
|
|
|
* Returns a timestamp without time zone.
|
2000-11-06 16:57:00 +01:00
|
|
|
*/
|
|
|
|
Datum
|
2001-09-28 10:09:14 +02:00
|
|
|
timestamptz_izone(PG_FUNCTION_ARGS)
|
2000-11-06 16:57:00 +01:00
|
|
|
{
|
|
|
|
Interval *zone = PG_GETARG_INTERVAL_P(0);
|
2003-05-13 01:08:52 +02:00
|
|
|
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
|
2002-04-21 21:52:18 +02:00
|
|
|
Timestamp result;
|
2000-11-06 16:57:00 +01:00
|
|
|
int tz;
|
|
|
|
|
|
|
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
2005-09-09 08:46:14 +02:00
|
|
|
PG_RETURN_TIMESTAMP(timestamp);
|
2000-11-06 16:57:00 +01:00
|
|
|
|
2013-01-31 18:12:23 +01:00
|
|
|
if (zone->month != 0 || zone->day != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("interval time zone \"%s\" must not include months or days",
|
|
|
|
DatumGetCString(DirectFunctionCall1(interval_out,
|
|
|
|
PointerGetDatum(zone))))));
|
2000-11-06 16:57:00 +01:00
|
|
|
|
2005-05-23 20:56:55 +02:00
|
|
|
tz = -(zone->time / USECS_PER_SEC);
|
2000-11-06 16:57:00 +01:00
|
|
|
|
2002-04-21 21:52:18 +02:00
|
|
|
result = dt2local(timestamp, tz);
|
2000-11-06 16:57:00 +01:00
|
|
|
|
2016-03-17 00:09:04 +01:00
|
|
|
if (!IS_VALID_TIMESTAMP(result))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("timestamp out of range")));
|
|
|
|
|
2002-04-21 21:52:18 +02:00
|
|
|
PG_RETURN_TIMESTAMP(result);
|
2005-07-22 17:15:38 +02:00
|
|
|
}
|
2008-05-05 01:19:24 +02:00
|
|
|
|
|
|
|
/* generate_series_timestamp()
|
|
|
|
* Generate the set of timestamps from start to finish by step
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
generate_series_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
FuncCallContext *funcctx;
|
|
|
|
generate_series_timestamp_fctx *fctx;
|
2009-06-11 16:49:15 +02:00
|
|
|
Timestamp result;
|
2008-05-05 01:19:24 +02:00
|
|
|
|
|
|
|
/* stuff done only on the first call of the function */
|
|
|
|
if (SRF_IS_FIRSTCALL())
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
Timestamp start = PG_GETARG_TIMESTAMP(0);
|
|
|
|
Timestamp finish = PG_GETARG_TIMESTAMP(1);
|
|
|
|
Interval *step = PG_GETARG_INTERVAL_P(2);
|
2008-05-05 01:19:24 +02:00
|
|
|
MemoryContext oldcontext;
|
2009-06-11 16:49:15 +02:00
|
|
|
Interval interval_zero;
|
2008-05-05 01:19:24 +02:00
|
|
|
|
|
|
|
/* create a function context for cross-call persistence */
|
|
|
|
funcctx = SRF_FIRSTCALL_INIT();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* switch to memory context appropriate for multiple function calls
|
|
|
|
*/
|
|
|
|
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
|
|
|
|
|
|
|
/* allocate memory for user context */
|
|
|
|
fctx = (generate_series_timestamp_fctx *)
|
|
|
|
palloc(sizeof(generate_series_timestamp_fctx));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use fctx to keep state from call to call. Seed current with the
|
|
|
|
* original start value
|
|
|
|
*/
|
|
|
|
fctx->current = start;
|
|
|
|
fctx->finish = finish;
|
|
|
|
fctx->step = *step;
|
|
|
|
|
|
|
|
/* Determine sign of the interval */
|
|
|
|
MemSet(&interval_zero, 0, sizeof(Interval));
|
|
|
|
fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero);
|
|
|
|
|
|
|
|
if (fctx->step_sign == 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("step size cannot equal zero")));
|
|
|
|
|
|
|
|
funcctx->user_fctx = fctx;
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* stuff done on every call of the function */
|
|
|
|
funcctx = SRF_PERCALL_SETUP();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get the saved state and use current as the result for this iteration
|
|
|
|
*/
|
|
|
|
fctx = funcctx->user_fctx;
|
|
|
|
result = fctx->current;
|
|
|
|
|
|
|
|
if (fctx->step_sign > 0 ?
|
|
|
|
timestamp_cmp_internal(result, fctx->finish) <= 0 :
|
|
|
|
timestamp_cmp_internal(result, fctx->finish) >= 0)
|
|
|
|
{
|
|
|
|
/* increment current in preparation for next iteration */
|
|
|
|
fctx->current = DatumGetTimestamp(
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
DirectFunctionCall2(timestamp_pl_interval,
|
|
|
|
TimestampGetDatum(fctx->current),
|
|
|
|
PointerGetDatum(&fctx->step)));
|
2008-05-05 01:19:24 +02:00
|
|
|
|
|
|
|
/* do when there is more left to send */
|
|
|
|
SRF_RETURN_NEXT(funcctx, TimestampGetDatum(result));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* do when there is no more left */
|
|
|
|
SRF_RETURN_DONE(funcctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* generate_series_timestamptz()
|
|
|
|
* Generate the set of timestamps from start to finish by step
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
generate_series_timestamptz(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
FuncCallContext *funcctx;
|
|
|
|
generate_series_timestamptz_fctx *fctx;
|
|
|
|
TimestampTz result;
|
|
|
|
|
|
|
|
/* stuff done only on the first call of the function */
|
|
|
|
if (SRF_IS_FIRSTCALL())
|
|
|
|
{
|
|
|
|
TimestampTz start = PG_GETARG_TIMESTAMPTZ(0);
|
|
|
|
TimestampTz finish = PG_GETARG_TIMESTAMPTZ(1);
|
2009-06-11 16:49:15 +02:00
|
|
|
Interval *step = PG_GETARG_INTERVAL_P(2);
|
2008-05-05 01:19:24 +02:00
|
|
|
MemoryContext oldcontext;
|
2009-06-11 16:49:15 +02:00
|
|
|
Interval interval_zero;
|
2008-05-05 01:19:24 +02:00
|
|
|
|
|
|
|
/* create a function context for cross-call persistence */
|
|
|
|
funcctx = SRF_FIRSTCALL_INIT();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* switch to memory context appropriate for multiple function calls
|
|
|
|
*/
|
|
|
|
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
|
|
|
|
|
|
|
/* allocate memory for user context */
|
|
|
|
fctx = (generate_series_timestamptz_fctx *)
|
|
|
|
palloc(sizeof(generate_series_timestamptz_fctx));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use fctx to keep state from call to call. Seed current with the
|
|
|
|
* original start value
|
|
|
|
*/
|
|
|
|
fctx->current = start;
|
|
|
|
fctx->finish = finish;
|
|
|
|
fctx->step = *step;
|
|
|
|
|
|
|
|
/* Determine sign of the interval */
|
|
|
|
MemSet(&interval_zero, 0, sizeof(Interval));
|
|
|
|
fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero);
|
|
|
|
|
|
|
|
if (fctx->step_sign == 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("step size cannot equal zero")));
|
|
|
|
|
|
|
|
funcctx->user_fctx = fctx;
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* stuff done on every call of the function */
|
|
|
|
funcctx = SRF_PERCALL_SETUP();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get the saved state and use current as the result for this iteration
|
|
|
|
*/
|
|
|
|
fctx = funcctx->user_fctx;
|
|
|
|
result = fctx->current;
|
|
|
|
|
|
|
|
if (fctx->step_sign > 0 ?
|
|
|
|
timestamp_cmp_internal(result, fctx->finish) <= 0 :
|
|
|
|
timestamp_cmp_internal(result, fctx->finish) >= 0)
|
|
|
|
{
|
|
|
|
/* increment current in preparation for next iteration */
|
|
|
|
fctx->current = DatumGetTimestampTz(
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
DirectFunctionCall2(timestamptz_pl_interval,
|
|
|
|
TimestampTzGetDatum(fctx->current),
|
|
|
|
PointerGetDatum(&fctx->step)));
|
2008-05-05 01:19:24 +02:00
|
|
|
|
|
|
|
/* do when there is more left to send */
|
|
|
|
SRF_RETURN_NEXT(funcctx, TimestampTzGetDatum(result));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* do when there is no more left */
|
|
|
|
SRF_RETURN_DONE(funcctx);
|
|
|
|
}
|
|
|
|
}
|